Rel smt parser (#1446)
authorArjun Viswanathan <arjun-viswanathan@uiowa.edu>
Thu, 28 Dec 2017 03:43:35 +0000 (21:43 -0600)
committerAndrew Reynolds <andrew.j.reynolds@gmail.com>
Thu, 28 Dec 2017 03:43:35 +0000 (21:43 -0600)
src/parser/smt2/Smt2.g
src/parser/smt2/smt2.cpp
src/printer/smt2/smt2_printer.cpp
test/regress/regress0/datatypes/Makefile.am
test/regress/regress0/datatypes/tuples-empty.smt2 [new file with mode: 0644]
test/regress/regress0/datatypes/tuples-multitype.smt2 [new file with mode: 0644]
test/regress/regress0/rels/Makefile.am
test/regress/regress0/rels/relations-ops.smt2 [new file with mode: 0644]

index 81f62ccf48ae034025a54fa6288dd2481dcd2838..d424fefad786e58e4f8e61e0b153b48b321abc90 100644 (file)
@@ -1980,11 +1980,33 @@ termNonVariable[CVC4::Expr& expr, CVC4::Expr& expr2]
 
   | LPAREN_TOK
     ( /* An indexed function application */
-      indexedFunctionName[op, kind] termList[args,expr] RPAREN_TOK
-      { 
-        if( kind!=kind::NULL_EXPR ){
+      indexedFunctionName[op, kind] termList[args,expr] RPAREN_TOK { 
+        if(kind==CVC4::kind::APPLY_SELECTOR) {
+          //tuple selector case
+          Integer x = op.getConst<CVC4::Rational>().getNumerator();
+          if (!x.fitsUnsignedInt()) {
+            PARSER_STATE->parseError("index of tupSel is larger than size of unsigned int");
+          }
+          unsigned int n = x.toUnsignedInt();
+          if (args.size()>1) {
+            PARSER_STATE->parseError("tupSel applied to more than one tuple argument");
+          }
+          Type t = args[0].getType();
+          if (!t.isTuple()) {
+            PARSER_STATE->parseError("tupSel applied to non-tuple");
+          }
+          size_t length = ((DatatypeType)t).getTupleLength();
+          if (n >= length) {
+            std::stringstream ss;
+            ss << "tuple is of length " << length << "; cannot access index " << n;
+            PARSER_STATE->parseError(ss.str());
+          }
+          const Datatype & dt = ((DatatypeType)t).getDatatype();
+          op = dt[0][n].getSelector();
+        }
+        if (kind!=kind::NULL_EXPR) {
           expr = MK_EXPR( kind, op, args );
-        }else{
+        } else {
           expr = MK_EXPR(op, args);
         }
         PARSER_STATE->checkOperator(expr.getKind(), args.size());
@@ -2347,6 +2369,25 @@ termNonVariable[CVC4::Expr& expr, CVC4::Expr& expr2]
     { //booleanType is placeholder here since we don't have type info without type annotation
       expr = EXPR_MANAGER->mkNullaryOperator(EXPR_MANAGER->booleanType(), kind::SEP_NIL); }
     // NOTE: Theory constants go here
+
+  | LPAREN_TOK TUPLE_CONST_TOK termList[args,expr] RPAREN_TOK
+    { std::vector<Type> types;
+      for(std::vector<Expr>::const_iterator i = args.begin(); i != args.end(); ++i) {
+        types.push_back((*i).getType());
+      }
+      DatatypeType t = EXPR_MANAGER->mkTupleType(types);
+      const Datatype& dt = t.getDatatype();
+      args.insert(args.begin(), dt[0].getConstructor());
+      expr = MK_EXPR(kind::APPLY_CONSTRUCTOR, args);
+    }
+  
+  | TUPLE_CONST_TOK
+    { std::vector<Type> types;
+      DatatypeType t = EXPR_MANAGER->mkTupleType(types);
+      const Datatype& dt = t.getDatatype();
+      args.insert(args.begin(), dt[0].getConstructor());
+      expr = MK_EXPR(kind::APPLY_CONSTRUCTOR, args);
+    }
   ;
 
 /**
@@ -2565,6 +2606,11 @@ indexedFunctionName[CVC4::Expr& op, CVC4::Kind& kind]
         op = Datatype::datatypeOf(expr)[Datatype::indexOf(expr)].getTester();
         kind = CVC4::kind::APPLY_TESTER;
       }
+    | TUPLE_SEL_TOK m=INTEGER_LITERAL {
+        kind = CVC4::kind::APPLY_SELECTOR;
+        //put m in op so that the caller (termNonVariable) can deal with this case
+        op = MK_CONST(Rational(AntlrInput::tokenToUnsigned($m)));
+      } 
     | badIndexedFunctionName
     )
     RPAREN_TOK
@@ -2843,6 +2889,8 @@ sortSymbol[CVC4::Type& t, CVC4::parser::DeclarationCheck check]
             PARSER_STATE->parseError("Illegal set type.");
           }
           t = EXPR_MANAGER->mkSetType( args[0] );
+        } else if(name == "Tuple") {
+          t = EXPR_MANAGER->mkTupleType(args); 
         } else if(check == CHECK_DECLARED ||
                   PARSER_STATE->isDeclared(name, SYM_SORT)) {
           t = PARSER_STATE->getSort(name, args);
@@ -3137,6 +3185,8 @@ INST_CLOSURE_TOK : 'inst-closure';
 EMPTYSET_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SETS) }? 'emptyset';
 UNIVSET_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SETS) }? 'univset';
 NILREF_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SEP) }? 'sep.nil';
+TUPLE_CONST_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_DATATYPES) }? 'mkTuple';
+TUPLE_SEL_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_DATATYPES) }? 'tupSel';
 // Other set theory operators are not
 // tokenized and handled directly when
 // processing a term
index 381a60fa872338da73ff2f5757a3433ccefb7e9f..e4f6569b877243b1b95e42ed05b5db45ec0f0358 100644 (file)
@@ -240,14 +240,22 @@ void Smt2::addTheory(Theory theory) {
     addOperator(kind::INSERT, "insert");
     addOperator(kind::CARD, "card");
     addOperator(kind::COMPLEMENT, "complement");
+    addOperator(kind::JOIN, "join");
+    addOperator(kind::PRODUCT, "product");
+    addOperator(kind::TRANSPOSE, "transpose");
+    addOperator(kind::TCLOSURE, "tclosure");
     break;
 
   case THEORY_DATATYPES:
+  {
+    const std::vector<Type> types;
+    defineType("Tuple", getExprManager()->mkTupleType(types));
     Parser::addOperator(kind::APPLY_CONSTRUCTOR);
     Parser::addOperator(kind::APPLY_TESTER);
     Parser::addOperator(kind::APPLY_SELECTOR);
     Parser::addOperator(kind::APPLY_SELECTOR_TOTAL);
     break;
+  }
 
   case THEORY_STRINGS:
     defineType("String", getExprManager()->stringType());
index c13c519ae77808e25af0af16dc6f33218fce0587..54fc107199e5e4c2721a86a63e01f1e4de0953ad 100644 (file)
@@ -252,11 +252,32 @@ void Smt2Printer::toStream(std::ostream& out,
     }
 
     case kind::DATATYPE_TYPE:
+    {
+      const Datatype& dt = (NodeManager::currentNM()->getDatatypeForIndex(
+          n.getConst<DatatypeIndexConstant>().getIndex()));
+      if (dt.isTuple())
+      {
+        unsigned int n = dt[0].getNumArgs();
+        if (n == 0)
+        {
+          out << "Tuple";
+        }
+        else
+        {
+          out << "(Tuple";
+          for (unsigned int i = 0; i < n; i++)
+          {
+            out << " " << dt[0][i].getRangeType();
+          }
+          out << ")";
+        }
+      }
+      else
       {
-        const Datatype & dt = (NodeManager::currentNM()->getDatatypeForIndex( n.getConst< DatatypeIndexConstant >().getIndex() ));
         out << maybeQuoteSymbol(dt.getName());
       }
       break;
+    }
 
     case kind::UNINTERPRETED_CONSTANT: {
       const UninterpretedConstant& uc = n.getConst<UninterpretedConstant>();
@@ -549,6 +570,11 @@ void Smt2Printer::toStream(std::ostream& out,
   case kind::INTERSECTION:
   case kind::SETMINUS:
   case kind::SUBSET:
+  case kind::CARD:
+  case kind::JOIN:
+  case kind::PRODUCT:
+  case kind::TRANSPOSE:
+  case kind::TCLOSURE:
     parametricTypeChildren = true;
     out << smtKindString(k) << " "; 
     break;
@@ -624,80 +650,103 @@ void Smt2Printer::toStream(std::ostream& out,
       return;
     }
     break;
-  case kind::APPLY_CONSTRUCTOR: typeChildren = true;
-  case kind::APPLY_TESTER:
-  case kind::APPLY_SELECTOR:
-  case kind::APPLY_SELECTOR_TOTAL:
-  case kind::PARAMETRIC_DATATYPE:
-    break;
 
-  //separation logic
-  case kind::SEP_EMP:
-  case kind::SEP_PTO:
-  case kind::SEP_STAR:
-  case kind::SEP_WAND:out << smtKindString(k) << " "; break;
+    case kind::APPLY_CONSTRUCTOR:
+    {
+      typeChildren = true;
+      const Datatype& dt = Datatype::datatypeOf(n.getOperator().toExpr());
+      if (dt.isTuple())
+      {
+        stillNeedToPrintParams = false;
+        out << "mkTuple" << ( dt[0].getNumArgs()==0 ? "" : " ");
+      }
+    }
+
+    case kind::APPLY_TESTER:
+    case kind::APPLY_SELECTOR:
+    case kind::APPLY_SELECTOR_TOTAL:
+    case kind::PARAMETRIC_DATATYPE: break;
 
-  case kind::SEP_NIL:out << "(as sep.nil " << n.getType() << ")";break;
+    // separation logic
+    case kind::SEP_EMP:
+    case kind::SEP_PTO:
+    case kind::SEP_STAR:
+    case kind::SEP_WAND: out << smtKindString(k) << " "; break;
 
-    // quantifiers
-  case kind::FORALL:
-  case kind::EXISTS:
-    if( k==kind::FORALL ){
-      out << "forall ";
-    }else{
-      out << "exists ";
-    }
-    for( unsigned i=0; i<2; i++) {
-      out << n[i] << " ";
-      if( i==0 && n.getNumChildren()==3 ){
-        out << "(! ";
+    case kind::SEP_NIL:
+      out << "(as sep.nil " << n.getType() << ")";
+      break;
+
+      // quantifiers
+    case kind::FORALL:
+    case kind::EXISTS:
+      if (k == kind::FORALL)
+      {
+        out << "forall ";
+      }
+      else
+      {
+        out << "exists ";
+      }
+      for (unsigned i = 0; i < 2; i++)
+      {
+        out << n[i] << " ";
+        if (i == 0 && n.getNumChildren() == 3)
+        {
+          out << "(! ";
+        }
+      }
+      if (n.getNumChildren() == 3)
+      {
+        out << n[2];
+        out << ")";
       }
-    }
-    if( n.getNumChildren()==3 ){
-      out << n[2];
       out << ")";
-    }
-    out << ")";
-    return;
-    break;
-  case kind::BOUND_VAR_LIST:
-    // the left parenthesis is already printed (before the switch)
-    for(TNode::iterator i = n.begin(), iend = n.end();
-        i != iend; ) {
-      out << '(';
-      toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1, types, 0);
-      out << ' ';
-      out << (*i).getType();
-      // The following code do stange things
-      // (*i).getType().toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
-      //                         false, language::output::LANG_SMTLIB_V2_5);
-      out << ')';
-      if(++i != iend) {
+      return;
+      break;
+    case kind::BOUND_VAR_LIST:
+      // the left parenthesis is already printed (before the switch)
+      for (TNode::iterator i = n.begin(), iend = n.end(); i != iend;)
+      {
+        out << '(';
+        toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1, types, 0);
         out << ' ';
+        out << (*i).getType();
+        // The following code do stange things
+        // (*i).getType().toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
+        //                         false, language::output::LANG_SMTLIB_V2_5);
+        out << ')';
+        if (++i != iend)
+        {
+          out << ' ';
+        }
       }
-    }
-    out << ')';
-    return;
-  case kind::INST_PATTERN:
-    break;
-  case kind::INST_PATTERN_LIST:
-    for(unsigned i=0; i<n.getNumChildren(); i++) {
-      if( n[i].getKind()==kind::INST_ATTRIBUTE ){
-        if( n[i][0].getAttribute(theory::FunDefAttribute()) ){
-          out << ":fun-def";
+      out << ')';
+      return;
+    case kind::INST_PATTERN: break;
+    case kind::INST_PATTERN_LIST:
+      for (unsigned i = 0; i < n.getNumChildren(); i++)
+      {
+        if (n[i].getKind() == kind::INST_ATTRIBUTE)
+        {
+          if (n[i][0].getAttribute(theory::FunDefAttribute()))
+          {
+            out << ":fun-def";
+          }
+        }
+        else
+        {
+          out << ":pattern " << n[i];
         }
-      }else{
-        out << ":pattern " << n[i];
       }
-    }
-    return;
-    break;
+      return;
+      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
-    // output that support for the kind needs to be added here.
-    out << n.getKind() << ' ';
+    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
+      // output that support for the kind needs to be added here.
+      out << n.getKind() << ' ';
   }
   if( n.getMetaKind() == kind::metakind::PARAMETERIZED &&
       stillNeedToPrintParams ) {
@@ -917,6 +966,12 @@ static string smtKindString(Kind k)
   case kind::SINGLETON: return "singleton";
   case kind::INSERT: return "insert";
   case kind::COMPLEMENT: return "complement";
+  case kind::CARD: return "card";
+  case kind::JOIN: return "join";
+  case kind::PRODUCT: return "product";
+  case kind::TRANSPOSE: return "transpose";
+  case kind::TCLOSURE:
+    return "tclosure";
 
     // fp theory
   case kind::FLOATINGPOINT_FP: return "fp";
@@ -1326,7 +1381,11 @@ void Smt2Printer::toStream(std::ostream& out,
     }
 */
   } else {
-    out << c << endl;
+    DatatypeDeclarationCommand* c1 = (DatatypeDeclarationCommand*)c;
+    const vector<DatatypeType>& datatypes = c1->getDatatypes();
+    if (!datatypes[0].isTuple()) {
+      out << c << endl;
+    }
   }
 }
 
@@ -1762,38 +1821,48 @@ static void toStream(std::ostream& out,
 {
   const vector<DatatypeType>& datatypes = c->getDatatypes();
   out << "(declare-";
-  Assert( !datatypes.empty() );
-  if( datatypes[0].getDatatype().isCodatatype() ){
+  Assert(!datatypes.empty());
+  if (datatypes[0].getDatatype().isCodatatype())
+  {
     out << "co";
   }
   out << "datatypes";
-  if(v == smt2_6_variant) {
+  if (v == smt2_6_variant)
+  {
     out << " (";
-    for(vector<DatatypeType>::const_iterator i = datatypes.begin(),
-          i_end = datatypes.end();
-        i != i_end; ++i) {
-      const Datatype & d = i->getDatatype();
+    for (vector<DatatypeType>::const_iterator i = datatypes.begin(),
+                                              i_end = datatypes.end();
+         i != i_end;
+         ++i)
+    {
+      const Datatype& d = i->getDatatype();
       out << "(" << maybeQuoteSymbol(d.getName());
       out << " " << d.getNumParameters() << ")";
     }
     out << ") (";
-    for(vector<DatatypeType>::const_iterator i = datatypes.begin(),
-          i_end = datatypes.end();
-        i != i_end; ++i) {
-      const Datatype & d = i->getDatatype();
+    for (vector<DatatypeType>::const_iterator i = datatypes.begin(),
+                                              i_end = datatypes.end();
+         i != i_end;
+         ++i)
+    {
+      const Datatype& d = i->getDatatype();
       out << "(";
-      toStream( out, d );
+      toStream(out, d);
       out << ")" << endl;
     }
     out << ")";
-  }else{
+  }
+  else
+  {
     out << " () (";
-    for(vector<DatatypeType>::const_iterator i = datatypes.begin(),
-          i_end = datatypes.end();
-        i != i_end; ++i) {
-      const Datatype & d = i->getDatatype();
+    for (vector<DatatypeType>::const_iterator i = datatypes.begin(),
+                                              i_end = datatypes.end();
+         i != i_end;
+         ++i)
+    {
+      const Datatype& d = i->getDatatype();
       out << "(" << maybeQuoteSymbol(d.getName()) << " ";
-      toStream( out, d );
+      toStream(out, d);
       out << ")" << endl;
     }
     out << ")";
index d346c0056c141fee4eb87c34d6f7cfa7a8fff0b4..a71c15869d14b3702845b1431aed61f884746a1f 100644 (file)
@@ -84,7 +84,9 @@ TESTS =       \
        jsat-2.6.smt2 \
        acyclicity-sr-ground096.smt2 \
        model-subterms-min.smt2 \
-       issue1433.smt2
+       issue1433.smt2 \
+        tuples-empty.smt2 \
+        tuples-multitype.smt2
 
 # rec5 -- no longer support subrange types
 FAILING_TESTS = \
diff --git a/test/regress/regress0/datatypes/tuples-empty.smt2 b/test/regress/regress0/datatypes/tuples-empty.smt2
new file mode 100644 (file)
index 0000000..ec7e36c
--- /dev/null
@@ -0,0 +1,14 @@
+; EXPECT: sat
+
+(set-logic ALL)
+(set-info :status sat)
+
+(declare-fun t () Tuple)
+(declare-fun t1 () (Tuple (Tuple Int Int) (Tuple Int String Int)))
+(declare-fun t2 () (Tuple (Tuple Bool Int) String))
+
+(assert (= t1 (mkTuple (mkTuple 12 99) (mkTuple 5 "xyz" 17))))
+(assert (= t2 (mkTuple (mkTuple true 14) "abc")))
+(assert (= t mkTuple))
+
+(check-sat)
diff --git a/test/regress/regress0/datatypes/tuples-multitype.smt2 b/test/regress/regress0/datatypes/tuples-multitype.smt2
new file mode 100644 (file)
index 0000000..8e412f2
--- /dev/null
@@ -0,0 +1,11 @@
+; EXPECT: sat
+(set-logic ALL)
+(set-info :status sat)
+
+(declare-fun t () (Tuple Int String))
+(declare-fun i () String)
+
+(assert (= t (mkTuple 0 "0")))
+(assert (= i ((_ tupSel 1) t)))
+
+(check-sat)
index 7f772a8e17eaa5cc4580d19037f26a8c9db671d4..c8fb739d01ae501ff545a212dc95c3146dd309d4 100644 (file)
@@ -113,7 +113,8 @@ TESTS =     \
   joinImg_1.cvc \
   joinImg_2_1.cvc \
   joinImg_2.cvc \
-  card_transpose.cvc
+  card_transpose.cvc \
+  relations-ops.smt2
 
 # unsolved : garbage_collect.cvc
 
diff --git a/test/regress/regress0/rels/relations-ops.smt2 b/test/regress/regress0/rels/relations-ops.smt2
new file mode 100644 (file)
index 0000000..abb7faf
--- /dev/null
@@ -0,0 +1,23 @@
+; EXPECT: sat
+(set-logic ALL)
+(set-info :status sat)
+
+(declare-fun r1 () (Set (Tuple String Int)))
+(declare-fun r2 () (Set (Tuple Int String)))
+(declare-fun r () (Set (Tuple String String)))
+(declare-fun s () (Set (Tuple String String)))
+(declare-fun t () (Set (Tuple String Int Int String)))
+(declare-fun lt1 () (Set (Tuple Int Int)))
+(declare-fun lt2 () (Set (Tuple Int Int)))
+(declare-fun i () Int)
+
+(assert (= r1 (insert (mkTuple "a" 1) (mkTuple "b" 2) (mkTuple "c" 3) (singleton (mkTuple "d" 4)))))
+(assert (= r2 (insert (mkTuple 1 "1") (mkTuple 2 "2") (mkTuple 3 "3") (singleton (mkTuple 17 "17")))))
+(assert (= r (join r1 r2)))
+(assert (= s (transpose r)))
+(assert (= t (product r1 r2)))
+(assert (= lt1 (insert (mkTuple 1 2) (mkTuple 2 3) (mkTuple 3 4) (singleton (mkTuple 4 5)))))
+(assert (= lt2 (tclosure lt1)))
+(assert (= i (card t)))
+
+(check-sat)