Make fun-def quantifiers carry the function app they define, make fun-def utilities...
authorajreynol <andrew.j.reynolds@gmail.com>
Wed, 8 Apr 2015 10:15:27 +0000 (12:15 +0200)
committerajreynol <andrew.j.reynolds@gmail.com>
Wed, 8 Apr 2015 10:15:33 +0000 (12:15 +0200)
src/parser/smt2/Smt2.g
src/theory/quantifiers/conjecture_generator.cpp
src/theory/quantifiers/conjecture_generator.h
src/theory/quantifiers/fun_def_process.cpp
src/theory/quantifiers/term_database.cpp
src/theory/quantifiers/term_database.h

index eac16372ac2796afe78e322b55a07cb91576b2ac..8b7c0bda2a38fb527d64c4630adb413f2ed357dc 100644 (file)
@@ -913,12 +913,10 @@ smt25Command[CVC4::Command*& cmd]
       term[expr, expr2]
       { PARSER_STATE->popScope(); 
         std::string attr_name("fun-def");
-        Type t = EXPR_MANAGER->booleanType();
-        Expr avar = PARSER_STATE->mkVar(attr_name, t);
-        aexpr = MK_EXPR(kind::INST_ATTRIBUTE, avar);
-        aexpr = MK_EXPR(kind::INST_PATTERN_LIST, aexpr );
+        aexpr = MK_EXPR(kind::INST_ATTRIBUTE, func_app);
+        aexpr = MK_EXPR(kind::INST_PATTERN_LIST, aexpr);
         //set the attribute to denote this is a function definition
-        static_cast<CommandSequence*>($cmd)->addCommand( new SetUserAttributeCommand( attr_name, avar ) );
+        static_cast<CommandSequence*>($cmd)->addCommand( new SetUserAttributeCommand( attr_name, func_app ) );
         //assert it
         Expr as = EXPR_MANAGER->mkExpr(kind::FORALL, EXPR_MANAGER->mkExpr(kind::BOUND_VAR_LIST, bvs), MK_EXPR( func_app.getType().isBoolean() ? kind::IFF : kind::EQUAL, func_app, expr ), aexpr);
         static_cast<CommandSequence*>($cmd)->addCommand( new AssertCommand(as, false) );
@@ -952,14 +950,6 @@ smt25Command[CVC4::Command*& cmd]
     RPAREN_TOK
     LPAREN_TOK
     { 
-      std::string attr_name("fun-def");
-      Type t = EXPR_MANAGER->booleanType();
-      Expr avar = PARSER_STATE->mkVar(attr_name, t);
-      aexpr = MK_EXPR(kind::INST_ATTRIBUTE, avar);
-      aexpr = MK_EXPR(kind::INST_PATTERN_LIST, aexpr );
-      //set the attribute to denote these are function definitions
-      static_cast<CommandSequence*>($cmd)->addCommand( new SetUserAttributeCommand( attr_name, avar ) );
-    
       //set up the first scope 
       if( sortedVarNamesList.empty() ){
         PARSER_STATE->parseError(std::string("Must define at least one function in define-funs-rec"));
@@ -980,6 +970,12 @@ smt25Command[CVC4::Command*& cmd]
     term[expr,expr2]
     { 
       func_defs.push_back( expr );
+      
+      std::string attr_name("fun-def");
+      aexpr = MK_EXPR(kind::INST_ATTRIBUTE, func_app);
+      aexpr = MK_EXPR(kind::INST_PATTERN_LIST, aexpr );
+      //set the attribute to denote these are function definitions
+      static_cast<CommandSequence*>($cmd)->addCommand( new SetUserAttributeCommand( attr_name, func_app ) );
       //assert it
       Expr as = EXPR_MANAGER->mkExpr(kind::FORALL, EXPR_MANAGER->mkExpr(kind::BOUND_VAR_LIST, bvs), MK_EXPR( func_app.getType().isBoolean() ? kind::IFF : kind::EQUAL, func_app, expr ), aexpr);
       static_cast<CommandSequence*>($cmd)->addCommand( new AssertCommand(as, false) );
@@ -1752,7 +1748,10 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
         ss << "warning: Attribute " << attr << " does not take a value (ignoring)";
         PARSER_STATE->warning(ss.str());
       }
+      Expr avar;
       bool success = true;
+      std::string attr_name = attr;
+      attr_name.erase( attr_name.begin() );
       if( attr==":fun-def" ){
         if( ( expr.getKind()!=kind::EQUAL && expr.getKind()!=kind::IFF ) || expr[0].getKind()!=kind::APPLY_UF ){
           success = false;
@@ -1776,14 +1775,15 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
           std::stringstream ss;
           ss << "warning: Function definition should be an equality whose LHS is an uninterpreted function applied to unique variables.";
           PARSER_STATE->warning(ss.str());
+        }else{
+          avar = expr[0];
         }
+      }else{
+        Type t = EXPR_MANAGER->booleanType();
+        avar = PARSER_STATE->mkVar(attr_name, t);
       }
       if( success ){
-        std::string attr_name = attr;
-        attr_name.erase( attr_name.begin() );
         //will set the attribute on auxiliary var (preserves attribute on formula through rewriting)
-        Type t = EXPR_MANAGER->booleanType();
-        Expr avar = PARSER_STATE->mkVar(attr_name, t);
         retExpr = MK_EXPR(kind::INST_ATTRIBUTE, avar);
         Command* c = new SetUserAttributeCommand( attr_name, avar );
         c->setMuted(true);
index 520ea5e70807bc04ce659cb44e7eb9a0d8f6a389..48d3f390245356755e303e925f7ba3bbd48fcc19 100755 (executable)
@@ -285,8 +285,12 @@ Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) {
   while( d_free_var[tn].size()<=i ){\r
     std::stringstream oss;\r
     oss << tn;\r
+    std::string typ_name = oss.str();\r
+    while( typ_name[0]=='(' ){\r
+      typ_name.erase( typ_name.begin() );\r
+    }\r
     std::stringstream os;\r
-    os << oss.str()[0] << i;\r
+    os << typ_name[0] << i;\r
     Node x = NodeManager::currentNM()->mkBoundVar( os.str().c_str(), tn );\r
     d_free_var_num[x] = d_free_var[tn].size();\r
     d_free_var[tn].push_back( x );\r
@@ -1713,7 +1717,9 @@ Node TermGenerator::getTerm( TermGenEnv * s ) {
     Node f = s->getTgFunc( d_typ, d_status_num );\r
     if( d_children.size()==s->d_func_args[f].size() ){\r
       std::vector< Node > children;\r
-      children.push_back( f );\r
+      if( s->d_tg_func_param[f] ){\r
+        children.push_back( f );\r
+      }\r
       for( unsigned i=0; i<d_children.size(); i++ ){\r
         Node nc = s->d_tg_alloc[d_children[i]].getTerm( s );\r
         if( nc.isNull() ){\r
@@ -1776,6 +1782,7 @@ void TermGenEnv::collectSignatureInformation() {
           d_func_kind[it->first] = nn.getKind();\r
           d_typ_tg_funcs[tnull].push_back( it->first );\r
           d_typ_tg_funcs[nn.getType()].push_back( it->first );\r
+          d_tg_func_param[it->first] = ( nn.getMetaKind() == kind::metakind::PARAMETERIZED );\r
           Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl;\r
           getTermDatabase()->computeUfEqcTerms( it->first );\r
         }\r
index 462fadfcef0cf695e567ede60cf905ebb9335847..2d8e8e403be55ec06709fb483af74bedbe1e51e0 100755 (executable)
@@ -138,6 +138,8 @@ public:
   std::map< TypeNode, unsigned > d_var_limit;\r
   //the functions we can currently generate\r
   std::map< TypeNode, std::vector< TNode > > d_typ_tg_funcs;\r
+  // whether functions must add operators\r
+  std::map< TNode, bool > d_tg_func_param;\r
   //the equivalence classes (if applicable) that match the currently generated term\r
   bool d_gen_relevant_terms;\r
   //relevant equivalence classes\r
index 0bc365ec77713c5521fdf228bb4e50d2f12ad324..b80d9d744bcca6408beaf1e672f1f7814d37b05e 100644 (file)
@@ -32,66 +32,71 @@ void FunDefFmf::simplify( std::vector< Node >& assertions, bool doRewrite ) {
   std::vector< int > fd_assertions;
   //first pass : find defined functions, transform quantifiers
   for( unsigned i=0; i<assertions.size(); i++ ){
-    if( assertions[i].getKind()==FORALL ){
-      if( quantifiers::TermDb::isFunDef( assertions[i] ) ){
-        Assert( assertions[i][1].getKind()==EQUAL || assertions[i][1].getKind()==IFF );
-        Node n = assertions[i][1][0];
-        Assert( n.getKind()==APPLY_UF );
-        Node f = n.getOperator();
-
-        //check if already defined, if so, throw error
-        if( d_sorts.find( f )!=d_sorts.end() ){
-          Message() << "Cannot define function " << f << " more than once." << std::endl;
-          exit( 0 );
-        }
+    Node n = TermDb::getFunDefHead( assertions[i] );
+    if( !n.isNull() ){
+      Assert( n.getKind()==APPLY_UF );
+      Node f = n.getOperator();
 
-        //create a sort S that represents the inputs of the function
-        std::stringstream ss;
-        ss << "I_" << f;
-        TypeNode iType = NodeManager::currentNM()->mkSort( ss.str() );
-        d_sorts[f] = iType;
+      //check if already defined, if so, throw error
+      if( d_sorts.find( f )!=d_sorts.end() ){
+        Message() << "Cannot define function " << f << " more than once." << std::endl;
+        exit( 0 );
+      }
+      
+      Node bd = TermDb::getFunDefBody( assertions[i] );
+      Assert( !bd.isNull() );
+      bd = NodeManager::currentNM()->mkNode( n.getType().isBoolean() ? IFF : EQUAL, n, bd );
 
-        //create functions f1...fn mapping from this sort to concrete elements
-        for( unsigned j=0; j<n.getNumChildren(); j++ ){
-          TypeNode typ = NodeManager::currentNM()->mkFunctionType( iType, n[j].getType() );
-          std::stringstream ss;
-          ss << f << "_arg_" << j;
-          d_input_arg_inj[f].push_back( NodeManager::currentNM()->mkSkolem( ss.str(), typ, "op created during fun def fmf" ) );
-        }
+      //create a sort S that represents the inputs of the function
+      std::stringstream ss;
+      ss << "I_" << f;
+      TypeNode iType = NodeManager::currentNM()->mkSort( ss.str() );
+      d_sorts[f] = iType;
 
-        //construct new quantifier forall S. F[f1(S)/x1....fn(S)/xn]
-        std::vector< Node > children;
-        Node bv = NodeManager::currentNM()->mkBoundVar("?i", iType );
-        Node bvl = NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, bv );
-        std::vector< Node > subs;
-        std::vector< Node > vars;
-        for( unsigned j=0; j<n.getNumChildren(); j++ ){
-          vars.push_back( n[j] );
-          subs.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, d_input_arg_inj[f][j], bv ) );
-        }
-        Node bd = assertions[i][1].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+      //create functions f1...fn mapping from this sort to concrete elements
+      for( unsigned j=0; j<n.getNumChildren(); j++ ){
+        TypeNode typ = NodeManager::currentNM()->mkFunctionType( iType, n[j].getType() );
+        std::stringstream ss;
+        ss << f << "_arg_" << j;
+        d_input_arg_inj[f].push_back( NodeManager::currentNM()->mkSkolem( ss.str(), typ, "op created during fun def fmf" ) );
+      }
 
-        Trace("fmf-fun-def") << "FMF fun def: rewrite " << assertions[i] << std::endl;
-        Trace("fmf-fun-def") << "  to " << std::endl;
-        assertions[i] = NodeManager::currentNM()->mkNode( FORALL, bvl, bd );
-        Trace("fmf-fun-def") << "  " << assertions[i] << std::endl;
-        fd_assertions.push_back( i );
+      //construct new quantifier forall S. F[f1(S)/x1....fn(S)/xn]
+      std::vector< Node > children;
+      Node bv = NodeManager::currentNM()->mkBoundVar("?i", iType );
+      Node bvl = NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, bv );
+      std::vector< Node > subs;
+      std::vector< Node > vars;
+      for( unsigned j=0; j<n.getNumChildren(); j++ ){
+        vars.push_back( n[j] );
+        subs.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, d_input_arg_inj[f][j], bv ) );
       }
+      bd = bd.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+
+      Trace("fmf-fun-def") << "FMF fun def: rewrite " << assertions[i] << std::endl;
+      Trace("fmf-fun-def") << "  to " << std::endl;
+      assertions[i] = NodeManager::currentNM()->mkNode( FORALL, bvl, bd );
+      assertions[i] = Rewriter::rewrite( assertions[i] );
+      Trace("fmf-fun-def") << "  " << assertions[i] << std::endl;
+      fd_assertions.push_back( i );
     }
   }
   //second pass : rewrite assertions
   for( unsigned i=0; i<assertions.size(); i++ ){
     int is_fd = std::find( fd_assertions.begin(), fd_assertions.end(), i )!=fd_assertions.end() ? 1 : 0;
-    std::vector< Node > constraints;
-    Trace("fmf-fun-def-rewrite") << "Rewriting " << assertions[i] << ", is_fd = " << is_fd << std::endl;
-    Node n = simplify( assertions[i], true, true, constraints, is_fd );
-    Assert( constraints.empty() );
-    if( n!=assertions[i] ){
-      n = Rewriter::rewrite( n );
-      Trace("fmf-fun-def-rewrite") << "FMF fun def : rewrite " << assertions[i] << std::endl;
-      Trace("fmf-fun-def-rewrite") << "  to " << std::endl;
-      Trace("fmf-fun-def-rewrite") << "  " << n << std::endl;
-      assertions[i] = n;
+    //constant boolean function definitions do not add domain constraints
+    if( is_fd==0 || ( is_fd==1 && ( assertions[i][1].getKind()==EQUAL || assertions[i][1].getKind()==IFF ) ) ){
+      std::vector< Node > constraints;
+      Trace("fmf-fun-def-rewrite") << "Rewriting " << assertions[i] << ", is_fd = " << is_fd << std::endl;
+      Node n = simplify( assertions[i], true, true, constraints, is_fd );
+      Assert( constraints.empty() );
+      if( n!=assertions[i] ){
+        n = Rewriter::rewrite( n );
+        Trace("fmf-fun-def-rewrite") << "FMF fun def : rewrite " << assertions[i] << std::endl;
+        Trace("fmf-fun-def-rewrite") << "  to " << std::endl;
+        Trace("fmf-fun-def-rewrite") << "  " << n << std::endl;
+        assertions[i] = n;
+      }
     }
   }
 }
index 2e2007c0ac995bdfae635044054fd4cae4999e7e..090d127f17b40de7465f6b555c7d28adea3984fd 100644 (file)
@@ -1187,20 +1187,44 @@ Node TermDb::getRewriteRule( Node q ) {
 }
 
 bool TermDb::isFunDef( Node q ) {
-  if( q.getKind()==FORALL && ( q[1].getKind()==EQUAL || q[1].getKind()==IFF ) && q[1][0].getKind()==APPLY_UF && q.getNumChildren()==3 ){
+  return !getFunDefHead( q ).isNull();
+}
+
+Node TermDb::getFunDefHead( Node q ) {
+  //&& ( q[1].getKind()==EQUAL || q[1].getKind()==IFF ) && q[1][0].getKind()==APPLY_UF && 
+  if( q.getKind()==FORALL && q.getNumChildren()==3 ){
     for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
       if( q[2][i].getKind()==INST_ATTRIBUTE ){
         if( q[2][i][0].getAttribute(FunDefAttribute()) ){
-          return true;
+          return q[2][i][0];
         }
       }
     }
   }
-  return false;
+  return Node::null();
+}
+Node TermDb::getFunDefBody( Node q ) {
+  Node h = getFunDefHead( q );
+  if( !h.isNull() ){
+    if( q[1].getKind()==EQUAL || q[1].getKind()==IFF ){
+      if( q[1][0]==h ){
+        return q[1][1];
+      }else if( q[1][1]==h ){
+        return q[1][0];
+      }
+    }else{
+      Node atom = q[1].getKind()==NOT ? q[1][0] : q[1];
+      bool pol = q[1].getKind()!=NOT;
+      if( atom==h ){
+        return NodeManager::currentNM()->mkConst( pol );
+      }
+    }
+  }
+  return Node::null();
 }
-
 
 void TermDb::computeAttributes( Node q ) {
+  Trace("quant-attr-debug") << "Compute attributes for " << q << std::endl;
   if( q.getNumChildren()==3 ){
     for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
       Trace("quant-attr-debug") << "Check : " << q[2][i] << " " << q[2][i].getKind() << std::endl;
@@ -1217,9 +1241,9 @@ void TermDb::computeAttributes( Node q ) {
         if( avar.getAttribute(FunDefAttribute()) ){
           Trace("quant-attr") << "Attribute : function definition : " << q << std::endl;
           d_qattr_fundef[q] = true;
-          Assert( q[1].getKind()==EQUAL || q[1].getKind()==IFF );
-          Assert( q[1][0].getKind()==APPLY_UF );
-          Node f = q[1][0].getOperator();
+          //Assert( q[1].getKind()==EQUAL || q[1].getKind()==IFF );
+          //Assert( q[2][i][0]==q[1][0] || q[2][i][0]==q[1][1] );
+          Node f = q[2][i][0].getOperator();
           if( d_fun_defs.find( f )!=d_fun_defs.end() ){
             Message() << "Cannot define function " << f << " more than once." << std::endl;
             exit( 0 );
index e4e34ce7f8bd5e4cf5cf3cc56d2f3cda75ed7682..db84ba885fc4528b44feeb334ca25c7dbe230d36 100644 (file)
@@ -340,6 +340,10 @@ public: //general queries concerning quantified formulas wrt modules
   static Node getRewriteRule( Node q );
   /** is fun def */
   static bool isFunDef( Node q );
+  /** get fun def body */
+  static Node getFunDefHead( Node q );
+  /** get fun def body */
+  static Node getFunDefBody( Node q );
 //attributes
 private:
   std::map< Node, bool > d_qattr_conjecture;