merge from fmf-devel branch. more updates to models: now with collectModelInfo with...
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Fri, 31 Aug 2012 16:48:20 +0000 (16:48 +0000)
committerAndrew Reynolds <andrew.j.reynolds@gmail.com>
Fri, 31 Aug 2012 16:48:20 +0000 (16:48 +0000)
106 files changed:
src/expr/command.cpp
src/expr/command.h
src/parser/cvc/Cvc.g
src/parser/smt2/Smt2.g
src/printer/ast/ast_printer.cpp
src/printer/ast/ast_printer.h
src/printer/cvc/cvc_printer.cpp
src/printer/cvc/cvc_printer.h
src/printer/dagification_visitor.cpp
src/printer/printer.cpp
src/printer/printer.h
src/printer/smt/smt_printer.cpp
src/printer/smt/smt_printer.h
src/printer/smt2/smt2_printer.cpp
src/printer/smt2/smt2_printer.h
src/prop/minisat/core/Solver.cc
src/prop/options
src/smt/Makefile.am
src/smt/model_format_mode.cpp [new file with mode: 0644]
src/smt/model_format_mode.h [new file with mode: 0644]
src/smt/options
src/smt/options_handlers.h
src/smt/smt_engine.cpp
src/smt/smt_engine.h
src/theory/Makefile.am
src/theory/arith/theory_arith.cpp
src/theory/arith/theory_arith.h
src/theory/arith/theory_arith_instantiator.cpp
src/theory/arith/theory_arith_instantiator.h
src/theory/arrays/theory_arrays.cpp
src/theory/arrays/theory_arrays.h
src/theory/arrays/theory_arrays_model.cpp
src/theory/arrays/theory_arrays_model.h
src/theory/booleans/theory_bool.cpp
src/theory/booleans/theory_bool.h
src/theory/builtin/theory_builtin.cpp
src/theory/builtin/theory_builtin.h
src/theory/bv/theory_bv.cpp
src/theory/bv/theory_bv.h
src/theory/datatypes/kinds
src/theory/datatypes/options
src/theory/datatypes/theory_datatypes.cpp
src/theory/datatypes/theory_datatypes.h
src/theory/datatypes/theory_datatypes_instantiator.cpp
src/theory/example/theory_uf_tim.h
src/theory/model.cpp
src/theory/model.h
src/theory/output_channel.h
src/theory/quantifiers/Makefile.am
src/theory/quantifiers/first_order_model.cpp
src/theory/quantifiers/first_order_model.h
src/theory/quantifiers/inst_match.cpp
src/theory/quantifiers/inst_when_mode.cpp [deleted file]
src/theory/quantifiers/inst_when_mode.h [deleted file]
src/theory/quantifiers/instantiation_engine.cpp
src/theory/quantifiers/instantiation_engine.h
src/theory/quantifiers/kinds
src/theory/quantifiers/literal_match_mode.cpp [deleted file]
src/theory/quantifiers/literal_match_mode.h [deleted file]
src/theory/quantifiers/model_builder.cpp
src/theory/quantifiers/model_builder.h
src/theory/quantifiers/model_engine.cpp
src/theory/quantifiers/model_engine.h
src/theory/quantifiers/modes.cpp [new file with mode: 0644]
src/theory/quantifiers/modes.h [new file with mode: 0644]
src/theory/quantifiers/options
src/theory/quantifiers/options_handlers.h
src/theory/quantifiers/quantifiers_attributes.cpp [new file with mode: 0644]
src/theory/quantifiers/quantifiers_attributes.h [new file with mode: 0644]
src/theory/quantifiers/relevant_domain.cpp
src/theory/quantifiers/relevant_domain.h
src/theory/quantifiers/rep_set_iterator.cpp [deleted file]
src/theory/quantifiers/rep_set_iterator.h [deleted file]
src/theory/quantifiers/term_database.cpp
src/theory/quantifiers/theory_quantifiers.cpp
src/theory/quantifiers/theory_quantifiers.h
src/theory/quantifiers_engine.cpp
src/theory/quantifiers_engine.h
src/theory/rep_set.cpp [new file with mode: 0644]
src/theory/rep_set.h [new file with mode: 0644]
src/theory/rewriterules/theory_rewriterules.cpp
src/theory/rewriterules/theory_rewriterules.h
src/theory/shared_terms_database.cpp
src/theory/shared_terms_database.h
src/theory/term_registration_visitor.cpp
src/theory/theory.h
src/theory/theory_engine.cpp
src/theory/theory_engine.h
src/theory/theory_test_utils.h
src/theory/uf/equality_engine.h
src/theory/uf/kinds
src/theory/uf/options
src/theory/uf/theory_uf.cpp
src/theory/uf/theory_uf.h
src/theory/uf/theory_uf_model.cpp
src/theory/uf/theory_uf_model.h
src/theory/uf/theory_uf_strong_solver.cpp
src/theory/uf/theory_uf_strong_solver.h
src/theory/uf/theory_uf_type_rules.h
src/theory/valuation.cpp
src/theory/valuation.h
src/util/datatype.cpp
src/util/datatype.h
src/util/model.h
test/regress/regress0/quantifiers/refcount24.cvc [new file with mode: 0644]
test/unit/theory/theory_engine_white.h

index f93df3722f757174a31d2fd7c1a54828356a254e..648c64388dd8217ecc4aa3561283a5a0e0617792 100644 (file)
@@ -462,13 +462,17 @@ DeclareFunctionCommand::DeclareFunctionCommand(const std::string& id, Expr func,
   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();
 }
 
@@ -500,7 +504,7 @@ Type DeclareTypeCommand::getType() const throw() {
 
 void DeclareTypeCommand::invoke(SmtEngine* smtEngine) throw() {
   Dump("declarations") << *this;
-  smtEngine->addToModelType( d_type );
+  smtEngine->addToModelCommand( clone(), Model::COMMAND_DECLARE_SORT );
   d_commandStatus = CommandSuccess::instance();
 }
 
@@ -644,6 +648,43 @@ Command* DefineNamedFunctionCommand::clone() const {
   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() :
@@ -1095,7 +1136,7 @@ void GetOptionCommand::invoke(SmtEngine* smtEngine) 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();
@@ -1148,6 +1189,7 @@ DatatypeDeclarationCommand::getDatatypes() const throw() {
 
 void DatatypeDeclarationCommand::invoke(SmtEngine* smtEngine) throw() {
   Dump("declarations") << *this;
+  smtEngine->addToModelCommand( clone(), Model::COMMAND_DECLARE_DATATYPES );
   d_commandStatus = CommandSuccess::instance();
 }
 
index 2c56e60d9d514f030ec923b51bd37877bc8d9416..4657755e7d809f52757dd473c82470ae54384237 100644 (file)
@@ -322,6 +322,7 @@ protected:
 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);
@@ -389,6 +390,27 @@ public:
   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;
index 3c4a51ad47bcd9f7fd89592392588ffcdb2177a3..82e27401e5d2fd411941223dc600960308f0392a 100644 (file)
@@ -747,9 +747,9 @@ mainCommand[CVC4::Command*& cmd]
     { 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"); }
index d8157acbc84c34f070a8f39d4b8da1dcfb93d414..867250c0f36fa46d584312d57c0b216670bac834 100644 (file)
@@ -705,8 +705,6 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
     ( attribute[expr, attexpr,attr]
       { if( attr == ":pattern" && ! attexpr.isNull()) {
           patexprs.push_back( attexpr );
-        }else if( attr==":axiom" ){
-          //do this?
         }
       }
     )+ RPAREN_TOK
@@ -788,18 +786,15 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
   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;
@@ -812,9 +807,20 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
       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);
+    }
   ;
 
 /**
@@ -1198,7 +1204,7 @@ PROPAGATION_RULE_TOK : 'assert-propagation';
 
 // attributes
 ATTRIBUTE_PATTERN_TOK : ':pattern';
-ATTRIBUTE_REWRITE_RULE : ':rewrite-rule';
+ATTRIBUTE_NAMED_TOK : ':named';
 
 // operators (NOTE: theory symbols go here)
 AMPERSAND_TOK     : '&';
index 50bd5016d36f97a7828465f4e97b387fcea6234d..39d76728a04bb91786105a657ec535cbd62c8a3e 100644 (file)
@@ -186,6 +186,10 @@ void AstPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw
 
 }/* 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() << ")";
 }
index 4dfb2c0d50f59c2f141f87ef724e799a24368869..1cac966df22666896cbe14370ed2dbf0fc058977 100644 (file)
@@ -35,6 +35,8 @@ public:
   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 */
index 6a709b83339a2f3fd380601678fcffdc1f575698..5803ad23fde56c8f5bd2db77aae1de0b462a756e 100644 (file)
@@ -23,6 +23,8 @@
 #include "expr/command.h"
 #include "theory/substitutions.h"
 
+#include "theory/model.h"
+
 #include <iostream>
 #include <vector>
 #include <string>
@@ -500,7 +502,7 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
       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 << ')';
@@ -537,7 +539,7 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
       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 << ')';
@@ -729,6 +731,83 @@ void CvcPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw
 
 }/* 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() << ";";
 }
index 7fb611a799d5374405f118f467cfa95ba068acf6..c868025ef9eb47711a73c8b94237903dc3ed8018 100644 (file)
@@ -38,6 +38,8 @@ public:
   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 */
index cb56c34309f857c7bdfda390709cb7971319af33..40b53261268d2586481d9b36e129a78fc61a7716 100644 (file)
@@ -55,6 +55,7 @@ bool DagificationVisitor::alreadyVisited(TNode current, TNode parent) {
   // 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() ||
index 0881b814be2c65239f27f9bac7ae416b7e75ae22..24baafa14a3f326a32ebdd8a5be1f6efaa78321c 100644 (file)
@@ -127,4 +127,10 @@ void Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
   }
 }/* 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 */
index e3b1d6f400843d225b1c3d0adc3cd3be42060200..6fedc854ce171cea72f2863e098bec05481f680b 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "util/language.h"
 #include "util/sexpr.h"
+#include "util/model.h"
 #include "expr/node.h"
 #include "expr/command.h"
 
@@ -76,6 +77,13 @@ public:
    */
   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 */
index fa46523a4c4d399e5299515820e4c57954f39b10..14a680a1e6c75372a66fc377b30ae8648a51e7ce 100644 (file)
@@ -51,6 +51,10 @@ void SmtPrinter::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
   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 */
index 6e1c607bfd0311e79befbcd444cbf5fedae7ee6d..1cf7fcf50527e2eed64904317bb113a8b930e85a 100644 (file)
@@ -35,6 +35,8 @@ public:
   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 */
index ed8648c475a83e5641bb5b86e4e0913f7fecb0bc..9400b77328d66731783d6a316c4463321fd6ae7e 100644 (file)
@@ -29,6 +29,8 @@
 #include "theory/substitutions.h"
 #include "util/language.h"
 
+#include "theory/model.h"
+
 using namespace std;
 
 namespace CVC4 {
@@ -306,14 +308,6 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
     // 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
@@ -526,6 +520,76 @@ void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const thro
 
 }/* 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() << ")";
 }
@@ -687,7 +751,7 @@ static void toStream(std::ostream& out, const GetOptionCommand* c) throw() {
 
 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;
@@ -698,14 +762,15 @@ static void toStream(std::ostream& out, const DatatypeDeclarationCommand* c) thr
     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;
   }
index fd65a1efaeb14bd3dee08f3329231852c93598ff..30c0ce647180b6d9f3110f5cecb447b5b2638f37 100644 (file)
@@ -35,6 +35,8 @@ public:
   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 */
index 675bc8f4eafecde47813d3bec91eead3c53b869e..5e19eb7762ae0b5d45531a4ca6af6f30f8583900 100644 (file)
@@ -407,6 +407,7 @@ Lit Solver::pickBranchLit()
     if(stopSearch) {
       return lit_Undef;
     }
+    Debug("propagateAsDecision") << "propagateAsDecision(): decide on another literal" << std::endl;
 
     Var next = var_Undef;
 
index c3c2674c4b7c8747f8fcfac515a8e4ea26792ff7..cda99538c053dd98f3a273c8e3ca56ac6a7587d5 100644 (file)
@@ -25,7 +25,7 @@ option satRestartInc --restart-int-inc=F double :default 3.0 :predicate greater_
 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
index 9bfc9680a1877e4d4af7b41031c32a86fe0c8288..333c887eed1d68567f0ac094f3da603ce7a96672 100644 (file)
@@ -12,7 +12,9 @@ libsmt_la_SOURCES = \
        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
diff --git a/src/smt/model_format_mode.cpp b/src/smt/model_format_mode.cpp
new file mode 100644 (file)
index 0000000..ffaa3df
--- /dev/null
@@ -0,0 +1,39 @@
+/*********************                                                        */
+/*! \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 */
diff --git a/src/smt/model_format_mode.h b/src/smt/model_format_mode.h
new file mode 100644 (file)
index 0000000..3c0a356
--- /dev/null
@@ -0,0 +1,41 @@
+/*********************                                                        */
+/*! \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 */
index fea609bb5843683c1971238cc1b684e908287ab5..bb0cf1a003ef2dc57d49824b7d2a0e98a86d4090 100644 (file)
@@ -34,6 +34,8 @@ common-option produceModels produce-models -m --produce-models bool :predicate C
  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.
index 925f86d4837ca4251fe8edd45c8d8783a8fa2c10..fb6cd84d8b5e78dfd4d3c06dfb336d5669ad2981 100644 (file)
@@ -150,6 +150,16 @@ none\n\
 + 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());
@@ -231,6 +241,20 @@ inline SimplificationMode stringToSimplificationMode(std::string option, std::st
   }
 }
 
+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) \
index d450319b1b5ae83765eb6059c353e034b1f98dbf..8327799449adc735d9fd69f39c97fd19445717fa 100644 (file)
@@ -60,6 +60,8 @@
 #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;
@@ -488,7 +490,9 @@ void SmtEngine::setLogicInternal() throw(AssertionException) {
     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
@@ -617,6 +621,21 @@ void SmtEngine::setLogicInternal() throw(AssertionException) {
     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)
@@ -1727,11 +1746,10 @@ Expr SmtEngine::getValue(const Expr& e)
     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();
@@ -1835,34 +1853,19 @@ CVC4::SExpr SmtEngine::getAssignment() throw(ModalException, AssertionException)
 }
 
 
-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) {
@@ -1871,7 +1874,11 @@ Model* SmtEngine::getModel() throw(ModalException, AssertionException){
       "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();
 }
 
@@ -2066,7 +2073,13 @@ StatisticsRegistry* SmtEngine::getStatisticsRegistry() const {
 
 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 */
index 25800f5b35876582dc64f5041f0b0e5097bdf9bc..23481424523c01a683121cb261c50f9ed5950ff8 100644 (file)
@@ -389,16 +389,10 @@ public:
   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
@@ -565,6 +559,12 @@ public:
    */
   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 */
index 8f6ab76c2c1796798ed837d50a8913701d60fed8..8dcd149954da67306ea9f76a458f196641a76c6a 100644 (file)
@@ -39,7 +39,9 @@ libtheory_la_SOURCES = \
        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 \
index ca2d74cf7f9045de864c49f812cf2615be6c0cfb..e159c0e42ed552c48c40376e48cd60906589586c 100644 (file)
@@ -1925,17 +1925,17 @@ DeltaRational TheoryArith::getDeltaValue(TNode n) {
   }
 }
 
-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);
index 35fcca4060310b0633d747add8764a94734610b5..a8c02545263b20a4f77e419f930385b47e7bb210 100644 (file)
@@ -323,7 +323,7 @@ public:
   void propagate(Effort e);
   Node explain(TNode n);
 
-  void collectModelInfo( TheoryModel* m );
+  void collectModelInfo( TheoryModel* m, bool fullModel );
 
   void shutdown(){ }
 
index 51e3a6638bc2c7e5d93ac2876a00f3df18626cc0..8d0815ee7b9d15b2f270f7f4d66dc71fd6fffc12 100644 (file)
@@ -27,11 +27,7 @@ using namespace CVC4::context;
 using namespace CVC4::theory;
 using namespace CVC4::theory::arith;
 
-#define ARITH_INSTANTIATOR_USE_DELTA
 #define ARITH_INSTANTIATOR_USE_MINUS_DELTA
-#define ARITH_INSTANTIATOR_STRONG_DELTA_LEMMA
-
-#define USE_ARITH_INSTANTIATION
 
 InstStrategySimplex::InstStrategySimplex( InstantiatorTheoryArith* th, QuantifiersEngine* ie ) :
     InstStrategy( ie ), d_th( th ), d_counter( 0 ){
@@ -97,87 +93,6 @@ int InstStrategySimplex::process( Node f, Theory::Effort effort, int e ){
   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() ){
@@ -392,59 +307,21 @@ Node InstantiatorTheoryArith::getTableauxValue( Node n, bool minus_delta ){
 }
 
 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);
 }
index 406478a2aebf2c179677cac4da82da651de83dac..a7602cf2809153b2edb90c9c03096413bcc1b0e0 100644 (file)
@@ -48,22 +48,6 @@ public:
   /** 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;
@@ -105,16 +89,11 @@ private:
   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();
   };
index 4beab2d61d8500660e8fe8becc945a303d2248db..0ec8e138430e47c08d98c0fd4e5e280fab208a87 100644 (file)
@@ -24,6 +24,7 @@
 #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;
@@ -625,8 +626,50 @@ void TheoryArrays::computeCareGraph()
 // 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 );
+  }
 }
 
 /////////////////////////////////////////////////////////////////////////////
index f7cbe8b73cdc7ac9a0947602a29bc560fad67648..aebee68170d560b31bda9c2a2f97b1d6675e85e0 100644 (file)
@@ -219,7 +219,7 @@ class TheoryArrays : public Theory {
   private:
   public:
 
-  void collectModelInfo( TheoryModel* m );
+  void collectModelInfo( TheoryModel* m, bool fullModel );
 
   /////////////////////////////////////////////////////////////////////////////
   // NOTIFICATIONS
index 5c969060d4e8342d7a31ec149aefd74923b15aef..39fdd095fe430b3973f2e527b4f6717a8de66ec7 100644 (file)
@@ -16,8 +16,7 @@
 
 #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;
@@ -26,43 +25,41 @@ using namespace CVC4::context;
 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 );
   }
index 28852296d3e9f34e13267ad6547e448c92486d05..4b93b38eb7d13b0d3b8ee4b280356a2fa64412d4 100644 (file)
@@ -1,62 +1,60 @@
-/*********************                                                        */
-/*! \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
index f096987db399c9095fd3b59189d2ca4f3305e0bb..6e7e86e4fa8720569e8c5e956ea6dca836a23de6 100644 (file)
@@ -32,10 +32,6 @@ namespace CVC4 {
 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>()) {
index 827b0ff5703873d5391e6fbc4b89011c796ae12e..45f0b4502863df4aca85ddb0af1796814f0a86e3 100644 (file)
@@ -35,8 +35,6 @@ public:
     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"); }
index fa176243cd69e603f80867141aba82a5bee844f6..90332f74af77d1fc21608b18ed5e0ec9da975f0e 100644 (file)
@@ -27,10 +27,6 @@ namespace CVC4 {
 namespace theory {
 namespace builtin {
 
-void TheoryBuiltin::collectModelInfo( TheoryModel* m ){
-
-}
-
 }/* CVC4::theory::builtin namespace */
 }/* CVC4::theory */
 }/* CVC4 namespace */
index 51bd7c75695790b75c6a6c174c9993610f068b1e..3212caf017cbb58798ec9f96adc4b967192c6507 100644 (file)
@@ -31,7 +31,6 @@ class TheoryBuiltin : public Theory {
 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 */
 
index 2bb4857a3dcb0fde281c2a6aba63074387c1634a..aa5281d2f1fdaf59ac2a90e06e3d30f28aa0b7da 100644 (file)
@@ -125,7 +125,7 @@ void TheoryBV::check(Effort e)
   }
 }
 
-void TheoryBV::collectModelInfo( TheoryModel* m ){
+void TheoryBV::collectModelInfo( TheoryModel* m, bool fullModel ){
 
 }
 
index 611927b2b699b2d8a58f47238904264001a8a6da..30cf5ac52fd0ca0147de30ab7a6a39ed8eb15dda 100644 (file)
@@ -60,7 +60,7 @@ public:
 
   Node explain(TNode n);
 
-  void collectModelInfo( TheoryModel* m );
+  void collectModelInfo( TheoryModel* m, bool fullModel );
 
   std::string identify() const { return std::string("TheoryBV"); }
 
index 58c8fb5d2bbdb173a6565e5417425c9d54e01a13..eac3d6eac084ae2ee93f209a49e7932c6dc8e463 100644 (file)
@@ -8,7 +8,7 @@ theory THEORY_DATATYPES ::CVC4::theory::datatypes::TheoryDatatypes "theory/datat
 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"
 
index 8a76e813495bc1f83822208f22df254e69132eda..ab627000ebf77a4a008adcbdf8c82c030f4cb631 100644 (file)
@@ -5,4 +5,11 @@
 
 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
index b7f4f39d55422701ff93f0f53f42c2483b6ce58c..3305b88d8628ec95aa2955eb756eb9a5fc22f252 100644 (file)
@@ -23,7 +23,9 @@
 #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>
 
@@ -34,51 +36,52 @@ using namespace CVC4::context;
 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;
   }
-  */
 }
 
 
@@ -129,6 +132,193 @@ TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( Node n, bool doMake
   }
 }
 
+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){
 
@@ -142,6 +332,7 @@ bool TheoryDatatypes::propagate(TNode literal){
     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) {
@@ -237,17 +428,19 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
             //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;
@@ -278,7 +471,7 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
         checkInst = true;
       }
       if( checkInst ){
-        checkInstantiate( eqc1, t1 );
+        instantiate( eqc1, t1 );
         if( d_conflict ){
           return;
         }
@@ -309,7 +502,7 @@ void TheoryDatatypes::eqNotifyDisequal(TNode t1, TNode t2, TNode reason){
 }
 
 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 ){
 
 }
 
@@ -361,10 +554,12 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
     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 );
@@ -373,6 +568,7 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
           d_out->conflict( d_conflictNode );
           return;
         }else{
+          //conflict because the existing label is contradictory
           j = getLabel( n );
           jt = j;
         }
@@ -380,6 +576,7 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
         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;
@@ -403,7 +600,7 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
         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
@@ -418,6 +615,7 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
               }
             }
             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++ ) {
@@ -433,7 +631,7 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
             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;
@@ -453,162 +651,50 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
   }
 }
 
-
-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 );
 }
 
 
@@ -617,12 +703,14 @@ void TheoryDatatypes::collectTerms( Node n ) {
     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 );
@@ -633,38 +721,58 @@ void TheoryDatatypes::collectTerms( Node 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() ){
@@ -677,8 +785,9 @@ void TheoryDatatypes::checkInstantiate( EqcInfo* eqc, Node n ){
     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 ){
@@ -686,7 +795,7 @@ void TheoryDatatypes::checkInstantiate( EqcInfo* eqc, Node n ){
         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 );
@@ -746,6 +855,46 @@ bool TheoryDatatypes::searchForCycle( Node n, Node on,
   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 );
 }
index 725f9a5e6f671e8584ac98074349fb86e496c6fa..17638b00a8a96244813b40e43e5df11ac2a0143a 100644 (file)
@@ -118,7 +118,7 @@ private:
     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
@@ -139,6 +139,10 @@ private:
   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
@@ -162,10 +166,15 @@ private:
   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);
@@ -192,9 +201,12 @@ public:
   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 );
@@ -209,11 +221,17 @@ private:
   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 );
index 23f3e8950520cf91310b77a271d7212876302d28..0df293cf9e35c7b402afe644564dc47e6dc50fe8 100644 (file)
@@ -56,7 +56,6 @@ int InstantiatorTheoryDatatypes::process( Node f, Theory::Effort effort, int e )
     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 );
@@ -66,18 +65,22 @@ int InstantiatorTheoryDatatypes::process( Node f, Theory::Effort effort, int e )
           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;
index 5a6732bc4a198ceef648d4dbd8eefcbb5d762c83..09d8942fc0fa388ac6b8b5d948160fa6833564ec 100644 (file)
@@ -142,15 +142,6 @@ public:
    */
   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:
index a194336fb3d5febab12f8f3d94ac97e0ee8cf25d..51d5a77b5dea306bed531ec5123f93cdadcc32ad 100644 (file)
@@ -17,7 +17,9 @@
 #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;
@@ -26,52 +28,17 @@ using namespace CVC4::kind;
 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(){
@@ -79,51 +46,6 @@ 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 );
@@ -141,31 +63,21 @@ void TheoryModel::toStream( std::ostream& out ){
     ++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;
   }
 
@@ -178,7 +90,7 @@ Node TheoryModel::getValue( TNode 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 );
@@ -192,16 +104,23 @@ Node TheoryModel::getValue( TNode n ){
   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
@@ -214,8 +133,9 @@ Node TheoryModel::getDomainValue( TypeNode tn, std::vector< Node >& exclude ){
   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;
@@ -239,6 +159,40 @@ Node TheoryModel::getNewDomainValue( TypeNode tn ){
     //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 */
@@ -262,7 +216,7 @@ void TheoryModel::assertEqualityEngine( const eq::EqualityEngine* ee ){
     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?
@@ -280,6 +234,11 @@ void TheoryModel::assertEqualityEngine( const eq::EqualityEngine* ee ){
   }
 }
 
+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 );
 }
@@ -287,7 +246,11 @@ bool TheoryModel::hasTerm( Node 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;
   }
@@ -315,7 +278,7 @@ bool TheoryModel::areDisequal( Node a, Node b ){
 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{
@@ -330,7 +293,7 @@ void TheoryModel::printRepresentative( std::ostream& out, Node r ){
   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{
@@ -349,7 +312,10 @@ TheoryModel( c, name ), d_enableFuncModels( enableFuncModels ){
 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 );
+    }
   }
 }
 
@@ -374,38 +340,46 @@ Node DefaultModel::getInterpretedValue( TNode 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;
       }
     }
@@ -416,191 +390,90 @@ TheoryEngineModelBuilder::TheoryEngineModelBuilder( TheoryEngine* te ) : d_te( t
 
 }
 
-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() ){
@@ -611,3 +484,71 @@ Node TheoryEngineModelBuilder::chooseRepresentative( TheoryModel* m, Node eqc ){
     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
index 4a4bf48c942d7a2c72fd43a61bddec9cc0f5f679..086e39f3e187ccf69c15de2326d826168203db2a 100644 (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
@@ -66,18 +43,8 @@ protected:
     *   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(){}
@@ -90,7 +57,7 @@ public:
   /** true/false nodes */
   Node d_true;
   Node d_false;
-public:
+protected:
   /** reset the model */
   virtual void reset();
   /** get interpreted value
@@ -98,11 +65,11 @@ public:
     *  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.
@@ -117,13 +84,28 @@ public:
     *   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 );
@@ -170,19 +152,24 @@ class TheoryEngineModelBuilder : public ModelBuilder
 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 );
 };
 
 }
index a86984ccab6ca1993b4bc29711633dd0b9ce9828..8ddf809b63bb93b0a6d6e61f995773c267260d86 100644 (file)
@@ -27,6 +27,8 @@
 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
@@ -206,8 +208,14 @@ public:
    * 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 */
 
index 2b16c9af317babe284ff123c5c245e7bcbc7f7bd..3a19ff9c69391300bb2fb79cece3a22ee7c85e02 100644 (file)
@@ -25,20 +25,18 @@ libquantifiers_la_SOURCES = \
        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 \
index fd616948c19a5563e51f469970d295460f9a0a91..c3be1cdaf790829ac370f818a7638efa98c5cc3f 100644 (file)
  **/
 
 #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;
@@ -26,39 +28,38 @@ using namespace CVC4::context;
 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] );
     }
   }
 }
@@ -92,33 +93,16 @@ void FirstOrderModel::initializeModelForTerm( Node n ){
   }
 }
 
-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() ){
@@ -141,44 +125,387 @@ Node FirstOrderModel::getInterpretedValue( TNode n ){
   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
+  }
 }
index 8ad9114528de899683b885252e03762074c9a54a..e66bf80402eb6a1172daca6d4f37a0a078ef4180 100644 (file)
@@ -42,32 +42,41 @@ class TermDb;
 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();
@@ -75,11 +84,30 @@ public:
   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 */
index ce35607d4fd6918ee5c748c1f88349d6268fb1ba..d2083ef3de281fdc5d79f1074a33f4e8f0a152a9 100644 (file)
@@ -148,7 +148,9 @@ void InstMatch::computeTermVec( QuantifiersEngine* qe, const std::vector< Node >
 }
 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] ] );
+    }
   }
 }
 
@@ -177,7 +179,7 @@ bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m
     }
     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() ){
@@ -193,13 +195,6 @@ bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m
           ++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;
   }
diff --git a/src/theory/quantifiers/inst_when_mode.cpp b/src/theory/quantifiers/inst_when_mode.cpp
deleted file mode 100644 (file)
index b60148c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*********************                                                        */
-/*! \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 */
-
diff --git a/src/theory/quantifiers/inst_when_mode.h b/src/theory/quantifiers/inst_when_mode.h
deleted file mode 100644 (file)
index 2cfba49..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*********************                                                        */
-/*! \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 */
index 0fa4fad1277f634e127a22ca3430ac9ff1397ffd..727f568c5dbf4081b238985992320629ffa8b3eb 100644 (file)
@@ -386,3 +386,16 @@ void InstantiationEngine::propagate( Theory::Effort level ){
     }
   }
 }
+
+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
index 37ee6d80126308ff6b28557ba996b69f7b9586e6..19dac736c43618fb64829650bfb07447e93efc0d 100644 (file)
@@ -66,6 +66,7 @@ public:
   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 ]; }
index 106d95cefc1f05d6591aa0d86ff0d41dcaaa6bb6..c81816528b21bc61fa167aed896e73cd274d295e 100644 (file)
@@ -8,7 +8,7 @@ theory THEORY_QUANTIFIERS ::CVC4::theory::quantifiers::TheoryQuantifiers "theory
 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"
 
@@ -30,6 +30,9 @@ sort INST_PATTERN_TYPE \
     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 \
@@ -37,6 +40,7 @@ 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 
diff --git a/src/theory/quantifiers/literal_match_mode.cpp b/src/theory/quantifiers/literal_match_mode.cpp
deleted file mode 100644 (file)
index 87b4b94..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*********************                                                        */
-/*! \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 */
diff --git a/src/theory/quantifiers/literal_match_mode.h b/src/theory/quantifiers/literal_match_mode.h
deleted file mode 100644 (file)
index 189f0a2..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*********************                                                        */
-/*! \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 */
index 5d49c914f559afe33514f603336a5da5849757dc..c09346f35128274b59b97102bf554534dd9de282 100644 (file)
 #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;
@@ -37,78 +36,95 @@ using namespace CVC4::context;
 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;
@@ -138,108 +154,138 @@ void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
 }
 
 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 );
+          }
         }
       }
     }
@@ -248,58 +294,87 @@ void ModelEngineBuilder::analyzeQuantifiers( FirstOrderModel* fm ){
 }
 
 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
@@ -311,10 +386,10 @@ void ModelEngineBuilder::finishBuildModel( FirstOrderModel* fm ){
     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 ){
@@ -337,7 +412,7 @@ void ModelEngineBuilder::finishBuildModelUf( FirstOrderModel* fm, Node op ){
     //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
@@ -381,12 +456,6 @@ void ModelEngineBuilder::finishBuildModelUf( FirstOrderModel* fm, Node op ){
   }
 }
 
-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();
 }
@@ -396,11 +465,11 @@ bool ModelEngineBuilder::optInstGen(){
 }
 
 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():
@@ -415,3 +484,7 @@ 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();
+}
index 344b731e096d10801e16b38bd9f0286b8af5209c..1366a7650657b4cba14d8ee6b8071fc92d2f66e9 100644 (file)
@@ -27,20 +27,29 @@ namespace CVC4 {
 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:
@@ -49,23 +58,30 @@ 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;
@@ -73,6 +89,8 @@ public:
   bool optUseModel();
   bool optInstGen();
   bool optOneQuantPerRoundInstGen();
+  // set effort
+  void setEffort( int effort );
   /** statistics class */
   class Statistics {
   public:
@@ -82,6 +100,8 @@ public:
     ~Statistics();
   };
   Statistics d_statistics;
+  // is quantifier active?
+  bool isQuantifierActive( Node f );
 };/* class ModelEngineBuilder */
 
 }/* CVC4::theory::quantifiers namespace */
index cbeeed8d05bd294b916fcc4855da4ea01c3e0c3d..b5a9ee74c07e9edfa3238e4f78017d7e8ad87d75 100644 (file)
@@ -15,7 +15,6 @@
  **/
 
 #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;
@@ -40,96 +39,97 @@ using namespace CVC4::theory::quantifiers;
 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() );
@@ -154,11 +154,7 @@ bool ModelEngine::optUseRelevantDomain(){
 }
 
 bool ModelEngine::optOneQuantPerRound(){
-#ifdef ONE_QUANT_PER_ROUND
-  return true;
-#else
-  return false;
-#endif
+  return options::fmfOneQuantPerRound();
 }
 
 int ModelEngine::initializeQuantifier( Node f ){
@@ -178,11 +174,13 @@ 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
@@ -193,67 +191,137 @@ int ModelEngine::initializeQuantifier( Node 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
@@ -270,70 +338,48 @@ int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){
           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 );
 }
index f5d1db736596346399f98a2a996542c021d36e6e..a292eb5f877e5d343f2d4b5366ad4a1f18c42eeb 100644 (file)
@@ -40,6 +40,8 @@ private:    //data maintained globally:
 private:    //analysis of current model:
   //relevant domain
   RelevantDomain d_rel_domain;
+  //is the exhaustive instantiation incomplete?
+  bool d_incomplete_check;
 private:
   //options
   bool optOneInstPerQuantRound();
@@ -48,6 +50,8 @@ private:
 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:
@@ -57,7 +61,7 @@ private:
   int d_totalLemmas;
   int d_relevantLemmas;
 public:
-  ModelEngine( QuantifiersEngine* qe );
+  ModelEngine( context::Context* c, QuantifiersEngine* qe );
   ~ModelEngine(){}
 public:
   void check( Theory::Effort e );
diff --git a/src/theory/quantifiers/modes.cpp b/src/theory/quantifiers/modes.cpp
new file mode 100644 (file)
index 0000000..b6786d9
--- /dev/null
@@ -0,0 +1,83 @@
+/*********************                                                        */
+/*! \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 */
+
diff --git a/src/theory/quantifiers/modes.h b/src/theory/quantifiers/modes.h
new file mode 100644 (file)
index 0000000..8c56b8f
--- /dev/null
@@ -0,0 +1,68 @@
+/*********************                                                        */
+/*! \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 */
index 91e831092aa4b954918c710e7f15d59cb5b285bc..a28ccb423aae177425335b48854148bf6c5799d2 100644 (file)
@@ -45,13 +45,13 @@ option smartTriggers /--disable-smart-triggers bool :default true
 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
@@ -67,23 +67,23 @@ option flipDecision --enable-flip-decision/ 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
index 24734e8c81e350b7d066bf8f3a8cb9158e644b3e..00e91d11560c0674cefded90f8a12160f239179e 100644 (file)
@@ -58,6 +58,23 @@ predicate\n\
 \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;
@@ -104,6 +121,22 @@ inline void checkLiteralMatchMode(std::string option, LiteralMatchMode mode, Smt
   }
 }
 
+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 */
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
new file mode 100644 (file)
index 0000000..22ee663
--- /dev/null
@@ -0,0 +1,43 @@
+/*********************                                                        */\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
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
new file mode 100644 (file)
index 0000000..49c374f
--- /dev/null
@@ -0,0 +1,53 @@
+/*********************                                                        */\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
index 1563a3d1d64806f8244d995cf027be66e50b738b..495e0f7a48ba583c16606e7185442a54ee229b42 100644 (file)
@@ -26,16 +26,18 @@ using namespace CVC4::context;
 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 ){
@@ -47,6 +49,7 @@ void RelevantDomain::compute(){
         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 );
@@ -56,12 +59,14 @@ void RelevantDomain::compute(){
       //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{
@@ -69,19 +74,20 @@ void RelevantDomain::compute(){
     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;
@@ -93,8 +99,9 @@ bool RelevantDomain::computeRelevantInstantiationDomain( Node n, Node parent, in
       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;
           }
         }
@@ -104,21 +111,21 @@ bool RelevantDomain::computeRelevantInstantiationDomain( Node n, Node parent, in
     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;
       }
     }
@@ -166,7 +173,13 @@ bool RelevantDomain::extendFunctionDomains( Node n, RepDomain& range ){
       }
     }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;
   }
index 6ce47d114db9b7b295c82e6500368dbee68c88f0..62522812ae7ce4bbeb57f190f8f51eb1fee3a1be 100644 (file)
@@ -28,6 +28,7 @@ namespace quantifiers {
 class RelevantDomain
 {
 private:
+  QuantifiersEngine* d_qe;
   FirstOrderModel* d_model;
 
   //the domain of the arguments for each operator
@@ -35,16 +36,17 @@ private:
   //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 */
diff --git a/src/theory/quantifiers/rep_set_iterator.cpp b/src/theory/quantifiers/rep_set_iterator.cpp
deleted file mode 100644 (file)
index 7461f34..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-/*********************                                                        */
-/*! \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
-  }
-}
-
-
diff --git a/src/theory/quantifiers/rep_set_iterator.h b/src/theory/quantifiers/rep_set_iterator.h
deleted file mode 100644 (file)
index 85a2f3f..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*********************                                                        */
-/*! \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
index a73d42a3175659314d0b6fcd409a222ef8e64fce..bd6b03a781163bfed336f0b3fbc742e0a47426b8 100644 (file)
@@ -131,7 +131,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
    //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{
@@ -199,6 +199,7 @@ Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
       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 ];
     }
@@ -337,12 +338,13 @@ Node TermDb::getFreeVariableForInstConstant( Node n ){
   TypeNode tn = n.getType();
   if( d_free_vars.find( tn )==d_free_vars.end() ){
     //if integer or real, make zero
-    if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
+    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 ];
       }
index 3d41d28b795d8a8a03891e9f030fa16fb6f8dd1f..c45626dd925ca2904b9fc8f6e2b5634b1882c5bc 100644 (file)
 #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;
@@ -42,6 +41,8 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output
   d_numRestarts(0){
   d_numInstantiations = 0;
   d_baseDecLevel = -1;
+  out.handleUserAttribute( "axiom", this );
+  out.handleUserAttribute( "conjecture", this );
 }
 
 
@@ -89,7 +90,7 @@ Node TheoryQuantifiers::getValue(TNode n) {
   }
 }
 
-void TheoryQuantifiers::collectModelInfo( TheoryModel* m ){
+void TheoryQuantifiers::collectModelInfo( TheoryModel* m, bool fullModel ){
 
 }
 
@@ -126,9 +127,12 @@ void TheoryQuantifiers::check(Effort e) {
 }
 
 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 ){
@@ -186,6 +190,6 @@ bool TheoryQuantifiers::restart(){
   }
 }
 
-void TheoryQuantifiers::performCheck(Effort e){
-  getQuantifiersEngine()->check( e );
+void TheoryQuantifiers::setUserAttribute( std::string& attr, Node n ){
+  QuantifiersAttributes::setUserAttribute( attr, n );
 }
index 1e42abd22630515083fd620c2b42f422f306f021..bc712955e370c72aa75cfcff508ce42589eb5902 100644 (file)
@@ -61,17 +61,17 @@ public:
   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 */
index 3dcd20d7863676eb40e2789c28778fa0ef023ce8..ca5cc568ea7d0ca4a4176ed3824244dfbf75050a 100644 (file)
@@ -70,7 +70,7 @@ d_active( c ){
   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() ){
@@ -81,7 +81,7 @@ d_active( c ){
     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;
@@ -121,18 +121,26 @@ void QuantifiersEngine::check( Theory::Effort e ){
 
   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 );
   }
 }
 
@@ -227,7 +235,7 @@ void QuantifiersEngine::registerPattern( std::vector<Node> & pattern) {
 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] );
     }
@@ -242,13 +250,26 @@ void QuantifiersEngine::propagate( Theory::Effort level ){
   }
 }
 
+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 ){
@@ -286,30 +307,24 @@ bool QuantifiersEngine::addLemma( Node lem ){
   }
 }
 
-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()) ){
@@ -319,10 +334,9 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms )
         }
         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());
@@ -332,6 +346,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms )
         }
       }
     }
+    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();
@@ -343,47 +358,46 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms )
   }
 }
 
-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 ){
index 5afc34bf6bd4afc3d4a1d89a86d8ec7b6cc71cc4..34d9d69a202b045f59ff7c70f165a5d9c0c2fadc 100644 (file)
@@ -102,7 +102,8 @@ public:
   /* 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 */
 
@@ -153,6 +154,8 @@ public:
   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 */
@@ -214,6 +217,8 @@ public:
   void assertNode( Node f );
   /** propagate */
   void propagate( Theory::Effort level );
+  /** get next decision request */
+  Node getNextDecisionRequest();
   /** reset instantiation round */
   void resetInstantiationRound( Theory::Effort level );
 
@@ -223,9 +228,9 @@ public:
   /** 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 */
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
new file mode 100644 (file)
index 0000000..aaca534
--- /dev/null
@@ -0,0 +1,216 @@
+/*********************                                                        */\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
diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h
new file mode 100644 (file)
index 0000000..3427502
--- /dev/null
@@ -0,0 +1,112 @@
+/*********************                                                        */\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
index b08b770d210ee7aaca83d619d73e7fa632fedfee..5ffd4ac4aec0b37c80c5c5b4afb9d3cfdd8c21a8 100644 (file)
@@ -587,7 +587,7 @@ Node TheoryRewriteRules::explain(TNode n){
   return normalizeConjunction(explanation);
 }
 
-void TheoryRewriteRules::collectModelInfo( TheoryModel* m ){
+void TheoryRewriteRules::collectModelInfo( TheoryModel* m, bool fullModel ){
 
 }
 
index bb5537474a6632bcee81b817dc9addb63ca9bb2f..5937c541f20f78ed0423ed03b8fa654f3a2e3f90 100644 (file)
@@ -207,7 +207,7 @@ private:
   /** 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";
index 7abc7f1e5c1871a48b310790ce5894d4937f0c3e..42645820293ab1b6aacd062586767b2c4177cfb9 100644 (file)
@@ -130,7 +130,7 @@ bool SharedTermsDatabase::propagateSharedEquality(TheoryId theory, TNode a, TNod
     return false;
   }
 
-  // Propagate away 
+  // Propagate away
   Node equality = a.eqNode(b);
   if (value) {
     d_theoryEngine->assertToTheory(equality, theory, THEORY_BUILTIN);
@@ -156,20 +156,20 @@ void SharedTermsDatabase::markNotified(TNode term, Theory::Set theories) {
   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 {
@@ -181,7 +181,7 @@ 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)) {
@@ -240,7 +240,7 @@ void SharedTermsDatabase::checkForConflict() {
     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();
   }
 }
@@ -261,6 +261,9 @@ Node SharedTermsDatabase::explain(TNode literal) const {
   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 );
+}
index 7b6527517495105c910a50ea9b860c42439d33d3..c685257ba5beee82318c7a018ad1e63ff4d33165 100644 (file)
@@ -242,6 +242,11 @@ public:
    * get equality engine
    */
   theory::eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; }
+
+  /**
+   * collect model info
+   */
+  void collectModelInfo( theory::TheoryModel* m, bool fullModel );
 protected:
 
   /**
index ab6b27dffc6a3543df59cd98b35f8ac98a152d81..104292e18840e23399e19ba350f4a01bfc35322e 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "theory/term_registration_visitor.h"
 #include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
 
 using namespace std;
 using namespace CVC4;
@@ -37,7 +38,8 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
 
   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;
@@ -160,7 +162,8 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
 
   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;
@@ -179,12 +182,40 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
   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;
@@ -208,7 +239,36 @@ void SharedTermsVisitor::visit(TNode current, TNode parent) {
   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;
@@ -221,7 +281,7 @@ void SharedTermsVisitor::visit(TNode current, TNode parent) {
     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;
index 46244aec62a6249ee500ab4b4953bb3ee3aea9b6..2f980fe2fc3688b766b26274d42e018c50e21c79 100644 (file)
@@ -553,11 +553,11 @@ public:
    * 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
@@ -657,6 +657,15 @@ public:
    */
   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;
 
index 7a67012a2ec8a7fcc600abcf63a2ba06536e6950..6dbabfe4df43ed3d064f6d0da8b676b8496d8710 100644 (file)
 #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;
@@ -85,7 +90,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
   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();
@@ -144,33 +149,57 @@ void TheoryEngine::preRegister(TNode preprocessed) {
   }
 }
 
+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;
           }
         }
       }
     }
-
   }
 }
 
@@ -312,7 +341,8 @@ void TheoryEngine::check(Theory::Effort effort) {
 
       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");
       }
 
@@ -346,7 +376,8 @@ void TheoryEngine::check(Theory::Effort effort) {
         ! 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) {
@@ -358,7 +389,7 @@ void TheoryEngine::check(Theory::Effort effort) {
         //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 );
       }
     }
 
@@ -436,6 +467,7 @@ void TheoryEngine::combineTheories() {
           d_factsAsserted = true;
           continue;
         } else {
+          Message() << "mark propagation fail: " << literal << " " << normalizedLiteral << " " << carePair.theory << std::endl;
           Unreachable();
         }
       }
@@ -560,12 +592,14 @@ bool TheoryEngine::properExplanation(TNode node, TNode expl) const {
   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 );
     }
   }
 }
@@ -688,6 +722,16 @@ theory::Theory::PPAssertStatus TheoryEngine::solve(TNode literal, SubstitutionMa
 
   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;
 }
 
@@ -1307,3 +1351,21 @@ void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
 {
   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 );
+}
index 75f4d6a3746005cfb9c427bbb5de43dd4ea8fe6c..d1d6bd1f35a4df29867f8c3ab4cb3b7e959d164d 100644 (file)
@@ -274,7 +274,9 @@ class TheoryEngine {
     void spendResource() throw() {
       d_engine->spendResource();
     }
-
+    void handleUserAttribute( const char* attr, theory::Theory* t ){
+      d_engine->handleUserAttribute( attr, t );
+    }
   };/* class TheoryEngine::EngineOutputChannel */
 
   /**
@@ -616,7 +618,7 @@ public:
   /**
    * collect model info
    */
-  void collectModelInfo( theory::TheoryModel* m );
+  void collectModelInfo( theory::TheoryModel* m, bool fullModel );
 
   /**
    * Get the current model
@@ -680,6 +682,22 @@ public:
 
   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 */
index f827b9ee7120eb3a1acf1d9d46df8b5357ed7f8d..ee7b4cf2dd20e2cb93470ad34166eb9c6b0f2d60 100644 (file)
@@ -103,6 +103,8 @@ public:
 
   void setIncomplete() throw(AssertionException) {}
 
+  void handleUserAttribute( const char* attr, theory::Theory* t ){}
+
   void clear() {
     d_callHistory.clear();
   }
index 1e3b276a4d4306f9f154506fdc3eda19f135c5b2..45d1b4acfc8d5aba74144b1761b97601aef8ac34 100644 (file)
@@ -82,7 +82,7 @@ public:
   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
@@ -384,7 +384,7 @@ private:
   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;
@@ -427,7 +427,7 @@ private:
   /**
    * 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;
 
@@ -440,7 +440,7 @@ private:
   Node d_true;
   /** True node id */
   EqualityNodeId d_trueId;
-  
+
   /** The false node */
   Node d_false;
   /** False node id */
@@ -484,12 +484,12 @@ private:
 
   /** 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;
@@ -524,7 +524,7 @@ private:
   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 */
 
@@ -591,7 +591,7 @@ private:
    * reasons should be pushed on the reasons vector.
    */
   void storePropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId);
-  
+
   /**
    * An equality tagged with a set of tags.
    */
@@ -599,10 +599,10 @@ private:
     /** 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) {}
   };
@@ -625,9 +625,9 @@ private:
 
   /**
    * 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 */
@@ -636,12 +636,12 @@ private:
 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);
 
@@ -791,7 +791,7 @@ class EqClassesIterator {
 
   const eq::EqualityEngine* d_ee;
   size_t d_it;
-
+  std::vector< Node > d_visited;
 public:
 
   EqClassesIterator(): d_ee(NULL), d_it(0){ }
@@ -812,11 +812,11 @@ public:
     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;
index efad8beb9d06594b02e87d2bd1bbbb8508e39e79..1d179248c9d420d30480145c7ca58ea6f5ae3fda 100644 (file)
@@ -9,7 +9,7 @@ typechecker "theory/uf/theory_uf_type_rules.h"
 instantiator ::CVC4::theory::uf::InstantiatorTheoryUf "theory/uf/theory_uf_instantiator.h"
 
 properties stable-infinite parametric
-properties check propagate 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"
@@ -19,47 +19,4 @@ typerule APPLY_UF ::CVC4::theory::uf::UfTypeRule
 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
index 6f6900da0e7c75cd1a050bb4dfe2a17624044fa7..8185f0b3df47c8368ce8068ce63fdaa8df0e82a1 100644 (file)
@@ -9,4 +9,22 @@ option ufSymmetryBreaker uf-symmetry-breaker --enable-symmetry-breaker/--disable
  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
index 5b8470567d060341257d560453ce19b638527e3e..a1500e084ba0c2778ba539d83dc712f6491b3d56 100644 (file)
@@ -23,6 +23,7 @@
 #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;
@@ -80,6 +81,10 @@ void TheoryUF::check(Effort level) {
     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
@@ -98,6 +103,9 @@ void TheoryUF::check(Effort level) {
   if (d_thss != NULL) {
     if (! d_conflict) {
       d_thss->check(level);
+      if( d_thss->isConflict() ){
+        d_conflict = true;
+      }
     }
   }
 
@@ -127,6 +135,9 @@ void TheoryUF::preRegisterTerm(TNode node) {
     // 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);
@@ -150,8 +161,16 @@ bool TheoryUF::propagate(TNode literal) {
 }/* 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();
   }
 }
 
@@ -173,8 +192,55 @@ Node TheoryUF::explain(TNode literal) {
   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() {
@@ -481,3 +547,4 @@ Node TheoryUF::ppRewrite(TNode node) {
     }
   }
 }
+
index 604b1f44c8e45204bf716ff4eb0d91b1f7d81e48..62ca640aa274af040700007a98624082aaf2636a 100644 (file)
@@ -193,7 +193,7 @@ public:
   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();
@@ -202,6 +202,7 @@ public:
   void computeCareGraph();
 
   void propagate(Effort effort);
+  Node getNextDecisionRequest();
 
   EqualityStatus getEqualityStatus(TNode a, TNode b);
 
@@ -226,7 +227,6 @@ public:
   void registerPpRewrite(TNode op, PpRewrite* callback) {
     d_registeredPpRewrites.insert(std::make_pair(op, callback));
   }
-
 };/* class TheoryUF */
 
 }/* CVC4::theory::uf namespace */
index 0082f4840c2bfdea681a4663bc047762d39f9c29..b8110a2aa34027fa8acb3eb618a638b33c9594df 100644 (file)
@@ -136,35 +136,46 @@ Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& inde
   }
 }
 
-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 ){
@@ -251,31 +262,17 @@ void UfModelTreeNode::debugPrint( std::ostream& out, TheoryModel* m, std::vector
   }
 }
 
-
-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;
index 9dba16608cb8dbbbc6c1e622a0578e500d8a75d2..61c0714a31463f2050f45c684bb65b3778b61ad2 100644 (file)
@@ -48,7 +48,9 @@ public:
   /** 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 ? */
@@ -123,12 +125,15 @@ public:
     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? */
@@ -147,6 +152,7 @@ private:
 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
index f0b386caefbcbe76ec22e9e95fe05bda3d06cc2b..47c51d8b90e7bf5ef9c656f35c9dfeec37f76aa2 100644 (file)
 #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
@@ -34,16 +33,11 @@ using namespace CVC4::context;
 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
@@ -75,7 +69,7 @@ void StrongSolverTheoryUf::ConflictFind::Region::takeNode( StrongSolverTheoryUf:
   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 ){
@@ -107,7 +101,7 @@ void StrongSolverTheoryUf::ConflictFind::Region::combine( StrongSolverTheoryUf::
 }
 
 /** 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++ ){
@@ -129,7 +123,7 @@ void StrongSolverTheoryUf::ConflictFind::Region::setEqual( Node a, Node b ){
   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 );
@@ -155,7 +149,7 @@ void StrongSolverTheoryUf::ConflictFind::Region::setDisequal( Node n1, Node n2,
   }
 }
 
-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() );
@@ -179,22 +173,24 @@ void StrongSolverTheoryUf::ConflictFind::Region::setRep( Node n, bool valid ){
   }
 }
 
-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
@@ -218,11 +214,10 @@ bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality
         }
       }
     }
-    //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++ ){
@@ -234,16 +229,21 @@ bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality
   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) ){
@@ -318,7 +318,7 @@ bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, in
   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 ){
@@ -327,7 +327,7 @@ void StrongSolverTheoryUf::ConflictFind::Region::getRepresentatives( std::vector
   }
 }
 
-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 ){
@@ -341,98 +341,7 @@ void StrongSolverTheoryUf::ConflictFind::Region::getNumExternalDisequalities( st
   }
 }
 
-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;
@@ -474,238 +383,431 @@ void StrongSolverTheoryUf::ConflictFind::Region::debugPrint( const char* c, bool
   }
 }
 
-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 ){
@@ -724,7 +826,7 @@ void StrongSolverTheoryUf::ConflictFind::checkRegion( int ri, bool rec ){
   }
 }
 
-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 ){
@@ -764,7 +866,7 @@ int StrongSolverTheoryUf::ConflictFind::forceCombineRegion( int ri, bool useDens
 }
 
 
-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 );
@@ -784,7 +886,7 @@ int StrongSolverTheoryUf::ConflictFind::combineRegions( int ai, int bi ){
   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 ) );
@@ -793,161 +895,248 @@ void StrongSolverTheoryUf::ConflictFind::moveNode( Node n, int 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;
@@ -972,7 +1161,32 @@ void StrongSolverTheoryUf::ConflictFind::debugPrint( const char* c ){
   }
 }
 
-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 ){
@@ -982,25 +1196,7 @@ int StrongSolverTheoryUf::ConflictFind::getNumRegions(){
   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++ ){
@@ -1019,87 +1215,158 @@ void StrongSolverTheoryUf::ConflictFind::getRepresentatives( std::vector< Node >
   }
 }
 
-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 );
@@ -1108,88 +1375,89 @@ void StrongSolverTheoryUf::assertDisequal( Node a, Node b, Node 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() ){
@@ -1205,63 +1473,51 @@ void StrongSolverTheoryUf::registerQuantifier( Node f ){
       }
       */
     }
+    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{
@@ -1269,28 +1525,22 @@ int StrongSolverTheoryUf::getCardinality( TypeNode t ) {
   }
 }
 
-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;
 }
 
@@ -1309,22 +1559,32 @@ void StrongSolverTheoryUf::debugPrint( const char* c ){
   //  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);
 }
 
@@ -1332,10 +1592,70 @@ StrongSolverTheoryUf::Statistics::~Statistics(){
   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() ){
index 479fea05f9ede7c922a671712702af3fd04a4bc4..8c63b4308c0bfe27c6fb59c9af255aebbee635e1 100644 (file)
@@ -32,24 +32,63 @@ namespace theory {
 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:
@@ -86,14 +125,13 @@ 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;
@@ -106,11 +144,11 @@ public:
       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
@@ -146,10 +184,6 @@ public:
     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 );
     };
@@ -162,25 +196,23 @@ public:
     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 );
@@ -191,78 +223,131 @@ public:
     /** 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() {}
@@ -279,6 +364,8 @@ public:
   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 */
@@ -290,35 +377,52 @@ public:
   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 */
index d00b69398271ed032684f1842c60e6b33d707c39..09f287884d6338e7cda9b3a195fc60d395eaf34e 100644 (file)
@@ -72,68 +72,6 @@ public:
   }
 };/* 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 */
index 948a7a1304537f2d905be421819d33e49414811f..d4c7a299e7cca3b6fb0a2a807392724c9482d2d9 100644 (file)
@@ -99,5 +99,9 @@ bool Valuation::isDecision(Node lit) const {
   return d_engine->getPropEngine()->isDecision(lit);
 }
 
+unsigned Valuation::getAssertionLevel() const{
+  return d_engine->getPropEngine()->getAssertionLevel();
+}
+
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index 7f3a00ec1181fc406313fa324557da6517704a7b..083163a5c2a729b5c5f9e3beccc94dfe322c0208 100644 (file)
@@ -117,6 +117,11 @@ public:
    */
   bool isDecision(Node lit) const;
 
+  /**
+   * Get the assertion level of the SAT solver.
+   */
+  unsigned getAssertionLevel() const;
+
 };/* class Valuation */
 
 }/* CVC4::theory namespace */
index bdefe67550ec4ad90b2ce8eeb3326e4e4ca7359c..bdb3f6cf6f70ef0b78308035a23b190c6315a00b 100644 (file)
@@ -379,6 +379,15 @@ Expr Datatype::getConstructor(std::string name) const {
   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,
@@ -689,7 +698,7 @@ Expr DatatypeConstructor::mkGroundTerm( Type t ) const throw(AssertionException)
     }
     groundTerms.push_back(selType.mkGroundTerm());
   }
-  
+
   groundTerm = getConstructor().getExprManager()->mkExpr(kind::APPLY_CONSTRUCTOR, groundTerms);
   if( groundTerm.getType()!=t ){
     Assert( Datatype::datatypeOf( d_constructor ).isParametric() );
@@ -722,6 +731,15 @@ Expr DatatypeConstructor::getSelector(std::string name) const {
   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),
index 60d2c7acdf9ed115e26e52d689e44d17d4aeb644..9853ba4177db4ef999d59bdd783c5ec9440dbf82 100644 (file)
@@ -316,6 +316,12 @@ public:
    */
   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 */
 
 /**
@@ -370,7 +376,7 @@ public:
  *    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
@@ -562,6 +568,12 @@ public:
    */
   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 */
 
 /**
index 60f1ab23f794969d59f24fb4bfab5089d77c3527..747247ae130128045e657fbcb03c70675e65679f 100644 (file)
 #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 */
@@ -34,7 +60,7 @@ class ModelBuilder
 public:
   ModelBuilder(){}
   virtual ~ModelBuilder(){}
-  virtual void buildModel( Model* m ) = 0;
+  virtual void buildModel( Model* m, bool fullModel ) = 0;
 };/* class ModelBuilder */
 
 }/* CVC4 namespace */
diff --git a/test/regress/regress0/quantifiers/refcount24.cvc b/test/regress/regress0/quantifiers/refcount24.cvc
new file mode 100644 (file)
index 0000000..21c9a3c
--- /dev/null
@@ -0,0 +1,112 @@
+% 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;
index eb6e5eefb4d831e9dec9fd65121f41d8cf1372e7..2a176e3d9efb7979cbd4d4a92a6b07aad1cf04b6 100644 (file)
@@ -75,6 +75,9 @@ class FakeOutputChannel : public OutputChannel {
   void setIncomplete() throw(AssertionException) {
     Unimplemented();
   }
+  void handleUserAttribute( const char* attr, Theory* t ){
+    Unimplemented();
+  }
 };/* class FakeOutputChannel */
 
 template<TheoryId theory>