// likely it is also in original message? if so, very likely
// we found the right place
string word = slice.substr(caretPos, (caretPosOrig - caretPos + 1));
- int messagePosSt = message.find(word);
- int messagePosEn = messagePosSt + (caretPosOrig - caretPos);
+ unsigned messagePosSt = message.find(word);
+ unsigned messagePosEn = messagePosSt + (caretPosOrig - caretPos);
if( messagePosSt < string::npos &&
(messagePosSt == 0 || !isSimpleChar(message[messagePosSt-1]) ) &&
(messagePosEn+1 == message.size() || !isSimpleChar(message[messagePosEn+1]) ) ) {
}
string word = slice.substr(nearestWordSt, (nearestWordEn - nearestWordSt + 1));
Debug("friendlyparser") << "[friendlyparser] nearest word = " << word << std::endl;
- int messagePosSt = message.find(word);
- int messagePosEn = messagePosSt + (nearestWordEn - nearestWordSt + 1);
+ unsigned messagePosSt = message.find(word);
+ unsigned messagePosEn = messagePosSt + (nearestWordEn - nearestWordSt + 1);
if( messagePosSt < string::npos &&
(messagePosSt == 0 || !isSimpleChar(message[messagePosSt-1]) ) &&
(messagePosEn+1 == message.size() || !isSimpleChar(message[messagePosEn+1]) ) ) {
/********************* */\r
-/*! \file regexp_operation.cpp
-\r
- ** \verbatim
-\r
- ** Original author: Tianyi Liang
- \r
- ** Major contributors: none
- \r
- ** Minor contributors (to current version): none
- \r
- ** This file is part of the CVC4 project.
- \r
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- \r
- ** See the file COPYING in the top-level source directory for licensing
- \r
- ** information.\endverbatim
- \r
- **
- \r
+/*! \file regexp_operation.cpp\r
+ ** \verbatim\r
+ ** Original author: Tianyi Liang\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 project.\r
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
** \brief Symbolic Regular Expresion Operations\r
**\r
** Symbolic Regular Expresion Operations\r
d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );\r
d_true = NodeManager::currentNM()->mkConst( true );\r
d_false = NodeManager::currentNM()->mkConst( false );\r
- d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );\r
- d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );\r
- d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );\r
- std::vector< Node > nvec;\r
+ d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );\r
+ d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );\r
+ d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );\r
+ std::vector< Node > nvec;\r
d_emptyRegexp = NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec );\r
- d_sigma = NodeManager::currentNM()->mkNode( kind::REGEXP_SIGMA, nvec );\r
- d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );\r
- d_card = 256;\r
+ d_sigma = NodeManager::currentNM()->mkNode( kind::REGEXP_SIGMA, nvec );\r
+ d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );\r
+ d_card = 256;\r
}\r
\r
int RegExpOpr::gcd ( int a, int b ) {\r
}\r
\r
bool RegExpOpr::checkConstRegExp( Node r ) {\r
- Trace("strings-regexp-cstre") << "RegExp-CheckConstRegExp starts with " << mkString( r ) << std::endl;\r
- bool ret = true;\r
- if( d_cstre_cache.find( r ) != d_cstre_cache.end() ) {\r
- ret = d_cstre_cache[r];\r
- } else {\r
- if(r.getKind() == kind::STRING_TO_REGEXP) {\r
- Node tmp = Rewriter::rewrite( r[0] );\r
- ret = tmp.isConst();\r
- } else {\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(!checkConstRegExp(r[i])) {\r
- ret = false; break;\r
- }\r
- }\r
- }\r
- d_cstre_cache[r] = ret;\r
- }\r
- return ret;\r
+ Trace("strings-regexp-cstre") << "RegExp-CheckConstRegExp starts with " << mkString( r ) << std::endl;\r
+ bool ret = true;\r
+ if( d_cstre_cache.find( r ) != d_cstre_cache.end() ) {\r
+ ret = d_cstre_cache[r];\r
+ } else {\r
+ if(r.getKind() == kind::STRING_TO_REGEXP) {\r
+ Node tmp = Rewriter::rewrite( r[0] );\r
+ ret = tmp.isConst();\r
+ } else {\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(!checkConstRegExp(r[i])) {\r
+ ret = false; break;\r
+ }\r
+ }\r
+ }\r
+ d_cstre_cache[r] = ret;\r
+ }\r
+ return ret;\r
}\r
\r
// 0-unknown, 1-yes, 2-no\r
int RegExpOpr::delta( Node r, Node &exp ) {\r
- Trace("regexp-delta") << "RegExp-Delta starts with " << mkString( r ) << std::endl;\r
- int ret = 0;\r
- if( d_delta_cache.find( r ) != d_delta_cache.end() ) {\r
- ret = d_delta_cache[r].first;\r
- exp = d_delta_cache[r].second;\r
- } else {\r
- int k = r.getKind();\r
- switch( k ) {\r
- case kind::REGEXP_EMPTY: {\r
- ret = 2;\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- ret = 2;\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- Node tmp = Rewriter::rewrite(r[0]);\r
- if(tmp.isConst()) {\r
- if(tmp == d_emptyString) {\r
- ret = 1;\r
- } else {\r
- ret = 2;\r
- }\r
- } else {\r
- ret = 0;\r
- if(tmp.getKind() == kind::STRING_CONCAT) {\r
- for(unsigned i=0; i<tmp.getNumChildren(); i++) {\r
- if(tmp[i].isConst()) {\r
- ret = 2; break;\r
- }\r
- }\r
+ Trace("regexp-delta") << "RegExp-Delta starts with " << mkString( r ) << std::endl;\r
+ int ret = 0;\r
+ if( d_delta_cache.find( r ) != d_delta_cache.end() ) {\r
+ ret = d_delta_cache[r].first;\r
+ exp = d_delta_cache[r].second;\r
+ } else {\r
+ int k = r.getKind();\r
+ switch( k ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ ret = 2;\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ ret = 2;\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ Node tmp = Rewriter::rewrite(r[0]);\r
+ if(tmp.isConst()) {\r
+ if(tmp == d_emptyString) {\r
+ ret = 1;\r
+ } else {\r
+ ret = 2;\r
+ }\r
+ } else {\r
+ ret = 0;\r
+ if(tmp.getKind() == kind::STRING_CONCAT) {\r
+ for(unsigned i=0; i<tmp.getNumChildren(); i++) {\r
+ if(tmp[i].isConst()) {\r
+ ret = 2; break;\r
+ }\r
+ }\r
\r
- }\r
- if(ret == 0) {\r
- exp = r[0].eqNode(d_emptyString);\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- bool flag = false;\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node exp2;\r
- int tmp = delta( r[i], exp2 );\r
- if(tmp == 2) {\r
- ret = 2;\r
- break;\r
- } else if(tmp == 0) {\r
- vec_nodes.push_back( exp2 );\r
- flag = true;\r
- }\r
- }\r
- if(ret != 2) {\r
- if(!flag) {\r
- ret = 1;\r
- } else {\r
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- bool flag = false;\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node exp2;\r
- int tmp = delta( r[i], exp2 );\r
- if(tmp == 1) {\r
- ret = 1;\r
- break;\r
- } else if(tmp == 0) {\r
- vec_nodes.push_back( exp2 );\r
- flag = true;\r
- }\r
- }\r
- if(ret != 1) {\r
- if(!flag) {\r
- ret = 2;\r
- } else {\r
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::OR, vec_nodes);\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- bool flag = false;\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node exp2;\r
- int tmp = delta( r[i], exp2 );\r
- if(tmp == 2) {\r
- ret = 2;\r
- break;\r
- } else if(tmp == 0) {\r
- vec_nodes.push_back( exp2 );\r
- flag = true;\r
- }\r
- }\r
- if(ret != 2) {\r
- if(!flag) {\r
- ret = 1;\r
- } else {\r
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- ret = 1;\r
- break;\r
- }\r
- case kind::REGEXP_PLUS: {\r
- ret = delta( r[0], exp );\r
- break;\r
- }\r
- case kind::REGEXP_OPT: {\r
- ret = 1;\r
- break;\r
- }\r
- case kind::REGEXP_RANGE: {\r
- ret = 2;\r
- break;\r
- }\r
- default: {\r
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;\r
- Assert( false );\r
- //return Node::null();\r
- }\r
- }\r
- if(!exp.isNull()) {\r
- exp = Rewriter::rewrite(exp);\r
- }\r
- std::pair< int, Node > p(ret, exp);\r
- d_delta_cache[r] = p;\r
- }\r
- Trace("regexp-delta") << "RegExp-Delta returns : " << ret << std::endl;\r
- return ret;\r
+ }\r
+ if(ret == 0) {\r
+ exp = r[0].eqNode(d_emptyString);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ bool flag = false;\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node exp2;\r
+ int tmp = delta( r[i], exp2 );\r
+ if(tmp == 2) {\r
+ ret = 2;\r
+ break;\r
+ } else if(tmp == 0) {\r
+ vec_nodes.push_back( exp2 );\r
+ flag = true;\r
+ }\r
+ }\r
+ if(ret != 2) {\r
+ if(!flag) {\r
+ ret = 1;\r
+ } else {\r
+ exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ bool flag = false;\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node exp2;\r
+ int tmp = delta( r[i], exp2 );\r
+ if(tmp == 1) {\r
+ ret = 1;\r
+ break;\r
+ } else if(tmp == 0) {\r
+ vec_nodes.push_back( exp2 );\r
+ flag = true;\r
+ }\r
+ }\r
+ if(ret != 1) {\r
+ if(!flag) {\r
+ ret = 2;\r
+ } else {\r
+ exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::OR, vec_nodes);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ bool flag = false;\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node exp2;\r
+ int tmp = delta( r[i], exp2 );\r
+ if(tmp == 2) {\r
+ ret = 2;\r
+ break;\r
+ } else if(tmp == 0) {\r
+ vec_nodes.push_back( exp2 );\r
+ flag = true;\r
+ }\r
+ }\r
+ if(ret != 2) {\r
+ if(!flag) {\r
+ ret = 1;\r
+ } else {\r
+ exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ ret = 1;\r
+ break;\r
+ }\r
+ case kind::REGEXP_PLUS: {\r
+ ret = delta( r[0], exp );\r
+ break;\r
+ }\r
+ case kind::REGEXP_OPT: {\r
+ ret = 1;\r
+ break;\r
+ }\r
+ case kind::REGEXP_RANGE: {\r
+ ret = 2;\r
+ break;\r
+ }\r
+ default: {\r
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;\r
+ Assert( false );\r
+ //return Node::null();\r
+ }\r
+ }\r
+ if(!exp.isNull()) {\r
+ exp = Rewriter::rewrite(exp);\r
+ }\r
+ std::pair< int, Node > p(ret, exp);\r
+ d_delta_cache[r] = p;\r
+ }\r
+ Trace("regexp-delta") << "RegExp-Delta returns : " << ret << std::endl;\r
+ return ret;\r
}\r
\r
// 0-unknown, 1-yes, 2-no\r
int RegExpOpr::derivativeS( Node r, CVC4::String c, Node &retNode ) {\r
- Assert( c.size() < 2 );\r
- Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;\r
- \r
- int ret = 1;\r
- retNode = d_emptyRegexp;\r
- \r
- PairNodeStr dv = std::make_pair( r, c );\r
- if( d_deriv_cache.find( dv ) != d_deriv_cache.end() ) {\r
- retNode = d_deriv_cache[dv].first;\r
- ret = d_deriv_cache[dv].second;\r
- } else if( c.isEmptyString() ) {\r
- Node expNode;\r
- ret = delta( r, expNode );\r
- if(ret == 0) {\r
- retNode = NodeManager::currentNM()->mkNode(kind::ITE, expNode, r, d_emptyRegexp);\r
- } else if(ret == 1) {\r
- retNode = r;\r
- }\r
- std::pair< Node, int > p(retNode, ret);\r
- d_deriv_cache[dv] = p;\r
- } else {\r
- switch( r.getKind() ) {\r
- case kind::REGEXP_EMPTY: {\r
- ret = 2;\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- retNode = d_emptySingleton;\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- Node tmp = Rewriter::rewrite(r[0]);\r
- if(tmp.isConst()) {\r
- if(tmp == d_emptyString) {\r
- ret = 2;\r
- } else {\r
- if(tmp.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {\r
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, \r
- tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );\r
- } else {\r
- ret = 2;\r
- }\r
- }\r
- } else {\r
- ret = 0;\r
- Node rest;\r
- if(tmp.getKind() == kind::STRING_CONCAT) {\r
- Node t2 = tmp[0];\r
- if(t2.isConst()) {\r
- if(t2.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {\r
- Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, \r
- tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );\r
- std::vector< Node > vec_nodes;\r
- vec_nodes.push_back(n);\r
- for(unsigned i=1; i<tmp.getNumChildren(); i++) {\r
- vec_nodes.push_back(tmp[i]);\r
- }\r
- retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);\r
- ret = 1;\r
- } else {\r
- ret = 2;\r
- }\r
- } else {\r
- tmp = tmp[0];\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=1; i<tmp.getNumChildren(); i++) {\r
- vec_nodes.push_back(tmp[i]);\r
- }\r
- rest = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);\r
- }\r
- }\r
- if(ret == 0) {\r
- Node sk = NodeManager::currentNM()->mkSkolem( "rsp", NodeManager::currentNM()->stringType(), "Split RegExp" );\r
- retNode = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, sk);\r
- if(!rest.isNull()) {\r
- retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, retNode, rest));\r
- }\r
- Node exp = tmp.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,\r
- NodeManager::currentNM()->mkConst(c), sk));\r
- retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, exp, retNode, d_emptyRegexp));\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- std::vector< Node > vec_nodes;\r
- std::vector< Node > delta_nodes;\r
- Node dnode = d_true;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node dc;\r
- Node exp2;\r
- int rt = derivativeS(r[i], c, dc);\r
- if(rt != 2) {\r
- if(rt == 0) {\r
- ret = 0;\r
- }\r
- std::vector< Node > vec_nodes2;\r
- if(dc != d_emptySingleton) {\r
- vec_nodes2.push_back( dc );\r
- }\r
- for(unsigned j=i+1; j<r.getNumChildren(); ++j) {\r
- if(r[j] != d_emptySingleton) {\r
- vec_nodes2.push_back( r[j] );\r
- }\r
- }\r
- Node tmp = vec_nodes2.size()==0 ? d_emptySingleton : \r
- vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );\r
- if(dnode != d_true) {\r
- tmp = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, dnode, tmp, d_emptyRegexp));\r
- ret = 0;\r
- }\r
- if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {\r
- vec_nodes.push_back( tmp );\r
- }\r
- }\r
- Node exp3;\r
- int rt2 = delta( r[i], exp3 );\r
- if( rt2 == 0 ) {\r
- dnode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, dnode, exp3));\r
- } else if( rt2 == 2 ) {\r
- break;\r
- }\r
- }\r
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
- if(retNode == d_emptyRegexp) {\r
- ret = 2;\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node dc;\r
- int rt = derivativeS(r[i], c, dc);\r
- if(rt == 0) {\r
- ret = 0;\r
- }\r
- if(rt != 2) {\r
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
- vec_nodes.push_back( dc );\r
- }\r
- }\r
- Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;\r
- }\r
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
- if(retNode == d_emptyRegexp) {\r
- ret = 2;\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- bool flag = true;\r
- bool flag_sg = false;\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node dc;\r
- int rt = derivativeS(r[i], c, dc);\r
- if(rt == 0) {\r
- ret = 0;\r
- } else if(rt == 2) {\r
- flag = false;\r
- break;\r
- }\r
- if(dc == d_sigma_star) {\r
- flag_sg = true;\r
- } else {\r
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
- vec_nodes.push_back( dc );\r
- }\r
- }\r
- }\r
- if(flag) {\r
- if(vec_nodes.size() == 0 && flag_sg) {\r
- retNode = d_sigma_star;\r
- } else {\r
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );\r
- if(retNode == d_emptyRegexp) {\r
- ret = 2;\r
- }\r
- }\r
- } else {\r
- retNode = d_emptyRegexp;\r
- ret = 2;\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- Node dc;\r
- ret = derivativeS(r[0], c, dc);\r
- retNode = dc==d_emptyRegexp ? dc : (dc==d_emptySingleton ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r ));\r
- break;\r
- }\r
- default: {\r
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;\r
- Assert( false, "Unsupported Term" );\r
- }\r
- }\r
- if(retNode != d_emptyRegexp) {\r
- retNode = Rewriter::rewrite( retNode );\r
- }\r
- std::pair< Node, int > p(retNode, ret);\r
- d_deriv_cache[dv] = p;\r
- }\r
+ Assert( c.size() < 2 );\r
+ Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;\r
+\r
+ int ret = 1;\r
+ retNode = d_emptyRegexp;\r
\r
- Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;\r
- return ret;\r
+ PairNodeStr dv = std::make_pair( r, c );\r
+ if( d_deriv_cache.find( dv ) != d_deriv_cache.end() ) {\r
+ retNode = d_deriv_cache[dv].first;\r
+ ret = d_deriv_cache[dv].second;\r
+ } else if( c.isEmptyString() ) {\r
+ Node expNode;\r
+ ret = delta( r, expNode );\r
+ if(ret == 0) {\r
+ retNode = NodeManager::currentNM()->mkNode(kind::ITE, expNode, r, d_emptyRegexp);\r
+ } else if(ret == 1) {\r
+ retNode = r;\r
+ }\r
+ std::pair< Node, int > p(retNode, ret);\r
+ d_deriv_cache[dv] = p;\r
+ } else {\r
+ switch( r.getKind() ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ ret = 2;\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ retNode = d_emptySingleton;\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ Node tmp = Rewriter::rewrite(r[0]);\r
+ if(tmp.isConst()) {\r
+ if(tmp == d_emptyString) {\r
+ ret = 2;\r
+ } else {\r
+ if(tmp.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {\r
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,\r
+ tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );\r
+ } else {\r
+ ret = 2;\r
+ }\r
+ }\r
+ } else {\r
+ ret = 0;\r
+ Node rest;\r
+ if(tmp.getKind() == kind::STRING_CONCAT) {\r
+ Node t2 = tmp[0];\r
+ if(t2.isConst()) {\r
+ if(t2.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {\r
+ Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,\r
+ tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );\r
+ std::vector< Node > vec_nodes;\r
+ vec_nodes.push_back(n);\r
+ for(unsigned i=1; i<tmp.getNumChildren(); i++) {\r
+ vec_nodes.push_back(tmp[i]);\r
+ }\r
+ retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);\r
+ ret = 1;\r
+ } else {\r
+ ret = 2;\r
+ }\r
+ } else {\r
+ tmp = tmp[0];\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=1; i<tmp.getNumChildren(); i++) {\r
+ vec_nodes.push_back(tmp[i]);\r
+ }\r
+ rest = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);\r
+ }\r
+ }\r
+ if(ret == 0) {\r
+ Node sk = NodeManager::currentNM()->mkSkolem( "rsp", NodeManager::currentNM()->stringType(), "Split RegExp" );\r
+ retNode = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, sk);\r
+ if(!rest.isNull()) {\r
+ retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, retNode, rest));\r
+ }\r
+ Node exp = tmp.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,\r
+ NodeManager::currentNM()->mkConst(c), sk));\r
+ retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, exp, retNode, d_emptyRegexp));\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ std::vector< Node > vec_nodes;\r
+ std::vector< Node > delta_nodes;\r
+ Node dnode = d_true;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node dc;\r
+ Node exp2;\r
+ int rt = derivativeS(r[i], c, dc);\r
+ if(rt != 2) {\r
+ if(rt == 0) {\r
+ ret = 0;\r
+ }\r
+ std::vector< Node > vec_nodes2;\r
+ if(dc != d_emptySingleton) {\r
+ vec_nodes2.push_back( dc );\r
+ }\r
+ for(unsigned j=i+1; j<r.getNumChildren(); ++j) {\r
+ if(r[j] != d_emptySingleton) {\r
+ vec_nodes2.push_back( r[j] );\r
+ }\r
+ }\r
+ Node tmp = vec_nodes2.size()==0 ? d_emptySingleton :\r
+ vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );\r
+ if(dnode != d_true) {\r
+ tmp = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, dnode, tmp, d_emptyRegexp));\r
+ ret = 0;\r
+ }\r
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {\r
+ vec_nodes.push_back( tmp );\r
+ }\r
+ }\r
+ Node exp3;\r
+ int rt2 = delta( r[i], exp3 );\r
+ if( rt2 == 0 ) {\r
+ dnode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, dnode, exp3));\r
+ } else if( rt2 == 2 ) {\r
+ break;\r
+ }\r
+ }\r
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
+ if(retNode == d_emptyRegexp) {\r
+ ret = 2;\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node dc;\r
+ int rt = derivativeS(r[i], c, dc);\r
+ if(rt == 0) {\r
+ ret = 0;\r
+ }\r
+ if(rt != 2) {\r
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
+ vec_nodes.push_back( dc );\r
+ }\r
+ }\r
+ Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;\r
+ }\r
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
+ if(retNode == d_emptyRegexp) {\r
+ ret = 2;\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ bool flag = true;\r
+ bool flag_sg = false;\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node dc;\r
+ int rt = derivativeS(r[i], c, dc);\r
+ if(rt == 0) {\r
+ ret = 0;\r
+ } else if(rt == 2) {\r
+ flag = false;\r
+ break;\r
+ }\r
+ if(dc == d_sigma_star) {\r
+ flag_sg = true;\r
+ } else {\r
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
+ vec_nodes.push_back( dc );\r
+ }\r
+ }\r
+ }\r
+ if(flag) {\r
+ if(vec_nodes.size() == 0 && flag_sg) {\r
+ retNode = d_sigma_star;\r
+ } else {\r
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );\r
+ if(retNode == d_emptyRegexp) {\r
+ ret = 2;\r
+ }\r
+ }\r
+ } else {\r
+ retNode = d_emptyRegexp;\r
+ ret = 2;\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ Node dc;\r
+ ret = derivativeS(r[0], c, dc);\r
+ retNode = dc==d_emptyRegexp ? dc : (dc==d_emptySingleton ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r ));\r
+ break;\r
+ }\r
+ default: {\r
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;\r
+ Assert( false, "Unsupported Term" );\r
+ }\r
+ }\r
+ if(retNode != d_emptyRegexp) {\r
+ retNode = Rewriter::rewrite( retNode );\r
+ }\r
+ std::pair< Node, int > p(retNode, ret);\r
+ d_deriv_cache[dv] = p;\r
+ }\r
+\r
+ Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;\r
+ return ret;\r
}\r
\r
Node RegExpOpr::derivativeSingle( Node r, CVC4::String c ) {\r
- Assert( c.size() < 2 );\r
- Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;\r
- Node retNode = d_emptyRegexp;\r
- PairNodeStr dv = std::make_pair( r, c );\r
- if( d_dv_cache.find( dv ) != d_dv_cache.end() ) {\r
- retNode = d_dv_cache[dv];\r
- } else if( c.isEmptyString() ){\r
- Node exp;\r
- int tmp = delta( r, exp );\r
- if(tmp == 0) {\r
- // TODO variable\r
- retNode = d_emptyRegexp;\r
- } else if(tmp == 1) {\r
- retNode = r;\r
- } else {\r
- retNode = d_emptyRegexp;\r
- }\r
- } else {\r
- int k = r.getKind();\r
- switch( k ) {\r
- case kind::REGEXP_EMPTY: {\r
- retNode = d_emptyRegexp;\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- if(r[0].isConst()) {\r
- if(r[0] == d_emptyString) {\r
- retNode = d_emptyRegexp;\r
- } else {\r
- if(r[0].getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {\r
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, \r
- r[0].getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( r[0].getConst< CVC4::String >().substr(1) ) );\r
- } else {\r
- retNode = d_emptyRegexp;\r
- }\r
- }\r
- } else {\r
- // TODO variable\r
- retNode = d_emptyRegexp;\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- Node rees = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node dc = derivativeSingle(r[i], c);\r
- if(dc != d_emptyRegexp) {\r
- std::vector< Node > vec_nodes2;\r
- if(dc != rees) {\r
- vec_nodes2.push_back( dc );\r
- }\r
- for(unsigned j=i+1; j<r.getNumChildren(); ++j) {\r
- if(r[j] != rees) {\r
- vec_nodes2.push_back( r[j] );\r
- }\r
- }\r
- Node tmp = vec_nodes2.size()==0 ? rees : \r
- vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );\r
- if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {\r
- vec_nodes.push_back( tmp );\r
- }\r
- }\r
- Node exp;\r
- if( delta( r[i], exp ) != 1 ) {\r
- break;\r
- }\r
- }\r
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node dc = derivativeSingle(r[i], c);\r
- if(dc != d_emptyRegexp) {\r
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
- vec_nodes.push_back( dc );\r
- }\r
- }\r
- Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;\r
- }\r
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- bool flag = true;\r
- bool flag_sg = false;\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- Node dc = derivativeSingle(r[i], c);\r
- if(dc != d_emptyRegexp) {\r
- if(dc == d_sigma_star) {\r
- flag_sg = true;\r
- } else {\r
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
- vec_nodes.push_back( dc );\r
- }\r
- }\r
- } else {\r
- flag = false;\r
- break;\r
- }\r
- }\r
- if(flag) {\r
- if(vec_nodes.size() == 0 && flag_sg) {\r
- retNode = d_sigma_star;\r
- } else {\r
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );\r
- }\r
- } else {\r
- retNode = d_emptyRegexp;\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- Node dc = derivativeSingle(r[0], c);\r
- if(dc != d_emptyRegexp) {\r
- retNode = dc==NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ) ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r );\r
- } else {\r
- retNode = d_emptyRegexp;\r
- }\r
- break;\r
- }\r
- default: {\r
- //TODO: special sym: sigma, none, all\r
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;\r
- Assert( false, "Unsupported Term" );\r
- //return Node::null();\r
- }\r
- }\r
- if(retNode != d_emptyRegexp) {\r
- retNode = Rewriter::rewrite( retNode );\r
- }\r
- d_dv_cache[dv] = retNode;\r
- }\r
- Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;\r
- return retNode;\r
+ Assert( c.size() < 2 );\r
+ Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;\r
+ Node retNode = d_emptyRegexp;\r
+ PairNodeStr dv = std::make_pair( r, c );\r
+ if( d_dv_cache.find( dv ) != d_dv_cache.end() ) {\r
+ retNode = d_dv_cache[dv];\r
+ } else if( c.isEmptyString() ){\r
+ Node exp;\r
+ int tmp = delta( r, exp );\r
+ if(tmp == 0) {\r
+ // TODO variable\r
+ retNode = d_emptyRegexp;\r
+ } else if(tmp == 1) {\r
+ retNode = r;\r
+ } else {\r
+ retNode = d_emptyRegexp;\r
+ }\r
+ } else {\r
+ int k = r.getKind();\r
+ switch( k ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ retNode = d_emptyRegexp;\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ if(r[0].isConst()) {\r
+ if(r[0] == d_emptyString) {\r
+ retNode = d_emptyRegexp;\r
+ } else {\r
+ if(r[0].getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {\r
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,\r
+ r[0].getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( r[0].getConst< CVC4::String >().substr(1) ) );\r
+ } else {\r
+ retNode = d_emptyRegexp;\r
+ }\r
+ }\r
+ } else {\r
+ // TODO variable\r
+ retNode = d_emptyRegexp;\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ Node rees = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node dc = derivativeSingle(r[i], c);\r
+ if(dc != d_emptyRegexp) {\r
+ std::vector< Node > vec_nodes2;\r
+ if(dc != rees) {\r
+ vec_nodes2.push_back( dc );\r
+ }\r
+ for(unsigned j=i+1; j<r.getNumChildren(); ++j) {\r
+ if(r[j] != rees) {\r
+ vec_nodes2.push_back( r[j] );\r
+ }\r
+ }\r
+ Node tmp = vec_nodes2.size()==0 ? rees :\r
+ vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );\r
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {\r
+ vec_nodes.push_back( tmp );\r
+ }\r
+ }\r
+ Node exp;\r
+ if( delta( r[i], exp ) != 1 ) {\r
+ break;\r
+ }\r
+ }\r
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node dc = derivativeSingle(r[i], c);\r
+ if(dc != d_emptyRegexp) {\r
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
+ vec_nodes.push_back( dc );\r
+ }\r
+ }\r
+ Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;\r
+ }\r
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ bool flag = true;\r
+ bool flag_sg = false;\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ Node dc = derivativeSingle(r[i], c);\r
+ if(dc != d_emptyRegexp) {\r
+ if(dc == d_sigma_star) {\r
+ flag_sg = true;\r
+ } else {\r
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {\r
+ vec_nodes.push_back( dc );\r
+ }\r
+ }\r
+ } else {\r
+ flag = false;\r
+ break;\r
+ }\r
+ }\r
+ if(flag) {\r
+ if(vec_nodes.size() == 0 && flag_sg) {\r
+ retNode = d_sigma_star;\r
+ } else {\r
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :\r
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );\r
+ }\r
+ } else {\r
+ retNode = d_emptyRegexp;\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ Node dc = derivativeSingle(r[0], c);\r
+ if(dc != d_emptyRegexp) {\r
+ retNode = dc==NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ) ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r );\r
+ } else {\r
+ retNode = d_emptyRegexp;\r
+ }\r
+ break;\r
+ }\r
+ default: {\r
+ //TODO: special sym: sigma, none, all\r
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;\r
+ Assert( false, "Unsupported Term" );\r
+ //return Node::null();\r
+ }\r
+ }\r
+ if(retNode != d_emptyRegexp) {\r
+ retNode = Rewriter::rewrite( retNode );\r
+ }\r
+ d_dv_cache[dv] = retNode;\r
+ }\r
+ Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;\r
+ return retNode;\r
}\r
\r
//TODO:\r
bool RegExpOpr::guessLength( Node r, int &co ) {\r
- int k = r.getKind();\r
- switch( k ) {\r
- case kind::STRING_TO_REGEXP:\r
- {\r
- if(r[0].isConst()) {\r
- co += r[0].getConst< CVC4::String >().size();\r
- return true;\r
- } else {\r
- return false;\r
- }\r
- }\r
- break;\r
- case kind::REGEXP_CONCAT:\r
- {\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(!guessLength( r[i], co)) {\r
- return false;\r
- }\r
- }\r
- return true;\r
- }\r
- break;\r
- case kind::REGEXP_UNION:\r
- {\r
- int g_co;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- int cop = 0;\r
- if(!guessLength( r[i], cop)) {\r
- return false;\r
- }\r
- if(i == 0) {\r
- g_co = cop;\r
- } else {\r
- g_co = gcd(g_co, cop);\r
- }\r
- }\r
- return true;\r
- }\r
- break;\r
- case kind::REGEXP_INTER:\r
- {\r
- int g_co;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- int cop = 0;\r
- if(!guessLength( r[i], cop)) {\r
- return false;\r
- }\r
- if(i == 0) {\r
- g_co = cop;\r
- } else {\r
- g_co = gcd(g_co, cop);\r
- }\r
- }\r
- return true;\r
- }\r
- break;\r
- case kind::REGEXP_STAR:\r
- {\r
- co = 0;\r
- return true;\r
- }\r
- break;\r
- default:\r
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in membership of RegExp." << std::endl;\r
- return false;\r
- }\r
+ int k = r.getKind();\r
+ switch( k ) {\r
+ case kind::STRING_TO_REGEXP:\r
+ {\r
+ if(r[0].isConst()) {\r
+ co += r[0].getConst< CVC4::String >().size();\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+ break;\r
+ case kind::REGEXP_CONCAT:\r
+ {\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(!guessLength( r[i], co)) {\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ break;\r
+ case kind::REGEXP_UNION:\r
+ {\r
+ int g_co;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ int cop = 0;\r
+ if(!guessLength( r[i], cop)) {\r
+ return false;\r
+ }\r
+ if(i == 0) {\r
+ g_co = cop;\r
+ } else {\r
+ g_co = gcd(g_co, cop);\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ break;\r
+ case kind::REGEXP_INTER:\r
+ {\r
+ int g_co;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ int cop = 0;\r
+ if(!guessLength( r[i], cop)) {\r
+ return false;\r
+ }\r
+ if(i == 0) {\r
+ g_co = cop;\r
+ } else {\r
+ g_co = gcd(g_co, cop);\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ break;\r
+ case kind::REGEXP_STAR:\r
+ {\r
+ co = 0;\r
+ return true;\r
+ }\r
+ break;\r
+ default:\r
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in membership of RegExp." << std::endl;\r
+ return false;\r
+ }\r
}\r
\r
void RegExpOpr::firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) {\r
- std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_fset_cache.find(r);\r
- if(itr != d_fset_cache.end()) {\r
- pcset.insert((itr->second).first.begin(), (itr->second).first.end());\r
- pvset.insert((itr->second).second.begin(), (itr->second).second.end());\r
- } else {\r
- std::set<unsigned> cset;\r
- SetNodes vset;\r
- int k = r.getKind();\r
- switch( k ) {\r
- case kind::REGEXP_EMPTY: {\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- for(unsigned i=0; i<d_card; i++) {\r
- cset.insert(i);\r
- }\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- Node st = Rewriter::rewrite(r[0]);\r
- if(st.isConst()) {\r
- CVC4::String s = st.getConst< CVC4::String >();\r
- if(s.size() != 0) {\r
- cset.insert(s[0]);\r
- }\r
- } else if(st.getKind() == kind::VARIABLE) {\r
- vset.insert( st );\r
- } else {\r
- if(st[0].isConst()) {\r
- CVC4::String s = st[0].getConst< CVC4::String >();\r
- cset.insert(s[0]);\r
- } else {\r
- vset.insert( st[0] );\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- for(unsigned i=0; i<r.getNumChildren(); i++) {\r
- firstChars(r[i], cset, vset);\r
- Node n = r[i];\r
- Node exp;\r
- int r = delta( n, exp );\r
- if(r != 1) {\r
- break;\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- for(unsigned i=0; i<r.getNumChildren(); i++) {\r
- firstChars(r[i], cset, vset);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- //TODO: Overapproximation for now\r
- for(unsigned i=0; i<r.getNumChildren(); i++) {\r
- firstChars(r[i], cset, vset);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- firstChars(r[0], cset, vset);\r
- break;\r
- }\r
- default: {\r
- Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;\r
- Assert( false, "Unsupported Term" );\r
- }\r
- }\r
- pcset.insert(cset.begin(), cset.end());\r
- pvset.insert(vset.begin(), vset.end());\r
- std::pair< std::set<unsigned>, SetNodes > p(cset, vset);\r
- d_fset_cache[r] = p;\r
+ std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_fset_cache.find(r);\r
+ if(itr != d_fset_cache.end()) {\r
+ pcset.insert((itr->second).first.begin(), (itr->second).first.end());\r
+ pvset.insert((itr->second).second.begin(), (itr->second).second.end());\r
+ } else {\r
+ std::set<unsigned> cset;\r
+ SetNodes vset;\r
+ int k = r.getKind();\r
+ switch( k ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ for(unsigned i=0; i<d_card; i++) {\r
+ cset.insert(i);\r
+ }\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ Node st = Rewriter::rewrite(r[0]);\r
+ if(st.isConst()) {\r
+ CVC4::String s = st.getConst< CVC4::String >();\r
+ if(s.size() != 0) {\r
+ cset.insert(s[0]);\r
+ }\r
+ } else if(st.getKind() == kind::VARIABLE) {\r
+ vset.insert( st );\r
+ } else {\r
+ if(st[0].isConst()) {\r
+ CVC4::String s = st[0].getConst< CVC4::String >();\r
+ cset.insert(s[0]);\r
+ } else {\r
+ vset.insert( st[0] );\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ for(unsigned i=0; i<r.getNumChildren(); i++) {\r
+ firstChars(r[i], cset, vset);\r
+ Node n = r[i];\r
+ Node exp;\r
+ int r = delta( n, exp );\r
+ if(r != 1) {\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ for(unsigned i=0; i<r.getNumChildren(); i++) {\r
+ firstChars(r[i], cset, vset);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ //TODO: Overapproximation for now\r
+ for(unsigned i=0; i<r.getNumChildren(); i++) {\r
+ firstChars(r[i], cset, vset);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ firstChars(r[0], cset, vset);\r
+ break;\r
+ }\r
+ default: {\r
+ Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;\r
+ Assert( false, "Unsupported Term" );\r
+ }\r
+ }\r
+ pcset.insert(cset.begin(), cset.end());\r
+ pvset.insert(vset.begin(), vset.end());\r
+ std::pair< std::set<unsigned>, SetNodes > p(cset, vset);\r
+ d_fset_cache[r] = p;\r
\r
- Trace("regexp-fset") << "FSET( " << mkString(r) << " ) = { ";\r
- for(std::set<unsigned>::const_iterator itr = cset.begin();\r
- itr != cset.end(); itr++) {\r
- Trace("regexp-fset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";\r
- }\r
- Trace("regexp-fset") << " }" << std::endl;\r
- }\r
+ Trace("regexp-fset") << "FSET( " << mkString(r) << " ) = { ";\r
+ for(std::set<unsigned>::const_iterator itr = cset.begin();\r
+ itr != cset.end(); itr++) {\r
+ Trace("regexp-fset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";\r
+ }\r
+ Trace("regexp-fset") << " }" << std::endl;\r
+ }\r
}\r
\r
bool RegExpOpr::follow( Node r, CVC4::String c, std::vector< char > &vec_chars ) {\r
- int k = r.getKind();\r
- switch( k ) {\r
- case kind::STRING_TO_REGEXP:\r
- {\r
- if(r[0].isConst()) {\r
- if(r[0] != d_emptyString) {\r
- char t1 = r[0].getConst< CVC4::String >().getFirstChar();\r
- if(c.isEmptyString()) {\r
- vec_chars.push_back( t1 );\r
- return true;\r
- } else {\r
- char t2 = c.getFirstChar();\r
- if(t1 != t2) {\r
- return false;\r
- } else {\r
- if(c.size() >= 2) {\r
- vec_chars.push_back( c.substr(1,1).getFirstChar() );\r
- } else {\r
- vec_chars.push_back( '\0' );\r
- }\r
- return true;\r
- }\r
- }\r
- } else {\r
- return false;\r
- }\r
- } else {\r
- return false;\r
- }\r
- }\r
- break;\r
- case kind::REGEXP_CONCAT:\r
- {\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if( follow(r[i], c, vec_chars) ) {\r
- if(vec_chars[vec_chars.size() - 1] == '\0') {\r
- vec_chars.pop_back();\r
- c = d_emptyString.getConst< CVC4::String >();\r
- }\r
- } else {\r
- return false;\r
- }\r
- }\r
- vec_chars.push_back( '\0' );\r
- return true;\r
- }\r
- break;\r
- case kind::REGEXP_UNION:\r
- {\r
- bool flag = false;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if( follow(r[i], c, vec_chars) ) {\r
- flag=true;\r
- }\r
- }\r
- return flag;\r
- }\r
- break;\r
- case kind::REGEXP_INTER:\r
- {\r
- std::vector< char > vt2;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- std::vector< char > v_tmp;\r
- if( !follow(r[i], c, v_tmp) ) {\r
- return false;\r
- }\r
- std::vector< char > vt3(vt2);\r
- vt2.clear();\r
- std::set_intersection( vt3.begin(), vt3.end(), v_tmp.begin(), v_tmp.end(), vt2.begin() );\r
- if(vt2.size() == 0) {\r
- return false;\r
- }\r
- }\r
- vec_chars.insert( vec_chars.end(), vt2.begin(), vt2.end() );\r
- return true;\r
- }\r
- break;\r
- case kind::REGEXP_STAR:\r
- {\r
- if(follow(r[0], c, vec_chars)) {\r
- if(vec_chars[vec_chars.size() - 1] == '\0') {\r
- if(c.isEmptyString()) {\r
- return true;\r
- } else {\r
- vec_chars.pop_back();\r
- c = d_emptyString.getConst< CVC4::String >();\r
- return follow(r[0], c, vec_chars);\r
- }\r
- } else {\r
- return true;\r
- }\r
- } else {\r
- vec_chars.push_back( '\0' );\r
- return true;\r
- }\r
- }\r
- break;\r
- default: {\r
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;\r
- //AlwaysAssert( false );\r
- //return Node::null();\r
- return false;\r
- }\r
- }\r
+ int k = r.getKind();\r
+ switch( k ) {\r
+ case kind::STRING_TO_REGEXP:\r
+ {\r
+ if(r[0].isConst()) {\r
+ if(r[0] != d_emptyString) {\r
+ char t1 = r[0].getConst< CVC4::String >().getFirstChar();\r
+ if(c.isEmptyString()) {\r
+ vec_chars.push_back( t1 );\r
+ return true;\r
+ } else {\r
+ char t2 = c.getFirstChar();\r
+ if(t1 != t2) {\r
+ return false;\r
+ } else {\r
+ if(c.size() >= 2) {\r
+ vec_chars.push_back( c.substr(1,1).getFirstChar() );\r
+ } else {\r
+ vec_chars.push_back( '\0' );\r
+ }\r
+ return true;\r
+ }\r
+ }\r
+ } else {\r
+ return false;\r
+ }\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+ break;\r
+ case kind::REGEXP_CONCAT:\r
+ {\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if( follow(r[i], c, vec_chars) ) {\r
+ if(vec_chars[vec_chars.size() - 1] == '\0') {\r
+ vec_chars.pop_back();\r
+ c = d_emptyString.getConst< CVC4::String >();\r
+ }\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+ vec_chars.push_back( '\0' );\r
+ return true;\r
+ }\r
+ break;\r
+ case kind::REGEXP_UNION:\r
+ {\r
+ bool flag = false;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if( follow(r[i], c, vec_chars) ) {\r
+ flag=true;\r
+ }\r
+ }\r
+ return flag;\r
+ }\r
+ break;\r
+ case kind::REGEXP_INTER:\r
+ {\r
+ std::vector< char > vt2;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ std::vector< char > v_tmp;\r
+ if( !follow(r[i], c, v_tmp) ) {\r
+ return false;\r
+ }\r
+ std::vector< char > vt3(vt2);\r
+ vt2.clear();\r
+ std::set_intersection( vt3.begin(), vt3.end(), v_tmp.begin(), v_tmp.end(), vt2.begin() );\r
+ if(vt2.size() == 0) {\r
+ return false;\r
+ }\r
+ }\r
+ vec_chars.insert( vec_chars.end(), vt2.begin(), vt2.end() );\r
+ return true;\r
+ }\r
+ break;\r
+ case kind::REGEXP_STAR:\r
+ {\r
+ if(follow(r[0], c, vec_chars)) {\r
+ if(vec_chars[vec_chars.size() - 1] == '\0') {\r
+ if(c.isEmptyString()) {\r
+ return true;\r
+ } else {\r
+ vec_chars.pop_back();\r
+ c = d_emptyString.getConst< CVC4::String >();\r
+ return follow(r[0], c, vec_chars);\r
+ }\r
+ } else {\r
+ return true;\r
+ }\r
+ } else {\r
+ vec_chars.push_back( '\0' );\r
+ return true;\r
+ }\r
+ }\r
+ break;\r
+ default: {\r
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;\r
+ //AlwaysAssert( false );\r
+ //return Node::null();\r
+ return false;\r
+ }\r
+ }\r
}\r
\r
Node RegExpOpr::mkAllExceptOne( char exp_c ) {\r
- std::vector< Node > vec_nodes;\r
- for(char c=d_char_start; c<=d_char_end; ++c) {\r
- if(c != exp_c ) {\r
- Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) );\r
- vec_nodes.push_back( n );\r
- }\r
- }\r
- return NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes );\r
+ std::vector< Node > vec_nodes;\r
+ for(char c=d_char_start; c<=d_char_end; ++c) {\r
+ if(c != exp_c ) {\r
+ Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) );\r
+ vec_nodes.push_back( n );\r
+ }\r
+ }\r
+ return NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes );\r
}\r
\r
//simplify\r
void RegExpOpr::simplify(Node t, std::vector< Node > &new_nodes, bool polarity) {\r
- Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl; \r
- Assert(t.getKind() == kind::STRING_IN_REGEXP);\r
- Node str = Rewriter::rewrite(t[0]);\r
- Node re = Rewriter::rewrite(t[1]);\r
- if(polarity) {\r
- simplifyPRegExp( str, re, new_nodes );\r
- } else {\r
- simplifyNRegExp( str, re, new_nodes );\r
- }\r
- Trace("strings-regexp-simpl") << "RegExp-Simpl returns (" << new_nodes.size() << "):\n";\r
- for(unsigned i=0; i<new_nodes.size(); i++) {\r
- Trace("strings-regexp-simpl") << "\t" << new_nodes[i] << std::endl;\r
- }\r
+ Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl;\r
+ Assert(t.getKind() == kind::STRING_IN_REGEXP);\r
+ Node str = Rewriter::rewrite(t[0]);\r
+ Node re = Rewriter::rewrite(t[1]);\r
+ if(polarity) {\r
+ simplifyPRegExp( str, re, new_nodes );\r
+ } else {\r
+ simplifyNRegExp( str, re, new_nodes );\r
+ }\r
+ Trace("strings-regexp-simpl") << "RegExp-Simpl returns (" << new_nodes.size() << "):\n";\r
+ for(unsigned i=0; i<new_nodes.size(); i++) {\r
+ Trace("strings-regexp-simpl") << "\t" << new_nodes[i] << std::endl;\r
+ }\r
}\r
void RegExpOpr::simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {\r
- std::pair < Node, Node > p(s, r);\r
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_neg_cache.find(p);\r
- if(itr != d_simpl_neg_cache.end()) {\r
- new_nodes.push_back( itr->second );\r
- } else {\r
- int k = r.getKind();\r
- Node conc;\r
- switch( k ) {\r
- case kind::REGEXP_EMPTY: {\r
- conc = d_true;\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)).negate();\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- conc = s.eqNode(r[0]).negate();\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- //TODO: rewrite empty\r
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);\r
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());\r
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);\r
- Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_zero),\r
- NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s), b1 ) );\r
- Node s1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1));\r
- Node s2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1)));\r
- Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();\r
- if(r[0].getKind() == kind::STRING_TO_REGEXP) {\r
- s1r1 = s1.eqNode(r[0][0]).negate();\r
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {\r
- s1r1 = d_true;\r
- }\r
- Node r2 = r[1];\r
- if(r.getNumChildren() > 2) {\r
- std::vector< Node > nvec;\r
- for(unsigned i=1; i<r.getNumChildren(); i++) {\r
- nvec.push_back( r[i] );\r
- }\r
- r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, nvec);\r
- }\r
- r2 = Rewriter::rewrite(r2);\r
- Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r2).negate();\r
- if(r2.getKind() == kind::STRING_TO_REGEXP) {\r
- s2r2 = s2.eqNode(r2[0]).negate();\r
- } else if(r2.getKind() == kind::REGEXP_EMPTY) {\r
- s2r2 = d_true;\r
- }\r
+ std::pair < Node, Node > p(s, r);\r
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_neg_cache.find(p);\r
+ if(itr != d_simpl_neg_cache.end()) {\r
+ new_nodes.push_back( itr->second );\r
+ } else {\r
+ int k = r.getKind();\r
+ Node conc;\r
+ switch( k ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ conc = d_true;\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)).negate();\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ conc = s.eqNode(r[0]).negate();\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ //TODO: rewrite empty\r
+ Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);\r
+ Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());\r
+ Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);\r
+ Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_zero),\r
+ NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s), b1 ) );\r
+ Node s1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1));\r
+ Node s2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1)));\r
+ Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();\r
+ if(r[0].getKind() == kind::STRING_TO_REGEXP) {\r
+ s1r1 = s1.eqNode(r[0][0]).negate();\r
+ } else if(r[0].getKind() == kind::REGEXP_EMPTY) {\r
+ s1r1 = d_true;\r
+ }\r
+ Node r2 = r[1];\r
+ if(r.getNumChildren() > 2) {\r
+ std::vector< Node > nvec;\r
+ for(unsigned i=1; i<r.getNumChildren(); i++) {\r
+ nvec.push_back( r[i] );\r
+ }\r
+ r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, nvec);\r
+ }\r
+ r2 = Rewriter::rewrite(r2);\r
+ Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r2).negate();\r
+ if(r2.getKind() == kind::STRING_TO_REGEXP) {\r
+ s2r2 = s2.eqNode(r2[0]).negate();\r
+ } else if(r2.getKind() == kind::REGEXP_EMPTY) {\r
+ s2r2 = d_true;\r
+ }\r
+\r
+ conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);\r
+ conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);\r
+ conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ std::vector< Node > c_and;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
+ c_and.push_back( r[i][0].eqNode(s).negate() );\r
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
+ continue;\r
+ } else {\r
+ c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());\r
+ }\r
+ }\r
+ conc = c_and.size() == 0 ? d_true :\r
+ c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ bool emptyflag = false;\r
+ std::vector< Node > c_or;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
+ c_or.push_back( r[i][0].eqNode(s).negate() );\r
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
+ emptyflag = true;\r
+ break;\r
+ } else {\r
+ c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());\r
+ }\r
+ }\r
+ if(emptyflag) {\r
+ conc = d_true;\r
+ } else {\r
+ conc = c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ if(s == d_emptyString) {\r
+ conc = d_false;\r
+ } else if(r[0].getKind() == kind::REGEXP_EMPTY) {\r
+ conc = s.eqNode(d_emptyString).negate();\r
+ } else if(r[0].getKind() == kind::REGEXP_SIGMA) {\r
+ conc = d_false;\r
+ } else {\r
+ Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);\r
+ Node sne = s.eqNode(d_emptyString).negate();\r
+ Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());\r
+ Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);\r
+ Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_one),\r
+ NodeManager::currentNM()->mkNode( kind::GEQ, lens, b1 ) );\r
+ //internal\r
+ Node s1 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1);\r
+ Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1));\r
+ Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();\r
+ Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r).negate();\r
\r
- conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);\r
- conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);\r
- conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- std::vector< Node > c_and;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
- c_and.push_back( r[i][0].eqNode(s).negate() );\r
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
- continue;\r
- } else {\r
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());\r
- }\r
- }\r
- conc = c_and.size() == 0 ? d_true :\r
- c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- bool emptyflag = false;\r
- std::vector< Node > c_or;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
- c_or.push_back( r[i][0].eqNode(s).negate() );\r
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
- emptyflag = true;\r
- break;\r
- } else {\r
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());\r
- }\r
- }\r
- if(emptyflag) {\r
- conc = d_true;\r
- } else {\r
- conc = c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- if(s == d_emptyString) {\r
- conc = d_false;\r
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {\r
- conc = s.eqNode(d_emptyString).negate();\r
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {\r
- conc = d_false;\r
- } else {\r
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);\r
- Node sne = s.eqNode(d_emptyString).negate();\r
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());\r
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);\r
- Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_one),\r
- NodeManager::currentNM()->mkNode( kind::GEQ, lens, b1 ) );\r
- //internal\r
- Node s1 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1);\r
- Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1));\r
- Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();\r
- Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r).negate();\r
- \r
- conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);\r
- conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);\r
- conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);\r
- conc = NodeManager::currentNM()->mkNode(kind::AND, sne, conc);\r
- }\r
- break;\r
- }\r
- default: {\r
- Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyNRegExp." << std::endl;\r
- Assert( false, "Unsupported Term" );\r
- }\r
- }\r
- conc = Rewriter::rewrite( conc );\r
- new_nodes.push_back( conc );\r
- d_simpl_neg_cache[p] = conc;\r
- }\r
+ conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);\r
+ conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);\r
+ conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);\r
+ conc = NodeManager::currentNM()->mkNode(kind::AND, sne, conc);\r
+ }\r
+ break;\r
+ }\r
+ default: {\r
+ Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyNRegExp." << std::endl;\r
+ Assert( false, "Unsupported Term" );\r
+ }\r
+ }\r
+ conc = Rewriter::rewrite( conc );\r
+ new_nodes.push_back( conc );\r
+ d_simpl_neg_cache[p] = conc;\r
+ }\r
}\r
void RegExpOpr::simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {\r
- std::pair < Node, Node > p(s, r);\r
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_cache.find(p);\r
- if(itr != d_simpl_cache.end()) {\r
- new_nodes.push_back( itr->second );\r
- } else {\r
- int k = r.getKind();\r
- Node conc;\r
- switch( k ) {\r
- case kind::REGEXP_EMPTY: {\r
- conc = d_false;\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- conc = s.eqNode(r[0]);\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- std::vector< Node > nvec;\r
- std::vector< Node > cc;\r
- bool emptyflag = false;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
- cc.push_back( r[i][0] );\r
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
- emptyflag = true;\r
- break;\r
- } else {\r
- Node sk = NodeManager::currentNM()->mkSkolem( "rc", s.getType(), "created for regular expression concat" );\r
- Node lem = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk, r[i]);\r
- nvec.push_back(lem);\r
- cc.push_back(sk);\r
- }\r
- }\r
- if(emptyflag) {\r
- conc = d_false;\r
- } else {\r
- Node lem = s.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc) );\r
- nvec.push_back(lem);\r
- conc = nvec.size() == 1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- std::vector< Node > c_or;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
- c_or.push_back( r[i][0].eqNode(s) );\r
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
- continue;\r
- } else {\r
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));\r
- }\r
- }\r
- conc = c_or.size() == 0 ? d_false :\r
- c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- std::vector< Node > c_and;\r
- bool emptyflag = false;\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
- c_and.push_back( r[i][0].eqNode(s) );\r
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
- emptyflag = true;\r
- break;\r
- } else {\r
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));\r
- }\r
- }\r
- if(emptyflag) {\r
- conc = d_false;\r
- } else {\r
- conc = c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- if(s == d_emptyString) {\r
- conc = d_true;\r
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {\r
- conc = s.eqNode(d_emptyString);\r
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {\r
- conc = d_true;\r
- } else {\r
- Node se = s.eqNode(d_emptyString);\r
- Node sinr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[0]);\r
- Node sk1 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );\r
- Node sk2 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );\r
- Node s1nz = sk1.eqNode(d_emptyString).negate();\r
- Node s2nz = sk2.eqNode(d_emptyString).negate();\r
- Node s1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);\r
- Node s2inrs = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2, r);\r
- Node s12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2));\r
+ std::pair < Node, Node > p(s, r);\r
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_cache.find(p);\r
+ if(itr != d_simpl_cache.end()) {\r
+ new_nodes.push_back( itr->second );\r
+ } else {\r
+ int k = r.getKind();\r
+ Node conc;\r
+ switch( k ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ conc = d_false;\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ conc = s.eqNode(r[0]);\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ std::vector< Node > nvec;\r
+ std::vector< Node > cc;\r
+ bool emptyflag = false;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
+ cc.push_back( r[i][0] );\r
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
+ emptyflag = true;\r
+ break;\r
+ } else {\r
+ Node sk = NodeManager::currentNM()->mkSkolem( "rc", s.getType(), "created for regular expression concat" );\r
+ Node lem = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk, r[i]);\r
+ nvec.push_back(lem);\r
+ cc.push_back(sk);\r
+ }\r
+ }\r
+ if(emptyflag) {\r
+ conc = d_false;\r
+ } else {\r
+ Node lem = s.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc) );\r
+ nvec.push_back(lem);\r
+ conc = nvec.size() == 1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ std::vector< Node > c_or;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
+ c_or.push_back( r[i][0].eqNode(s) );\r
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
+ continue;\r
+ } else {\r
+ c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));\r
+ }\r
+ }\r
+ conc = c_or.size() == 0 ? d_false :\r
+ c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ std::vector< Node > c_and;\r
+ bool emptyflag = false;\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {\r
+ c_and.push_back( r[i][0].eqNode(s) );\r
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {\r
+ emptyflag = true;\r
+ break;\r
+ } else {\r
+ c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));\r
+ }\r
+ }\r
+ if(emptyflag) {\r
+ conc = d_false;\r
+ } else {\r
+ conc = c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ if(s == d_emptyString) {\r
+ conc = d_true;\r
+ } else if(r[0].getKind() == kind::REGEXP_EMPTY) {\r
+ conc = s.eqNode(d_emptyString);\r
+ } else if(r[0].getKind() == kind::REGEXP_SIGMA) {\r
+ conc = d_true;\r
+ } else {\r
+ Node se = s.eqNode(d_emptyString);\r
+ Node sinr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[0]);\r
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );\r
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );\r
+ Node s1nz = sk1.eqNode(d_emptyString).negate();\r
+ Node s2nz = sk2.eqNode(d_emptyString).negate();\r
+ Node s1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);\r
+ Node s2inrs = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2, r);\r
+ Node s12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2));\r
\r
- conc = NodeManager::currentNM()->mkNode(kind::AND, s12, s1nz, s2nz, s1inr, s2inrs);\r
- conc = NodeManager::currentNM()->mkNode(kind::OR, se, sinr, conc);\r
- }\r
- break;\r
- }\r
- default: {\r
- Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyPRegExp." << std::endl;\r
- Assert( false, "Unsupported Term" );\r
- }\r
- }\r
- conc = Rewriter::rewrite( conc );\r
- new_nodes.push_back( conc );\r
- d_simpl_cache[p] = conc;\r
- }\r
+ conc = NodeManager::currentNM()->mkNode(kind::AND, s12, s1nz, s2nz, s1inr, s2inrs);\r
+ conc = NodeManager::currentNM()->mkNode(kind::OR, se, sinr, conc);\r
+ }\r
+ break;\r
+ }\r
+ default: {\r
+ Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyPRegExp." << std::endl;\r
+ Assert( false, "Unsupported Term" );\r
+ }\r
+ }\r
+ conc = Rewriter::rewrite( conc );\r
+ new_nodes.push_back( conc );\r
+ d_simpl_cache[p] = conc;\r
+ }\r
}\r
\r
void RegExpOpr::getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) {\r
- std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_cset_cache.find(r);\r
- if(itr != d_cset_cache.end()) {\r
- pcset.insert((itr->second).first.begin(), (itr->second).first.end());\r
- pvset.insert((itr->second).second.begin(), (itr->second).second.end());\r
- } else {\r
- std::set<unsigned> cset;\r
- SetNodes vset;\r
- int k = r.getKind();\r
- switch( k ) {\r
- case kind::REGEXP_EMPTY: {\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- for(unsigned i=0; i<d_card; i++) {\r
- cset.insert(i);\r
- }\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- Node st = Rewriter::rewrite(r[0]);\r
- if(st.isConst()) {\r
- CVC4::String s = st.getConst< CVC4::String >();\r
- s.getCharSet( cset );\r
- } else if(st.getKind() == kind::VARIABLE) {\r
- vset.insert( st );\r
- } else {\r
- for(unsigned i=0; i<st.getNumChildren(); i++) {\r
- if(st[i].isConst()) {\r
- CVC4::String s = st[i].getConst< CVC4::String >();\r
- s.getCharSet( cset );\r
- } else {\r
- vset.insert( st[i] );\r
- }\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- for(unsigned i=0; i<r.getNumChildren(); i++) {\r
- getCharSet(r[i], cset, vset);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- for(unsigned i=0; i<r.getNumChildren(); i++) {\r
- getCharSet(r[i], cset, vset);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- //TODO: Overapproximation for now\r
- for(unsigned i=0; i<r.getNumChildren(); i++) {\r
- getCharSet(r[i], cset, vset);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- getCharSet(r[0], cset, vset);\r
- break;\r
- }\r
- default: {\r
- Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;\r
- Assert( false, "Unsupported Term" );\r
- }\r
- }\r
- pcset.insert(cset.begin(), cset.end());\r
- pvset.insert(vset.begin(), vset.end());\r
- std::pair< std::set<unsigned>, SetNodes > p(cset, vset);\r
- d_cset_cache[r] = p;\r
+ std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_cset_cache.find(r);\r
+ if(itr != d_cset_cache.end()) {\r
+ pcset.insert((itr->second).first.begin(), (itr->second).first.end());\r
+ pvset.insert((itr->second).second.begin(), (itr->second).second.end());\r
+ } else {\r
+ std::set<unsigned> cset;\r
+ SetNodes vset;\r
+ int k = r.getKind();\r
+ switch( k ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ for(unsigned i=0; i<d_card; i++) {\r
+ cset.insert(i);\r
+ }\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ Node st = Rewriter::rewrite(r[0]);\r
+ if(st.isConst()) {\r
+ CVC4::String s = st.getConst< CVC4::String >();\r
+ s.getCharSet( cset );\r
+ } else if(st.getKind() == kind::VARIABLE) {\r
+ vset.insert( st );\r
+ } else {\r
+ for(unsigned i=0; i<st.getNumChildren(); i++) {\r
+ if(st[i].isConst()) {\r
+ CVC4::String s = st[i].getConst< CVC4::String >();\r
+ s.getCharSet( cset );\r
+ } else {\r
+ vset.insert( st[i] );\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ for(unsigned i=0; i<r.getNumChildren(); i++) {\r
+ getCharSet(r[i], cset, vset);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ for(unsigned i=0; i<r.getNumChildren(); i++) {\r
+ getCharSet(r[i], cset, vset);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ //TODO: Overapproximation for now\r
+ for(unsigned i=0; i<r.getNumChildren(); i++) {\r
+ getCharSet(r[i], cset, vset);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ getCharSet(r[0], cset, vset);\r
+ break;\r
+ }\r
+ default: {\r
+ Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;\r
+ Assert( false, "Unsupported Term" );\r
+ }\r
+ }\r
+ pcset.insert(cset.begin(), cset.end());\r
+ pvset.insert(vset.begin(), vset.end());\r
+ std::pair< std::set<unsigned>, SetNodes > p(cset, vset);\r
+ d_cset_cache[r] = p;\r
\r
- Trace("regexp-cset") << "CSET( " << mkString(r) << " ) = { ";\r
- for(std::set<unsigned>::const_iterator itr = cset.begin();\r
- itr != cset.end(); itr++) {\r
- Trace("regexp-cset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";\r
- }\r
- Trace("regexp-cset") << " }" << std::endl;\r
- }\r
+ Trace("regexp-cset") << "CSET( " << mkString(r) << " ) = { ";\r
+ for(std::set<unsigned>::const_iterator itr = cset.begin();\r
+ itr != cset.end(); itr++) {\r
+ Trace("regexp-cset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";\r
+ }\r
+ Trace("regexp-cset") << " }" << std::endl;\r
+ }\r
}\r
\r
Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ) {\r
- if(spflag) {\r
- //TODO: var\r
- return Node::null();\r
- }\r
- std::pair < Node, Node > p(r1, r2);\r
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p);\r
- Node rNode;\r
- if(itr != d_inter_cache.end()) {\r
- rNode = itr->second;\r
- } else {\r
- if(r1 == r2) {\r
- rNode = r1;\r
- } else if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {\r
- rNode = d_emptyRegexp;\r
- } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {\r
- Node exp;\r
- int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);\r
- if(r == 0) {\r
- //TODO: variable\r
- spflag = true;\r
- } else if(r == 1) {\r
- rNode = d_emptySingleton;\r
- } else {\r
- rNode = d_emptyRegexp;\r
- }\r
- } else {\r
- std::set< unsigned > cset, cset2;\r
- std::set< Node > vset, vset2;\r
- getCharSet(r1, cset, vset);\r
- getCharSet(r2, cset2, vset2);\r
- if(vset.empty() && vset2.empty()) {\r
- cset.clear();\r
- firstChars(r1, cset, vset);\r
- std::vector< Node > vec_nodes;\r
- for(std::set<unsigned>::const_iterator itr = cset.begin();\r
- itr != cset.end(); itr++) {\r
- CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );\r
- std::pair< Node, Node > p(r1, r2);\r
- if(cache[ *itr ].find(p) == cache[ *itr ].end()) {\r
- Node r1l = derivativeSingle(r1, c);\r
- Node r2l = derivativeSingle(r2, c);\r
- std::map< unsigned, std::set< PairNodes > > cache2(cache);\r
- PairNodes p(r1l, r2l);\r
- cache2[ *itr ].insert( p );\r
- Node rt = intersectInternal(r1l, r2l, cache2, spflag);\r
- if(spflag) {\r
- //TODO:\r
- return Node::null();\r
- }\r
- rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, \r
- NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) );\r
- vec_nodes.push_back(rt);\r
- }\r
- }\r
- rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] :\r
- NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);\r
- rNode = Rewriter::rewrite( rNode );\r
- } else {\r
- //TODO: non-empty var set\r
- spflag = true;\r
- }\r
- }\r
- d_inter_cache[p] = rNode;\r
- }\r
- Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;\r
- return rNode;\r
+ if(spflag) {\r
+ //TODO: var\r
+ return Node::null();\r
+ }\r
+ std::pair < Node, Node > p(r1, r2);\r
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p);\r
+ Node rNode;\r
+ if(itr != d_inter_cache.end()) {\r
+ rNode = itr->second;\r
+ } else {\r
+ if(r1 == r2) {\r
+ rNode = r1;\r
+ } else if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {\r
+ rNode = d_emptyRegexp;\r
+ } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {\r
+ Node exp;\r
+ int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);\r
+ if(r == 0) {\r
+ //TODO: variable\r
+ spflag = true;\r
+ } else if(r == 1) {\r
+ rNode = d_emptySingleton;\r
+ } else {\r
+ rNode = d_emptyRegexp;\r
+ }\r
+ } else {\r
+ std::set< unsigned > cset, cset2;\r
+ std::set< Node > vset, vset2;\r
+ getCharSet(r1, cset, vset);\r
+ getCharSet(r2, cset2, vset2);\r
+ if(vset.empty() && vset2.empty()) {\r
+ cset.clear();\r
+ firstChars(r1, cset, vset);\r
+ std::vector< Node > vec_nodes;\r
+ for(std::set<unsigned>::const_iterator itr = cset.begin();\r
+ itr != cset.end(); itr++) {\r
+ CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );\r
+ std::pair< Node, Node > p(r1, r2);\r
+ if(cache[ *itr ].find(p) == cache[ *itr ].end()) {\r
+ Node r1l = derivativeSingle(r1, c);\r
+ Node r2l = derivativeSingle(r2, c);\r
+ std::map< unsigned, std::set< PairNodes > > cache2(cache);\r
+ PairNodes p(r1l, r2l);\r
+ cache2[ *itr ].insert( p );\r
+ Node rt = intersectInternal(r1l, r2l, cache2, spflag);\r
+ if(spflag) {\r
+ //TODO:\r
+ return Node::null();\r
+ }\r
+ rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,\r
+ NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) );\r
+ vec_nodes.push_back(rt);\r
+ }\r
+ }\r
+ rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] :\r
+ NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);\r
+ rNode = Rewriter::rewrite( rNode );\r
+ } else {\r
+ //TODO: non-empty var set\r
+ spflag = true;\r
+ }\r
+ }\r
+ d_inter_cache[p] = rNode;\r
+ }\r
+ Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;\r
+ return rNode;\r
}\r
Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) {\r
- std::map< unsigned, std::set< PairNodes > > cache;\r
- return intersectInternal(r1, r2, cache, spflag);\r
+ std::map< unsigned, std::set< PairNodes > > cache;\r
+ return intersectInternal(r1, r2, cache, spflag);\r
}\r
\r
Node RegExpOpr::complement(Node r, int &ret) {\r
- Node rNode;\r
- ret = 1;\r
- if(d_compl_cache.find(r) != d_compl_cache.end()) {\r
- rNode = d_compl_cache[r].first;\r
- ret = d_compl_cache[r].second;\r
- } else {\r
- if(r == d_emptyRegexp) {\r
- rNode = d_sigma_star;\r
- } else if(r == d_emptySingleton) {\r
- rNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, d_sigma, d_sigma_star);\r
- } else if(!checkConstRegExp(r)) {\r
- //TODO: var to be extended\r
- ret = 0;\r
- } else {\r
- std::set<unsigned> cset;\r
- SetNodes vset;\r
- firstChars(r, cset, vset);\r
- std::vector< Node > vec_nodes;\r
- for(unsigned i=0; i<d_card; i++) {\r
- CVC4::String c = CVC4::String::convertUnsignedIntToChar(i);\r
- Node n = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c));\r
- Node r2;\r
- if(cset.find(i) == cset.end()) {\r
- r2 = d_sigma_star;\r
- } else {\r
- int rt;\r
- derivativeS(r, c, r2);\r
- if(r2 == r) {\r
- r2 = d_emptyRegexp;\r
- } else {\r
- r2 = complement(r2, rt);\r
- }\r
- }\r
- n = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, n, r2));\r
- vec_nodes.push_back(n);\r
- }\r
- rNode = vec_nodes.size()==0? d_emptyRegexp : vec_nodes.size()==1? vec_nodes[0] :\r
- NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);\r
- }\r
- rNode = Rewriter::rewrite(rNode);\r
- std::pair< Node, int > p(rNode, ret);\r
- d_compl_cache[r] = p;\r
- }\r
- Trace("regexp-compl") << "COMPL( " << mkString(r) << " ) = " << mkString(rNode) << ", ret=" << ret << std::endl;\r
- return rNode;\r
+ Node rNode;\r
+ ret = 1;\r
+ if(d_compl_cache.find(r) != d_compl_cache.end()) {\r
+ rNode = d_compl_cache[r].first;\r
+ ret = d_compl_cache[r].second;\r
+ } else {\r
+ if(r == d_emptyRegexp) {\r
+ rNode = d_sigma_star;\r
+ } else if(r == d_emptySingleton) {\r
+ rNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, d_sigma, d_sigma_star);\r
+ } else if(!checkConstRegExp(r)) {\r
+ //TODO: var to be extended\r
+ ret = 0;\r
+ } else {\r
+ std::set<unsigned> cset;\r
+ SetNodes vset;\r
+ firstChars(r, cset, vset);\r
+ std::vector< Node > vec_nodes;\r
+ for(unsigned i=0; i<d_card; i++) {\r
+ CVC4::String c = CVC4::String::convertUnsignedIntToChar(i);\r
+ Node n = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c));\r
+ Node r2;\r
+ if(cset.find(i) == cset.end()) {\r
+ r2 = d_sigma_star;\r
+ } else {\r
+ int rt;\r
+ derivativeS(r, c, r2);\r
+ if(r2 == r) {\r
+ r2 = d_emptyRegexp;\r
+ } else {\r
+ r2 = complement(r2, rt);\r
+ }\r
+ }\r
+ n = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, n, r2));\r
+ vec_nodes.push_back(n);\r
+ }\r
+ rNode = vec_nodes.size()==0? d_emptyRegexp : vec_nodes.size()==1? vec_nodes[0] :\r
+ NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);\r
+ }\r
+ rNode = Rewriter::rewrite(rNode);\r
+ std::pair< Node, int > p(rNode, ret);\r
+ d_compl_cache[r] = p;\r
+ }\r
+ Trace("regexp-compl") << "COMPL( " << mkString(r) << " ) = " << mkString(rNode) << ", ret=" << ret << std::endl;\r
+ return rNode;\r
}\r
\r
void RegExpOpr::splitRegExp(Node r, std::vector< PairNodes > &pset) {\r
- Assert(checkConstRegExp(r));\r
- if(d_split_cache.find(r) != d_split_cache.end()) {\r
- pset = d_split_cache[r];\r
- } else {\r
- switch( r.getKind() ) {\r
- case kind::REGEXP_EMPTY: {\r
- break;\r
- }\r
- case kind::REGEXP_OPT: {\r
- PairNodes tmp(d_emptySingleton, d_emptySingleton);\r
- pset.push_back(tmp);\r
- }\r
- case kind::REGEXP_RANGE:\r
- case kind::REGEXP_SIGMA: {\r
- PairNodes tmp1(d_emptySingleton, r);\r
- PairNodes tmp2(r, d_emptySingleton);\r
- pset.push_back(tmp1);\r
- pset.push_back(tmp2);\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- Assert(r[0].isConst());\r
- CVC4::String s = r[0].getConst< CVC4::String >();\r
- PairNodes tmp1(d_emptySingleton, r);\r
- pset.push_back(tmp1);\r
- for(unsigned i=1; i<s.size(); i++) {\r
- CVC4::String s1 = s.substr(0, i);\r
- CVC4::String s2 = s.substr(i);\r
- Node n1 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s1));\r
- Node n2 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s2));\r
- PairNodes tmp3(n1, n2);\r
- pset.push_back(tmp3);\r
- }\r
- PairNodes tmp2(r, d_emptySingleton);\r
- pset.push_back(tmp2);\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- for(unsigned i=0; i<r.getNumChildren(); i++) {\r
- std::vector< PairNodes > tset;\r
- splitRegExp(r[i], tset);\r
- std::vector< Node > hvec;\r
- std::vector< Node > tvec;\r
- for(unsigned j=0; j<=i; j++) {\r
- hvec.push_back(r[j]);\r
- }\r
- for(unsigned j=i; j<r.getNumChildren(); j++) {\r
- tvec.push_back(r[j]);\r
- }\r
- for(unsigned j=0; j<tset.size(); j++) {\r
- hvec[i] = tset[j].first;\r
- tvec[0] = tset[j].second;\r
- Node r1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, hvec) );\r
- Node r2 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tvec) );\r
- PairNodes tmp2(r1, r2);\r
- pset.push_back(tmp2);\r
- }\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- std::vector< PairNodes > tset;\r
- splitRegExp(r[i], tset);\r
- pset.insert(pset.end(), tset.begin(), tset.end());\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- bool spflag = false;\r
- Node tmp = r[0];\r
- for(unsigned i=1; i<r.getNumChildren(); i++) {\r
- tmp = intersect(tmp, r[i], spflag);\r
- }\r
- splitRegExp(tmp, pset);\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- std::vector< PairNodes > tset;\r
- splitRegExp(r[0], tset);\r
- PairNodes tmp1(d_emptySingleton, d_emptySingleton);\r
- pset.push_back(tmp1);\r
- for(unsigned i=0; i<tset.size(); i++) {\r
- Node r1 = tset[i].first==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);\r
- Node r2 = tset[i].second==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);\r
- PairNodes tmp2(r1, r2);\r
- pset.push_back(tmp2);\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_PLUS: {\r
- std::vector< PairNodes > tset;\r
- splitRegExp(r[0], tset);\r
- for(unsigned i=0; i<tset.size(); i++) {\r
- Node r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);\r
- Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);\r
- PairNodes tmp2(r1, r2);\r
- pset.push_back(tmp2);\r
- }\r
- break;\r
- }\r
- default: {\r
- Trace("strings-error") << "Unsupported term: " << r << " in splitRegExp." << std::endl;\r
- Assert( false );\r
- //return Node::null();\r
- }\r
- }\r
- d_split_cache[r] = pset;\r
- }\r
+ Assert(checkConstRegExp(r));\r
+ if(d_split_cache.find(r) != d_split_cache.end()) {\r
+ pset = d_split_cache[r];\r
+ } else {\r
+ switch( r.getKind() ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ break;\r
+ }\r
+ case kind::REGEXP_OPT: {\r
+ PairNodes tmp(d_emptySingleton, d_emptySingleton);\r
+ pset.push_back(tmp);\r
+ }\r
+ case kind::REGEXP_RANGE:\r
+ case kind::REGEXP_SIGMA: {\r
+ PairNodes tmp1(d_emptySingleton, r);\r
+ PairNodes tmp2(r, d_emptySingleton);\r
+ pset.push_back(tmp1);\r
+ pset.push_back(tmp2);\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ Assert(r[0].isConst());\r
+ CVC4::String s = r[0].getConst< CVC4::String >();\r
+ PairNodes tmp1(d_emptySingleton, r);\r
+ pset.push_back(tmp1);\r
+ for(unsigned i=1; i<s.size(); i++) {\r
+ CVC4::String s1 = s.substr(0, i);\r
+ CVC4::String s2 = s.substr(i);\r
+ Node n1 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s1));\r
+ Node n2 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s2));\r
+ PairNodes tmp3(n1, n2);\r
+ pset.push_back(tmp3);\r
+ }\r
+ PairNodes tmp2(r, d_emptySingleton);\r
+ pset.push_back(tmp2);\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ for(unsigned i=0; i<r.getNumChildren(); i++) {\r
+ std::vector< PairNodes > tset;\r
+ splitRegExp(r[i], tset);\r
+ std::vector< Node > hvec;\r
+ std::vector< Node > tvec;\r
+ for(unsigned j=0; j<=i; j++) {\r
+ hvec.push_back(r[j]);\r
+ }\r
+ for(unsigned j=i; j<r.getNumChildren(); j++) {\r
+ tvec.push_back(r[j]);\r
+ }\r
+ for(unsigned j=0; j<tset.size(); j++) {\r
+ hvec[i] = tset[j].first;\r
+ tvec[0] = tset[j].second;\r
+ Node r1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, hvec) );\r
+ Node r2 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tvec) );\r
+ PairNodes tmp2(r1, r2);\r
+ pset.push_back(tmp2);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ std::vector< PairNodes > tset;\r
+ splitRegExp(r[i], tset);\r
+ pset.insert(pset.end(), tset.begin(), tset.end());\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ bool spflag = false;\r
+ Node tmp = r[0];\r
+ for(unsigned i=1; i<r.getNumChildren(); i++) {\r
+ tmp = intersect(tmp, r[i], spflag);\r
+ }\r
+ splitRegExp(tmp, pset);\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ std::vector< PairNodes > tset;\r
+ splitRegExp(r[0], tset);\r
+ PairNodes tmp1(d_emptySingleton, d_emptySingleton);\r
+ pset.push_back(tmp1);\r
+ for(unsigned i=0; i<tset.size(); i++) {\r
+ Node r1 = tset[i].first==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);\r
+ Node r2 = tset[i].second==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);\r
+ PairNodes tmp2(r1, r2);\r
+ pset.push_back(tmp2);\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_PLUS: {\r
+ std::vector< PairNodes > tset;\r
+ splitRegExp(r[0], tset);\r
+ for(unsigned i=0; i<tset.size(); i++) {\r
+ Node r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);\r
+ Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);\r
+ PairNodes tmp2(r1, r2);\r
+ pset.push_back(tmp2);\r
+ }\r
+ break;\r
+ }\r
+ default: {\r
+ Trace("strings-error") << "Unsupported term: " << r << " in splitRegExp." << std::endl;\r
+ Assert( false );\r
+ //return Node::null();\r
+ }\r
+ }\r
+ d_split_cache[r] = pset;\r
+ }\r
}\r
\r
//printing\r
std::string RegExpOpr::niceChar( Node r ) {\r
- if(r.isConst()) {\r
- std::string s = r.getConst<CVC4::String>().toString() ;\r
- return s == "" ? "{E}" : ( s == " " ? "{ }" : s.size()>1? "("+s+")" : s );\r
- } else {\r
- std::string ss = "$" + r.toString();\r
- return ss;\r
- }\r
+ if(r.isConst()) {\r
+ std::string s = r.getConst<CVC4::String>().toString() ;\r
+ return s == "" ? "{E}" : ( s == " " ? "{ }" : s.size()>1? "("+s+")" : s );\r
+ } else {\r
+ std::string ss = "$" + r.toString();\r
+ return ss;\r
+ }\r
}\r
std::string RegExpOpr::mkString( Node r ) {\r
- std::string retStr;\r
- if(r.isNull()) {\r
- retStr = "Empty";\r
- } else {\r
- int k = r.getKind();\r
- switch( k ) {\r
- case kind::REGEXP_EMPTY: {\r
- retStr += "Empty";\r
- break;\r
- }\r
- case kind::REGEXP_SIGMA: {\r
- retStr += "{W}";\r
- break;\r
- }\r
- case kind::STRING_TO_REGEXP: {\r
- retStr += niceChar( r[0] );\r
- break;\r
- }\r
- case kind::REGEXP_CONCAT: {\r
- retStr += "(";\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- //if(i != 0) retStr += ".";\r
- retStr += mkString( r[i] );\r
- }\r
- retStr += ")";\r
- break;\r
- }\r
- case kind::REGEXP_UNION: {\r
- if(r == d_sigma) {\r
- retStr += "{A}";\r
- } else {\r
- retStr += "(";\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(i != 0) retStr += "|";\r
- retStr += mkString( r[i] );\r
- }\r
- retStr += ")";\r
- }\r
- break;\r
- }\r
- case kind::REGEXP_INTER: {\r
- retStr += "(";\r
- for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
- if(i != 0) retStr += "&";\r
- retStr += mkString( r[i] );\r
- }\r
- retStr += ")";\r
- break;\r
- }\r
- case kind::REGEXP_STAR: {\r
- retStr += mkString( r[0] );\r
- retStr += "*";\r
- break;\r
- }\r
- case kind::REGEXP_PLUS: {\r
- retStr += mkString( r[0] );\r
- retStr += "+";\r
- break;\r
- }\r
- case kind::REGEXP_OPT: {\r
- retStr += mkString( r[0] );\r
- retStr += "?";\r
- break;\r
- }\r
- case kind::REGEXP_RANGE: {\r
- retStr += "[";\r
- retStr += niceChar( r[0] );\r
- retStr += "-";\r
- retStr += niceChar( r[1] );\r
- retStr += "]";\r
- break;\r
- }\r
- default:\r
- Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl;\r
- //Assert( false );\r
- //return Node::null();\r
- }\r
- }\r
+ std::string retStr;\r
+ if(r.isNull()) {\r
+ retStr = "Empty";\r
+ } else {\r
+ int k = r.getKind();\r
+ switch( k ) {\r
+ case kind::REGEXP_EMPTY: {\r
+ retStr += "Empty";\r
+ break;\r
+ }\r
+ case kind::REGEXP_SIGMA: {\r
+ retStr += "{W}";\r
+ break;\r
+ }\r
+ case kind::STRING_TO_REGEXP: {\r
+ retStr += niceChar( r[0] );\r
+ break;\r
+ }\r
+ case kind::REGEXP_CONCAT: {\r
+ retStr += "(";\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ //if(i != 0) retStr += ".";\r
+ retStr += mkString( r[i] );\r
+ }\r
+ retStr += ")";\r
+ break;\r
+ }\r
+ case kind::REGEXP_UNION: {\r
+ if(r == d_sigma) {\r
+ retStr += "{A}";\r
+ } else {\r
+ retStr += "(";\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(i != 0) retStr += "|";\r
+ retStr += mkString( r[i] );\r
+ }\r
+ retStr += ")";\r
+ }\r
+ break;\r
+ }\r
+ case kind::REGEXP_INTER: {\r
+ retStr += "(";\r
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {\r
+ if(i != 0) retStr += "&";\r
+ retStr += mkString( r[i] );\r
+ }\r
+ retStr += ")";\r
+ break;\r
+ }\r
+ case kind::REGEXP_STAR: {\r
+ retStr += mkString( r[0] );\r
+ retStr += "*";\r
+ break;\r
+ }\r
+ case kind::REGEXP_PLUS: {\r
+ retStr += mkString( r[0] );\r
+ retStr += "+";\r
+ break;\r
+ }\r
+ case kind::REGEXP_OPT: {\r
+ retStr += mkString( r[0] );\r
+ retStr += "?";\r
+ break;\r
+ }\r
+ case kind::REGEXP_RANGE: {\r
+ retStr += "[";\r
+ retStr += niceChar( r[0] );\r
+ retStr += "-";\r
+ retStr += niceChar( r[1] );\r
+ retStr += "]";\r
+ break;\r
+ }\r
+ default:\r
+ Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl;\r
+ //Assert( false );\r
+ //return Node::null();\r
+ }\r
+ }\r
\r
- return retStr;\r
+ return retStr;\r
}\r
\r
}/* CVC4::theory::strings namespace */\r
namespace strings {\r
\r
class RegExpOpr {\r
- typedef std::pair< Node, CVC4::String > PairNodeStr;\r
- typedef std::set< Node > SetNodes;\r
- typedef std::pair< Node, Node > PairNodes;\r
+ typedef std::pair< Node, CVC4::String > PairNodeStr;\r
+ typedef std::set< Node > SetNodes;\r
+ typedef std::pair< Node, Node > PairNodes;\r
\r
private:\r
- unsigned d_card;\r
+ unsigned d_card;\r
Node d_emptyString;\r
Node d_true;\r
Node d_false;\r
- Node d_emptySingleton;\r
- Node d_emptyRegexp;\r
- Node d_zero;\r
- Node d_one;\r
+ Node d_emptySingleton;\r
+ Node d_emptyRegexp;\r
+ Node d_zero;\r
+ Node d_one;\r
\r
- char d_char_start;\r
- char d_char_end;\r
- Node d_sigma;\r
- Node d_sigma_star;\r
- \r
- std::map< PairNodes, Node > d_simpl_cache;\r
- std::map< PairNodes, Node > d_simpl_neg_cache;\r
- std::map< Node, std::pair< int, Node > > d_delta_cache;\r
- std::map< PairNodeStr, Node > d_dv_cache;\r
- std::map< PairNodeStr, std::pair< Node, int > > d_deriv_cache;\r
- std::map< Node, std::pair< Node, int > > d_compl_cache;\r
- std::map< Node, bool > d_cstre_cache;\r
- std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_cset_cache;\r
- std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_fset_cache;\r
- std::map< PairNodes, Node > d_inter_cache;\r
- std::map< Node, std::vector< PairNodes > > d_split_cache;\r
- //bool checkStarPlus( Node t );\r
- void simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes );\r
- void simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes );\r
- std::string niceChar( Node r );\r
- int gcd ( int a, int b );\r
- Node mkAllExceptOne( char c );\r
+ char d_char_start;\r
+ char d_char_end;\r
+ Node d_sigma;\r
+ Node d_sigma_star;\r
\r
- void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset );\r
- Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag );\r
- void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset );\r
+ std::map< PairNodes, Node > d_simpl_cache;\r
+ std::map< PairNodes, Node > d_simpl_neg_cache;\r
+ std::map< Node, std::pair< int, Node > > d_delta_cache;\r
+ std::map< PairNodeStr, Node > d_dv_cache;\r
+ std::map< PairNodeStr, std::pair< Node, int > > d_deriv_cache;\r
+ std::map< Node, std::pair< Node, int > > d_compl_cache;\r
+ std::map< Node, bool > d_cstre_cache;\r
+ std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_cset_cache;\r
+ std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_fset_cache;\r
+ std::map< PairNodes, Node > d_inter_cache;\r
+ std::map< Node, std::vector< PairNodes > > d_split_cache;\r
+ //bool checkStarPlus( Node t );\r
+ void simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes );\r
+ void simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes );\r
+ std::string niceChar( Node r );\r
+ int gcd ( int a, int b );\r
+ Node mkAllExceptOne( char c );\r
\r
- //TODO: for intersection\r
- bool follow( Node r, CVC4::String c, std::vector< char > &vec_chars );\r
+ void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset );\r
+ Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag );\r
+ void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset );\r
+\r
+ //TODO: for intersection\r
+ bool follow( Node r, CVC4::String c, std::vector< char > &vec_chars );\r
\r
public:\r
- RegExpOpr();\r
+ RegExpOpr();\r
\r
- bool checkConstRegExp( Node r );\r
+ bool checkConstRegExp( Node r );\r
void simplify(Node t, std::vector< Node > &new_nodes, bool polarity);\r
- int delta( Node r, Node &exp );\r
- int derivativeS( Node r, CVC4::String c, Node &retNode );\r
- Node derivativeSingle( Node r, CVC4::String c );\r
- bool guessLength( Node r, int &co );\r
- Node intersect(Node r1, Node r2, bool &spflag);\r
- Node complement(Node r, int &ret);\r
- void splitRegExp(Node r, std::vector< PairNodes > &pset);\r
+ int delta( Node r, Node &exp );\r
+ int derivativeS( Node r, CVC4::String c, Node &retNode );\r
+ Node derivativeSingle( Node r, CVC4::String c );\r
+ bool guessLength( Node r, int &co );\r
+ Node intersect(Node r1, Node r2, bool &spflag);\r
+ Node complement(Node r, int &ret);\r
+ void splitRegExp(Node r, std::vector< PairNodes > &pset);\r
\r
- std::string mkString( Node r );\r
+ std::string mkString( Node r );\r
};\r
\r
}/* CVC4::theory::strings namespace */\r
d_infer(c),
d_infer_exp(c),
d_nf_pairs(c),
- d_loop_antec(u),
- d_length_intro_vars(u),
- d_prereg_cached(u),
- d_length_nodes(u),
- d_length_inst(u),
- d_str_pos_ctn(c),
- d_str_neg_ctn(c),
- d_neg_ctn_eqlen(u),
- d_neg_ctn_ulen(u),
- d_pos_ctn_cached(u),
- d_neg_ctn_cached(u),
- d_regexp_memberships(c),
- d_regexp_ucached(u),
- d_regexp_ccached(c),
- d_str_re_map(c),
- d_inter_cache(c),
- d_inter_index(c),
- d_regexp_ant(c),
- d_input_vars(u),
- d_input_var_lsum(u),
- d_cardinality_lits(u),
- d_curr_cardinality(c, 0)
+ d_loop_antec(u),
+ d_length_intro_vars(u),
+ d_prereg_cached(u),
+ d_length_nodes(u),
+ d_length_inst(u),
+ d_str_pos_ctn(c),
+ d_str_neg_ctn(c),
+ d_neg_ctn_eqlen(u),
+ d_neg_ctn_ulen(u),
+ d_pos_ctn_cached(u),
+ d_neg_ctn_cached(u),
+ d_regexp_memberships(c),
+ d_regexp_ucached(u),
+ d_regexp_ccached(c),
+ d_str_re_map(c),
+ d_inter_cache(c),
+ d_inter_index(c),
+ d_regexp_ant(c),
+ d_input_vars(u),
+ d_input_var_lsum(u),
+ d_cardinality_lits(u),
+ d_curr_cardinality(c, 0)
{
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP);
}
Node TheoryStrings::getRepresentative( Node t ) {
- if( d_equalityEngine.hasTerm( t ) ){
- return d_equalityEngine.getRepresentative( t );
- }else{
- return t;
- }
+ if( d_equalityEngine.hasTerm( t ) ){
+ return d_equalityEngine.getRepresentative( t );
+ }else{
+ return t;
+ }
}
bool TheoryStrings::hasTerm( Node a ){
}
bool TheoryStrings::areDisequal( Node a, Node b ){
- if( a==b ){
- return false;
- } else {
- if( a.getType().isString() ) {
- for( unsigned i=0; i<2; i++ ) {
- Node ac = a.getKind()==kind::STRING_CONCAT ? a[i==0 ? 0 : a.getNumChildren()-1] : a;
- Node bc = b.getKind()==kind::STRING_CONCAT ? b[i==0 ? 0 : b.getNumChildren()-1] : b;
- if( ac.isConst() && bc.isConst() ){
- CVC4::String as = ac.getConst<String>();
- CVC4::String bs = bc.getConst<String>();
- int slen = as.size() > bs.size() ? bs.size() : as.size();
- bool flag = i == 1 ? as.rstrncmp(bs, slen): as.strncmp(bs, slen);
- if(!flag) {
- return true;
- }
- }
- }
- }
- if( hasTerm( a ) && hasTerm( b ) ) {
- if( d_equalityEngine.areDisequal( a, b, false ) ){
- return true;
- }
- }
- return false;
- }
+ if( a==b ){
+ return false;
+ } else {
+ if( a.getType().isString() ) {
+ for( unsigned i=0; i<2; i++ ) {
+ Node ac = a.getKind()==kind::STRING_CONCAT ? a[i==0 ? 0 : a.getNumChildren()-1] : a;
+ Node bc = b.getKind()==kind::STRING_CONCAT ? b[i==0 ? 0 : b.getNumChildren()-1] : b;
+ if( ac.isConst() && bc.isConst() ){
+ CVC4::String as = ac.getConst<String>();
+ CVC4::String bs = bc.getConst<String>();
+ int slen = as.size() > bs.size() ? bs.size() : as.size();
+ bool flag = i == 1 ? as.rstrncmp(bs, slen): as.strncmp(bs, slen);
+ if(!flag) {
+ return true;
+ }
+ }
+ }
+ }
+ if( hasTerm( a ) && hasTerm( b ) ) {
+ if( d_equalityEngine.areDisequal( a, b, false ) ){
+ return true;
+ }
+ }
+ return false;
+ }
}
Node TheoryStrings::getLengthTerm( Node t ) {
- EqcInfo * ei = getOrMakeEqcInfo( t, false );
- Node length_term = ei ? ei->d_length_term : Node::null();
- if( length_term.isNull()) {
- //typically shouldnt be necessary
- length_term = t;
- }
- Debug("strings") << "TheoryStrings::getLengthTerm" << t << std::endl;
- return length_term;
+ EqcInfo * ei = getOrMakeEqcInfo( t, false );
+ Node length_term = ei ? ei->d_length_term : Node::null();
+ if( length_term.isNull()) {
+ //typically shouldnt be necessary
+ length_term = t;
+ }
+ Debug("strings") << "TheoryStrings::getLengthTerm" << t << std::endl;
+ return length_term;
}
Node TheoryStrings::getLength( Node t ) {
- Node retNode;
- if(t.isConst()) {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t );
- } else {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, getLengthTerm( t ) );
- }
- return Rewriter::rewrite( retNode );
+ Node retNode;
+ if(t.isConst()) {
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t );
+ } else {
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, getLengthTerm( t ) );
+ }
+ return Rewriter::rewrite( retNode );
}
void TheoryStrings::setMasterEqualityEngine(eq::EqualityEngine* eq) {
}
Debug("strings-explain-debug") << "Explanation for " << literal << " was " << std::endl;
for( unsigned i=ps; i<assumptions.size(); i++ ){
- Debug("strings-explain-debug") << " " << assumptions[i] << std::endl;
+ Debug("strings-explain-debug") << " " << assumptions[i] << std::endl;
}
}
void TheoryStrings::presolve() {
- Trace("strings-presolve") << "TheoryStrings::Presolving : get fmf options " << (options::stringFMF() ? "true" : "false") << std::endl;
- d_opt_fmf = options::stringFMF();
+ Trace("strings-presolve") << "TheoryStrings::Presolving : get fmf options " << (options::stringFMF() ? "true" : "false") << std::endl;
+ d_opt_fmf = options::stringFMF();
}
void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
- Trace("strings-model") << "TheoryStrings : Collect model info, fullModel = " << fullModel << std::endl;
- Trace("strings-model") << "TheoryStrings : assertEqualityEngine." << std::endl;
- m->assertEqualityEngine( &d_equalityEngine );
+ Trace("strings-model") << "TheoryStrings : Collect model info, fullModel = " << fullModel << std::endl;
+ Trace("strings-model") << "TheoryStrings : assertEqualityEngine." << std::endl;
+ m->assertEqualityEngine( &d_equalityEngine );
// Generate model
- std::vector< Node > nodes;
- getEquivalenceClasses( nodes );
- std::map< Node, Node > processed;
- std::vector< std::vector< Node > > col;
- std::vector< Node > lts;
- separateByLength( nodes, col, lts );
- //step 1 : get all values for known lengths
- std::vector< Node > lts_values;
- std::map< unsigned, bool > values_used;
- for( unsigned i=0; i<col.size(); i++ ){
- Trace("strings-model") << "Checking length for {";
- for( unsigned j=0; j<col[i].size(); j++ ){
- if( j>0 ) Trace("strings-model") << ", ";
- Trace("strings-model") << col[i][j];
- }
- Trace("strings-model") << " } (length is " << lts[i] << ")" << std::endl;
- if( lts[i].isConst() ){
- lts_values.push_back( lts[i] );
- unsigned lvalue = lts[i].getConst<Rational>().getNumerator().toUnsignedInt();
- values_used[ lvalue ] = true;
- }else{
- //get value for lts[i];
- if( !lts[i].isNull() ){
- Node v = d_valuation.getModelValue(lts[i]);
- Trace("strings-model") << "Model value for " << lts[i] << " is " << v << std::endl;
- lts_values.push_back( v );
- unsigned lvalue = v.getConst<Rational>().getNumerator().toUnsignedInt();
- values_used[ lvalue ] = true;
- }else{
- //Trace("strings-model-warn") << "No length for eqc " << col[i][0] << std::endl;
- //Assert( false );
- lts_values.push_back( Node::null() );
- }
- }
- }
- ////step 2 : assign arbitrary values for unknown lengths?
- // confirmed by calculus invariant, see paper
- //for( unsigned i=0; i<col.size(); i++ ){
- // if(
- //}
- Trace("strings-model") << "Assign to equivalence classes..." << std::endl;
- //step 3 : assign values to equivalence classes that are pure variables
- for( unsigned i=0; i<col.size(); i++ ){
- std::vector< Node > pure_eq;
- Trace("strings-model") << "The equivalence classes ";
- for( unsigned j=0; j<col[i].size(); j++ ) {
- Trace("strings-model") << col[i][j] << " ";
- //check if col[i][j] has only variables
- EqcInfo* ei = getOrMakeEqcInfo( col[i][j], false );
+ std::vector< Node > nodes;
+ getEquivalenceClasses( nodes );
+ std::map< Node, Node > processed;
+ std::vector< std::vector< Node > > col;
+ std::vector< Node > lts;
+ separateByLength( nodes, col, lts );
+ //step 1 : get all values for known lengths
+ std::vector< Node > lts_values;
+ std::map< unsigned, bool > values_used;
+ for( unsigned i=0; i<col.size(); i++ ){
+ Trace("strings-model") << "Checking length for {";
+ for( unsigned j=0; j<col[i].size(); j++ ){
+ if( j>0 ) Trace("strings-model") << ", ";
+ Trace("strings-model") << col[i][j];
+ }
+ Trace("strings-model") << " } (length is " << lts[i] << ")" << std::endl;
+ if( lts[i].isConst() ){
+ lts_values.push_back( lts[i] );
+ unsigned lvalue = lts[i].getConst<Rational>().getNumerator().toUnsignedInt();
+ values_used[ lvalue ] = true;
+ }else{
+ //get value for lts[i];
+ if( !lts[i].isNull() ){
+ Node v = d_valuation.getModelValue(lts[i]);
+ Trace("strings-model") << "Model value for " << lts[i] << " is " << v << std::endl;
+ lts_values.push_back( v );
+ unsigned lvalue = v.getConst<Rational>().getNumerator().toUnsignedInt();
+ values_used[ lvalue ] = true;
+ }else{
+ //Trace("strings-model-warn") << "No length for eqc " << col[i][0] << std::endl;
+ //Assert( false );
+ lts_values.push_back( Node::null() );
+ }
+ }
+ }
+ ////step 2 : assign arbitrary values for unknown lengths?
+ // confirmed by calculus invariant, see paper
+ //for( unsigned i=0; i<col.size(); i++ ){
+ // if(
+ //}
+ Trace("strings-model") << "Assign to equivalence classes..." << std::endl;
+ //step 3 : assign values to equivalence classes that are pure variables
+ for( unsigned i=0; i<col.size(); i++ ){
+ std::vector< Node > pure_eq;
+ Trace("strings-model") << "The equivalence classes ";
+ for( unsigned j=0; j<col[i].size(); j++ ) {
+ Trace("strings-model") << col[i][j] << " ";
+ //check if col[i][j] has only variables
+ EqcInfo* ei = getOrMakeEqcInfo( col[i][j], false );
Node cst = ei ? ei->d_const_term : Node::null();
- if( cst.isNull() ){
- Assert( d_normal_forms.find( col[i][j] )!=d_normal_forms.end() );
- if( d_normal_forms[col[i][j]].size()==1 ){//&& d_normal_forms[col[i][j]][0]==col[i][j] ){
- pure_eq.push_back( col[i][j] );
- }
- }else{
- processed[col[i][j]] = cst;
- }
- }
- Trace("strings-model") << "have length " << lts_values[i] << std::endl;
-
- //assign a new length if necessary
- if( !pure_eq.empty() ){
- if( lts_values[i].isNull() ){
- unsigned lvalue = 0;
- while( values_used.find( lvalue )!=values_used.end() ){
- lvalue++;
- }
- Trace("strings-model") << "*** Decide to make length of " << lvalue << std::endl;
- lts_values[i] = NodeManager::currentNM()->mkConst( Rational( lvalue ) );
- values_used[ lvalue ] = true;
- }
- Trace("strings-model") << "Need to assign values of length " << lts_values[i] << " to equivalence classes ";
- for( unsigned j=0; j<pure_eq.size(); j++ ){
- Trace("strings-model") << pure_eq[j] << " ";
- }
- Trace("strings-model") << std::endl;
-
-
- //use type enumerator
- StringEnumeratorLength sel(lts_values[i].getConst<Rational>().getNumerator().toUnsignedInt());
- for( unsigned j=0; j<pure_eq.size(); j++ ){
- Assert( !sel.isFinished() );
- Node c = *sel;
- while( d_equalityEngine.hasTerm( c ) ){
- ++sel;
- Assert( !sel.isFinished() );
- c = *sel;
- }
- ++sel;
- Trace("strings-model") << "*** Assigned constant " << c << " for " << pure_eq[j] << std::endl;
- processed[pure_eq[j]] = c;
- m->assertEquality( pure_eq[j], c, true );
- }
- }
- }
- Trace("strings-model") << "String Model : Pure Assigned." << std::endl;
- //step 4 : assign constants to all other equivalence classes
- for( unsigned i=0; i<nodes.size(); i++ ){
- if( processed.find( nodes[i] )==processed.end() ){
- Assert( d_normal_forms.find( nodes[i] )!=d_normal_forms.end() );
- Trace("strings-model") << "Construct model for " << nodes[i] << " based on normal form ";
- for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
- if( j>0 ) Trace("strings-model") << " ++ ";
- Trace("strings-model") << d_normal_forms[nodes[i]][j];
- Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
- if( !r.isConst() && processed.find( r )==processed.end() ){
- Trace("strings-model") << "(UNPROCESSED)";
- }
- }
- Trace("strings-model") << std::endl;
- std::vector< Node > nc;
- for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
- Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
- Assert( r.isConst() || processed.find( r )!=processed.end() );
- nc.push_back(r.isConst() ? r : processed[r]);
- }
- Node cc = mkConcat( nc );
- Assert( cc.getKind()==kind::CONST_STRING );
- Trace("strings-model") << "*** Determined constant " << cc << " for " << nodes[i] << std::endl;
- processed[nodes[i]] = cc;
- m->assertEquality( nodes[i], cc, true );
- }
- }
- Trace("strings-model") << "String Model : Assigned." << std::endl;
- //check for negative contains
- /*
- Trace("strings-model") << "String Model : Check Neg Contains, size = " << d_str_neg_ctn.size() << std::endl;
- for( unsigned i=0; i<d_str_neg_ctn.size(); i++ ) {
- Node x = d_str_neg_ctn[i][0];
- Node y = d_str_neg_ctn[i][1];
- Trace("strings-model") << "String Model : Check Neg contains: ~contains(" << x << ", " << y << ")." << std::endl;
- //Node xv = m->getValue(x);
- //Node yv = m->getValue(y);
- //Trace("strings-model") << "String Model : Check Neg contains Value: ~contains(" << xv << ", " << yv << ")." << std::endl;
- }
- */
- Trace("strings-model") << "String Model : Finished." << std::endl;
+ if( cst.isNull() ){
+ Assert( d_normal_forms.find( col[i][j] )!=d_normal_forms.end() );
+ if( d_normal_forms[col[i][j]].size()==1 ){//&& d_normal_forms[col[i][j]][0]==col[i][j] ){
+ pure_eq.push_back( col[i][j] );
+ }
+ }else{
+ processed[col[i][j]] = cst;
+ }
+ }
+ Trace("strings-model") << "have length " << lts_values[i] << std::endl;
+
+ //assign a new length if necessary
+ if( !pure_eq.empty() ){
+ if( lts_values[i].isNull() ){
+ unsigned lvalue = 0;
+ while( values_used.find( lvalue )!=values_used.end() ){
+ lvalue++;
+ }
+ Trace("strings-model") << "*** Decide to make length of " << lvalue << std::endl;
+ lts_values[i] = NodeManager::currentNM()->mkConst( Rational( lvalue ) );
+ values_used[ lvalue ] = true;
+ }
+ Trace("strings-model") << "Need to assign values of length " << lts_values[i] << " to equivalence classes ";
+ for( unsigned j=0; j<pure_eq.size(); j++ ){
+ Trace("strings-model") << pure_eq[j] << " ";
+ }
+ Trace("strings-model") << std::endl;
+
+
+ //use type enumerator
+ StringEnumeratorLength sel(lts_values[i].getConst<Rational>().getNumerator().toUnsignedInt());
+ for( unsigned j=0; j<pure_eq.size(); j++ ){
+ Assert( !sel.isFinished() );
+ Node c = *sel;
+ while( d_equalityEngine.hasTerm( c ) ){
+ ++sel;
+ Assert( !sel.isFinished() );
+ c = *sel;
+ }
+ ++sel;
+ Trace("strings-model") << "*** Assigned constant " << c << " for " << pure_eq[j] << std::endl;
+ processed[pure_eq[j]] = c;
+ m->assertEquality( pure_eq[j], c, true );
+ }
+ }
+ }
+ Trace("strings-model") << "String Model : Pure Assigned." << std::endl;
+ //step 4 : assign constants to all other equivalence classes
+ for( unsigned i=0; i<nodes.size(); i++ ){
+ if( processed.find( nodes[i] )==processed.end() ){
+ Assert( d_normal_forms.find( nodes[i] )!=d_normal_forms.end() );
+ Trace("strings-model") << "Construct model for " << nodes[i] << " based on normal form ";
+ for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
+ if( j>0 ) Trace("strings-model") << " ++ ";
+ Trace("strings-model") << d_normal_forms[nodes[i]][j];
+ Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
+ if( !r.isConst() && processed.find( r )==processed.end() ){
+ Trace("strings-model") << "(UNPROCESSED)";
+ }
+ }
+ Trace("strings-model") << std::endl;
+ std::vector< Node > nc;
+ for( unsigned j=0; j<d_normal_forms[nodes[i]].size(); j++ ) {
+ Node r = getRepresentative( d_normal_forms[nodes[i]][j] );
+ Assert( r.isConst() || processed.find( r )!=processed.end() );
+ nc.push_back(r.isConst() ? r : processed[r]);
+ }
+ Node cc = mkConcat( nc );
+ Assert( cc.getKind()==kind::CONST_STRING );
+ Trace("strings-model") << "*** Determined constant " << cc << " for " << nodes[i] << std::endl;
+ processed[nodes[i]] = cc;
+ m->assertEquality( nodes[i], cc, true );
+ }
+ }
+ Trace("strings-model") << "String Model : Assigned." << std::endl;
+ //check for negative contains
+ /*
+ Trace("strings-model") << "String Model : Check Neg Contains, size = " << d_str_neg_ctn.size() << std::endl;
+ for( unsigned i=0; i<d_str_neg_ctn.size(); i++ ) {
+ Node x = d_str_neg_ctn[i][0];
+ Node y = d_str_neg_ctn[i][1];
+ Trace("strings-model") << "String Model : Check Neg contains: ~contains(" << x << ", " << y << ")." << std::endl;
+ //Node xv = m->getValue(x);
+ //Node yv = m->getValue(y);
+ //Trace("strings-model") << "String Model : Check Neg contains Value: ~contains(" << xv << ", " << yv << ")." << std::endl;
+ }
+ */
+ Trace("strings-model") << "String Model : Finished." << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
d_equalityEngine.addTriggerPredicate(n);
break;
case kind::STRING_SUBSTR_TOTAL: {
- Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
+ Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[0] ),
NodeManager::currentNM()->mkNode( kind::PLUS, n[1], n[2] ) );
Node t1geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, n[1], d_zero);
Node x_eq_123 = n[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, n, sk3 ) );
Node len_sk1_eq_i = n[1].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
Node lenc = n[2].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n ) );
- Node lemma = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, cond,
+ Node lemma = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, cond,
NodeManager::currentNM()->mkNode( kind::AND, x_eq_123, len_sk1_eq_i, lenc ),
n.eqNode(d_emptyString)));
Trace("strings-lemma") << "Strings::Lemma SUBSTR : " << lemma << std::endl;
TNode atom;
/*if(getLogicInfo().hasEverything()) {
- WarningOnce() << "WARNING: strings not supported in default configuration (ALL_SUPPORTED).\n"
- << "To suppress this warning in the future use proper logic symbol, e.g. (set-logic QF_S)." << std::endl;
- }
+ WarningOnce() << "WARNING: strings not supported in default configuration (ALL_SUPPORTED).\n"
+ << "To suppress this warning in the future use proper logic symbol, e.g. (set-logic QF_S)." << std::endl;
+ }
}*/
if( !done() && !hasTerm( d_emptyString ) ) {
- preRegisterTerm( d_emptyString );
+ preRegisterTerm( d_emptyString );
}
// Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
polarity = fact.getKind() != kind::NOT;
atom = polarity ? fact : fact[0];
- //must record string in regular expressions
- if ( atom.getKind() == kind::STRING_IN_REGEXP ) {
- addMembership(assertion);
- d_equalityEngine.assertPredicate(atom, polarity, fact);
- } else if (atom.getKind() == kind::STRING_STRCTN) {
- if(polarity) {
- d_str_pos_ctn.push_back( atom );
- } else {
- d_str_neg_ctn.push_back( atom );
- }
- d_equalityEngine.assertPredicate(atom, polarity, fact);
+ //must record string in regular expressions
+ if ( atom.getKind() == kind::STRING_IN_REGEXP ) {
+ addMembership(assertion);
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
+ } else if (atom.getKind() == kind::STRING_STRCTN) {
+ if(polarity) {
+ d_str_pos_ctn.push_back( atom );
+ } else {
+ d_str_neg_ctn.push_back( atom );
+ }
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
} else if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.assertEquality(atom, polarity, fact);
+ d_equalityEngine.assertEquality(atom, polarity, fact);
} else {
- d_equalityEngine.assertPredicate(atom, polarity, fact);
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
}
}
doPendingFacts();
bool addedLemma = false;
if( e == EFFORT_FULL && !d_conflict ) {
- addedLemma = checkSimple();
- Trace("strings-process") << "Done simple checking, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !addedLemma ) {
- addedLemma = checkNormalForms();
- Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkLengthsEqc();
- Trace("strings-process") << "Done check lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkContains();
- Trace("strings-process") << "Done check contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !d_conflict && !addedLemma ) {
- addedLemma = checkMemberships();
- Trace("strings-process") << "Done check membership constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !d_conflict && !addedLemma ) {
- addedLemma = checkCardinality();
- Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- }
- }
- }
- }
- }
+ addedLemma = checkSimple();
+ Trace("strings-process") << "Done simple checking, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !addedLemma ) {
+ addedLemma = checkNormalForms();
+ Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkLengthsEqc();
+ Trace("strings-process") << "Done check lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkContains();
+ Trace("strings-process") << "Done check contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !d_conflict && !addedLemma ) {
+ addedLemma = checkMemberships();
+ Trace("strings-process") << "Done check membership constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !d_conflict && !addedLemma ) {
+ addedLemma = checkCardinality();
+ Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ }
+ }
+ }
+ }
}
Trace("strings-check") << "Theory of strings, done check : " << e << std::endl;
Trace("strings-process") << "Theory of strings, done check : " << e << std::endl;
/** Conflict when merging two constants */
void TheoryStrings::conflict(TNode a, TNode b){
if( !d_conflict ){
- Trace("strings-conflict-debug") << "Making conflict..." << std::endl;
- d_conflict = true;
- Node conflictNode;
- if (a.getKind() == kind::CONST_BOOLEAN) {
- conflictNode = explain( a.iffNode(b) );
- } else {
- conflictNode = explain( a.eqNode(b) );
- }
- Trace("strings-conflict") << "CONFLICT: Eq engine conflict : " << conflictNode << std::endl;
- d_out->conflict( conflictNode );
+ Trace("strings-conflict-debug") << "Making conflict..." << std::endl;
+ d_conflict = true;
+ Node conflictNode;
+ if (a.getKind() == kind::CONST_BOOLEAN) {
+ conflictNode = explain( a.iffNode(b) );
+ } else {
+ conflictNode = explain( a.eqNode(b) );
+ }
+ Trace("strings-conflict") << "CONFLICT: Eq engine conflict : " << conflictNode << std::endl;
+ d_out->conflict( conflictNode );
}
}
}
void TheoryStrings::doPendingLemmas() {
if( !d_conflict && !d_lemma_cache.empty() ){
- for( unsigned i=0; i<d_lemma_cache.size(); i++ ){
- Trace("strings-pending") << "Process pending lemma : " << d_lemma_cache[i] << std::endl;
- d_out->lemma( d_lemma_cache[i] );
- }
- for( std::map< Node, bool >::iterator it = d_pending_req_phase.begin(); it != d_pending_req_phase.end(); ++it ){
+ for( unsigned i=0; i<d_lemma_cache.size(); i++ ){
+ Trace("strings-pending") << "Process pending lemma : " << d_lemma_cache[i] << std::endl;
+ d_out->lemma( d_lemma_cache[i] );
+ }
+ for( std::map< Node, bool >::iterator it = d_pending_req_phase.begin(); it != d_pending_req_phase.end(); ++it ){
Trace("strings-pending") << "Require phase : " << it->first << ", polarity = " << it->second << std::endl;
d_out->requirePhase( it->first, it->second );
- }
+ }
}
d_lemma_cache.clear();
d_pending_req_phase.clear();
bool TheoryStrings::getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
std::vector< std::vector< Node > > &normal_forms, std::vector< std::vector< Node > > &normal_forms_exp, std::vector< Node > &normal_form_src) {
- Trace("strings-process-debug") << "Get normal forms " << eqc << std::endl;
- // EqcItr
- eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
- while( !eqc_i.isFinished() ) {
- Node n = (*eqc_i);
- if( n.getKind() == kind::CONST_STRING || n.getKind() == kind::STRING_CONCAT ) {
- Trace("strings-process-debug") << "Get Normal Form : Process term " << n << " in eqc " << eqc << std::endl;
- std::vector<Node> nf_n;
- std::vector<Node> nf_exp_n;
- bool result = true;
- if( n.getKind() == kind::CONST_STRING ) {
- if( n!=d_emptyString ) {
- nf_n.push_back( n );
- }
- } else if( n.getKind() == kind::STRING_CONCAT ) {
- for( unsigned i=0; i<n.getNumChildren(); i++ ) {
- Node nr = d_equalityEngine.getRepresentative( n[i] );
- std::vector< Node > nf_temp;
- std::vector< Node > nf_exp_temp;
- Trace("strings-process-debug") << "Normalizing subterm " << n[i] << " = " << nr << std::endl;
- bool nresult = false;
- if( nr==eqc ) {
- nf_temp.push_back( nr );
- } else {
- nresult = normalizeEquivalenceClass( nr, visited, nf_temp, nf_exp_temp );
- if( d_conflict || !d_pending.empty() || !d_lemma_cache.empty() ) {
- return true;
- }
- }
- //successfully computed normal form
- if( nf.size()!=1 || nf[0]!=d_emptyString ) {
- for( unsigned r=0; r<nf_temp.size(); r++ ) {
- if( nresult && nf_temp[r].getKind()==kind::STRING_CONCAT ){
- Trace("strings-error") << "Strings::Error: From eqc = " << eqc << ", " << n << " index " << i << ", bad normal form : ";
- for( unsigned rr=0; rr<nf_temp.size(); rr++ ) {
- Trace("strings-error") << nf_temp[rr] << " ";
- }
- Trace("strings-error") << std::endl;
- }
- Assert( !nresult || nf_temp[r].getKind()!=kind::STRING_CONCAT );
- }
- nf_n.insert( nf_n.end(), nf_temp.begin(), nf_temp.end() );
- }
- nf_exp_n.insert( nf_exp_n.end(), nf_exp_temp.begin(), nf_exp_temp.end() );
- if( nr!=n[i] ) {
- nf_exp_n.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n[i], nr ) );
- }
- if( !nresult ) {
- //Trace("strings-process-debug") << "....Caused already asserted
- for( unsigned j=i+1; j<n.getNumChildren(); j++ ) {
- if( !areEqual( n[j], d_emptyString ) ) {
- nf_n.push_back( n[j] );
- }
- }
- if( nf_n.size()>1 ) {
- result = false;
- break;
- }
- }
- }
- }
- //if not equal to self
- //if( nf_n.size()!=1 || (nf_n.size()>1 && nf_n[0]!=eqc ) ){
- if( nf_n.size()>1 || ( nf_n.size()==1 && nf_n[0].getKind()==kind::CONST_STRING ) ) {
- if( nf_n.size()>1 ) {
- Trace("strings-process-debug") << "Check for cycle lemma for normal form ";
- printConcat(nf_n,"strings-process-debug");
- Trace("strings-process-debug") << "..." << std::endl;
- for( unsigned i=0; i<nf_n.size(); i++ ) {
- //if a component is equal to whole,
- if( areEqual( nf_n[i], n ) ){
- //all others must be empty
- std::vector< Node > ant;
- if( nf_n[i]!=n ){
- ant.push_back( nf_n[i].eqNode( n ) );
- }
- ant.insert( ant.end(), nf_exp_n.begin(), nf_exp_n.end() );
- std::vector< Node > cc;
- for( unsigned j=0; j<nf_n.size(); j++ ){
- if( i!=j ){
- cc.push_back( nf_n[j].eqNode( d_emptyString ) );
- }
- }
- std::vector< Node > empty_vec;
- Node conc = cc.size()==1 ? cc[0] : NodeManager::currentNM()->mkNode( kind::AND, cc );
- sendLemma( mkExplain( ant ), conc, "CYCLE" );
- return true;
- }
- }
- }
- if( !result ) {
- Trace("strings-process-debug") << "Will have cycle lemma at higher level!!!!!!!!!!!!!!!!" << std::endl;
- //we have a normal form that will cause a component lemma at a higher level
- normal_forms.clear();
- normal_forms_exp.clear();
- normal_form_src.clear();
- }
- normal_forms.push_back(nf_n);
- normal_forms_exp.push_back(nf_exp_n);
- normal_form_src.push_back(n);
- if( !result ){
- return false;
- }
- } else {
- Node nn = nf_n.size()==0 ? d_emptyString : nf_n[0];
- //Assert( areEqual( nf_n[0], eqc ) );
- if( !areEqual( nn, eqc ) ){
- std::vector< Node > ant;
- ant.insert( ant.end(), nf_exp_n.begin(), nf_exp_n.end() );
- ant.push_back( n.eqNode( eqc ) );
- Node conc = nn.eqNode( eqc );
- sendLemma( mkExplain( ant ), conc, "CYCLE-T" );
- return true;
- }
- }
- //}
- }
- ++eqc_i;
- }
+ Trace("strings-process-debug") << "Get normal forms " << eqc << std::endl;
+ // EqcItr
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ) {
+ Node n = (*eqc_i);
+ if( n.getKind() == kind::CONST_STRING || n.getKind() == kind::STRING_CONCAT ) {
+ Trace("strings-process-debug") << "Get Normal Form : Process term " << n << " in eqc " << eqc << std::endl;
+ std::vector<Node> nf_n;
+ std::vector<Node> nf_exp_n;
+ bool result = true;
+ if( n.getKind() == kind::CONST_STRING ) {
+ if( n!=d_emptyString ) {
+ nf_n.push_back( n );
+ }
+ } else if( n.getKind() == kind::STRING_CONCAT ) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node nr = d_equalityEngine.getRepresentative( n[i] );
+ std::vector< Node > nf_temp;
+ std::vector< Node > nf_exp_temp;
+ Trace("strings-process-debug") << "Normalizing subterm " << n[i] << " = " << nr << std::endl;
+ bool nresult = false;
+ if( nr==eqc ) {
+ nf_temp.push_back( nr );
+ } else {
+ nresult = normalizeEquivalenceClass( nr, visited, nf_temp, nf_exp_temp );
+ if( d_conflict || !d_pending.empty() || !d_lemma_cache.empty() ) {
+ return true;
+ }
+ }
+ //successfully computed normal form
+ if( nf.size()!=1 || nf[0]!=d_emptyString ) {
+ for( unsigned r=0; r<nf_temp.size(); r++ ) {
+ if( nresult && nf_temp[r].getKind()==kind::STRING_CONCAT ){
+ Trace("strings-error") << "Strings::Error: From eqc = " << eqc << ", " << n << " index " << i << ", bad normal form : ";
+ for( unsigned rr=0; rr<nf_temp.size(); rr++ ) {
+ Trace("strings-error") << nf_temp[rr] << " ";
+ }
+ Trace("strings-error") << std::endl;
+ }
+ Assert( !nresult || nf_temp[r].getKind()!=kind::STRING_CONCAT );
+ }
+ nf_n.insert( nf_n.end(), nf_temp.begin(), nf_temp.end() );
+ }
+ nf_exp_n.insert( nf_exp_n.end(), nf_exp_temp.begin(), nf_exp_temp.end() );
+ if( nr!=n[i] ) {
+ nf_exp_n.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n[i], nr ) );
+ }
+ if( !nresult ) {
+ //Trace("strings-process-debug") << "....Caused already asserted
+ for( unsigned j=i+1; j<n.getNumChildren(); j++ ) {
+ if( !areEqual( n[j], d_emptyString ) ) {
+ nf_n.push_back( n[j] );
+ }
+ }
+ if( nf_n.size()>1 ) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ //if not equal to self
+ //if( nf_n.size()!=1 || (nf_n.size()>1 && nf_n[0]!=eqc ) ){
+ if( nf_n.size()>1 || ( nf_n.size()==1 && nf_n[0].getKind()==kind::CONST_STRING ) ) {
+ if( nf_n.size()>1 ) {
+ Trace("strings-process-debug") << "Check for cycle lemma for normal form ";
+ printConcat(nf_n,"strings-process-debug");
+ Trace("strings-process-debug") << "..." << std::endl;
+ for( unsigned i=0; i<nf_n.size(); i++ ) {
+ //if a component is equal to whole,
+ if( areEqual( nf_n[i], n ) ){
+ //all others must be empty
+ std::vector< Node > ant;
+ if( nf_n[i]!=n ){
+ ant.push_back( nf_n[i].eqNode( n ) );
+ }
+ ant.insert( ant.end(), nf_exp_n.begin(), nf_exp_n.end() );
+ std::vector< Node > cc;
+ for( unsigned j=0; j<nf_n.size(); j++ ){
+ if( i!=j ){
+ cc.push_back( nf_n[j].eqNode( d_emptyString ) );
+ }
+ }
+ std::vector< Node > empty_vec;
+ Node conc = cc.size()==1 ? cc[0] : NodeManager::currentNM()->mkNode( kind::AND, cc );
+ sendLemma( mkExplain( ant ), conc, "CYCLE" );
+ return true;
+ }
+ }
+ }
+ if( !result ) {
+ Trace("strings-process-debug") << "Will have cycle lemma at higher level!!!!!!!!!!!!!!!!" << std::endl;
+ //we have a normal form that will cause a component lemma at a higher level
+ normal_forms.clear();
+ normal_forms_exp.clear();
+ normal_form_src.clear();
+ }
+ normal_forms.push_back(nf_n);
+ normal_forms_exp.push_back(nf_exp_n);
+ normal_form_src.push_back(n);
+ if( !result ){
+ return false;
+ }
+ } else {
+ Node nn = nf_n.size()==0 ? d_emptyString : nf_n[0];
+ //Assert( areEqual( nf_n[0], eqc ) );
+ if( !areEqual( nn, eqc ) ){
+ std::vector< Node > ant;
+ ant.insert( ant.end(), nf_exp_n.begin(), nf_exp_n.end() );
+ ant.push_back( n.eqNode( eqc ) );
+ Node conc = nn.eqNode( eqc );
+ sendLemma( mkExplain( ant ), conc, "CYCLE-T" );
+ return true;
+ }
+ }
+ //}
+ }
+ ++eqc_i;
+ }
// Test the result
if( !normal_forms.empty() ) {
//normal_form_src.push_back(eqc);
Trace("strings-solve") << "--- Single normal form for equivalence class " << eqc << std::endl;
}
- return true;
+ return true;
}
void TheoryStrings::mergeCstVec(std::vector< Node > &vec_strings) {
- std::vector< Node >::iterator itr = vec_strings.begin();
- while(itr != vec_strings.end()) {
- if(itr->isConst()) {
- std::vector< Node >::iterator itr2 = itr + 1;
- if(itr2 == vec_strings.end()) {
- break;
- } else if(itr2->isConst()) {
- CVC4::String s1 = itr->getConst<String>();
- CVC4::String s2 = itr2->getConst<String>();
- *itr = NodeManager::currentNM()->mkConst(s1.concat(s2));
- vec_strings.erase(itr2);
- } else {
- ++itr;
- }
- } else {
- ++itr;
- }
- }
+ std::vector< Node >::iterator itr = vec_strings.begin();
+ while(itr != vec_strings.end()) {
+ if(itr->isConst()) {
+ std::vector< Node >::iterator itr2 = itr + 1;
+ if(itr2 == vec_strings.end()) {
+ break;
+ } else if(itr2->isConst()) {
+ CVC4::String s1 = itr->getConst<String>();
+ CVC4::String s2 = itr2->getConst<String>();
+ *itr = NodeManager::currentNM()->mkConst(s1.concat(s2));
+ vec_strings.erase(itr2);
+ } else {
+ ++itr;
+ }
+ } else {
+ ++itr;
+ }
+ }
}
bool TheoryStrings::detectLoop( std::vector< std::vector< Node > > &normal_forms,
int i, int j, int index_i, int index_j,
int &loop_in_i, int &loop_in_j) {
- int has_loop[2] = { -1, -1 };
- if( options::stringLB() != 2 ) {
- for( unsigned r=0; r<2; r++ ) {
- int index = (r==0 ? index_i : index_j);
- int other_index = (r==0 ? index_j : index_i );
- int n_index = (r==0 ? i : j);
- int other_n_index = (r==0 ? j : i);
- if( normal_forms[other_n_index][other_index].getKind() != kind::CONST_STRING ) {
- for( unsigned lp = index+1; lp<normal_forms[n_index].size(); lp++ ){
- if( normal_forms[n_index][lp]==normal_forms[other_n_index][other_index] ){
- has_loop[r] = lp;
- break;
- }
- }
- }
- }
- }
- if( has_loop[0]!=-1 || has_loop[1]!=-1 ) {
- loop_in_i = has_loop[0];
- loop_in_j = has_loop[1];
- return true;
- } else {
- return false;
- }
+ int has_loop[2] = { -1, -1 };
+ if( options::stringLB() != 2 ) {
+ for( unsigned r=0; r<2; r++ ) {
+ int index = (r==0 ? index_i : index_j);
+ int other_index = (r==0 ? index_j : index_i );
+ int n_index = (r==0 ? i : j);
+ int other_n_index = (r==0 ? j : i);
+ if( normal_forms[other_n_index][other_index].getKind() != kind::CONST_STRING ) {
+ for( unsigned lp = index+1; lp<normal_forms[n_index].size(); lp++ ){
+ if( normal_forms[n_index][lp]==normal_forms[other_n_index][other_index] ){
+ has_loop[r] = lp;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if( has_loop[0]!=-1 || has_loop[1]!=-1 ) {
+ loop_in_i = has_loop[0];
+ loop_in_j = has_loop[1];
+ return true;
+ } else {
+ return false;
+ }
}
//xs(zy)=t(yz)xr
bool TheoryStrings::processLoop(std::vector< Node > &antec,
std::vector< Node > &normal_form_src,
int i, int j, int loop_n_index, int other_n_index,
int loop_index, int index, int other_index) {
- Node conc;
- Trace("strings-loop") << "Detected possible loop for " << normal_forms[loop_n_index][loop_index] << std::endl;
- Trace("strings-loop") << " ... (X)= " << normal_forms[other_n_index][other_index] << std::endl;
-
- Trace("strings-loop") << " ... T(Y.Z)= ";
- std::vector< Node > vec_t;
- for(int lp=index; lp<loop_index; ++lp) {
- if(lp != index) Trace("strings-loop") << " ++ ";
- Trace("strings-loop") << normal_forms[loop_n_index][lp];
- vec_t.push_back( normal_forms[loop_n_index][lp] );
- }
- Node t_yz = mkConcat( vec_t );
- Trace("strings-loop") << " (" << t_yz << ")" << std::endl;
- Trace("strings-loop") << " ... S(Z.Y)= ";
- std::vector< Node > vec_s;
- for(int lp=other_index+1; lp<(int)normal_forms[other_n_index].size(); ++lp) {
- if(lp != other_index+1) Trace("strings-loop") << " ++ ";
- Trace("strings-loop") << normal_forms[other_n_index][lp];
- vec_s.push_back( normal_forms[other_n_index][lp] );
- }
- Node s_zy = mkConcat( vec_s );
- Trace("strings-loop") << " (" << s_zy << ")" << std::endl;
- Trace("strings-loop") << " ... R= ";
- std::vector< Node > vec_r;
- for(int lp=loop_index+1; lp<(int)normal_forms[loop_n_index].size(); ++lp) {
- if(lp != loop_index+1) Trace("strings-loop") << " ++ ";
- Trace("strings-loop") << normal_forms[loop_n_index][lp];
- vec_r.push_back( normal_forms[loop_n_index][lp] );
- }
- Node r = mkConcat( vec_r );
- Trace("strings-loop") << " (" << r << ")" << std::endl;
-
- //Trace("strings-loop") << "Lemma Cache: " << normal_form_src[i] << " vs " << normal_form_src[j] << std::endl;
- //TODO: can be more general
- if( s_zy.isConst() && r.isConst() && r != d_emptyString) {
- int c;
- bool flag = true;
- if(s_zy.getConst<String>().tailcmp( r.getConst<String>(), c ) ) {
- if(c >= 0) {
- s_zy = NodeManager::currentNM()->mkConst( s_zy.getConst<String>().substr(0, c) );
- r = d_emptyString;
- vec_r.clear();
- Trace("strings-loop") << "Strings::Loop: Refactor S(Z.Y)= " << s_zy << ", c=" << c << std::endl;
- flag = false;
- }
- }
- if(flag) {
- Trace("strings-loop") << "Strings::Loop: tails are different." << std::endl;
- Node ant = mkExplain( antec );
- sendLemma( ant, conc, "Conflict" );
- return true;
- }
- }
-
- //require that x is non-empty
- if( !areDisequal( normal_forms[loop_n_index][loop_index], d_emptyString ) ){
- //try to make normal_forms[loop_n_index][loop_index] equal to empty to avoid loop
- sendSplit( normal_forms[loop_n_index][loop_index], d_emptyString, "Loop-X-E-Split" );
- } else if( !areDisequal( t_yz, d_emptyString ) && t_yz.getKind()!=kind::CONST_STRING ) {
- //try to make normal_forms[loop_n_index][loop_index] equal to empty to avoid loop
- sendSplit( t_yz, d_emptyString, "Loop-YZ-E-SPlit" );
- } else {
- //need to break
- antec.push_back( normal_forms[loop_n_index][loop_index].eqNode( d_emptyString ).negate() );
- if( t_yz.getKind()!=kind::CONST_STRING ) {
- antec.push_back( t_yz.eqNode( d_emptyString ).negate() );
- }
- Node ant = mkExplain( antec );
- if(d_loop_antec.find(ant) == d_loop_antec.end()) {
- d_loop_antec.insert(ant);
-
- Node str_in_re;
- if( s_zy == t_yz &&
- r == d_emptyString &&
- s_zy.isConst() &&
- s_zy.getConst<String>().isRepeated()
- ) {
- Node rep_c = NodeManager::currentNM()->mkConst( s_zy.getConst<String>().substr(0, 1) );
- Trace("strings-loop") << "Special case (X)=" << normal_forms[other_n_index][other_index] << " " << std::endl;
- Trace("strings-loop") << "... (C)=" << rep_c << " " << std::endl;
- //special case
- str_in_re = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, normal_forms[other_n_index][other_index],
- NodeManager::currentNM()->mkNode( kind::REGEXP_STAR,
- NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, rep_c ) ) );
- conc = str_in_re;
- } else if(t_yz.isConst()) {
- CVC4::String s = t_yz.getConst< CVC4::String >();
- unsigned size = s.size();
- std::vector< Node > vconc;
- for(unsigned len=1; len<=size; len++) {
- Node y = NodeManager::currentNM()->mkConst(s.substr(0, len));
- Node z = NodeManager::currentNM()->mkConst(s.substr(len, size - len));
- Node restr = s_zy;
- Node cc;
- if(r != d_emptyString) {
- std::vector< Node > v2(vec_r);
- v2.insert(v2.begin(), y);
- v2.insert(v2.begin(), z);
- restr = mkConcat( z, y );
- cc = Rewriter::rewrite(s_zy.eqNode( mkConcat( v2 ) ));
- } else {
- cc = Rewriter::rewrite(s_zy.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, z, y) ));
- }
- if(cc == d_false) {
- continue;
- }
- Node conc2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, normal_forms[other_n_index][other_index],
- NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
- NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, y),
- NodeManager::currentNM()->mkNode(kind::REGEXP_STAR,
- NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, restr))));
- cc = cc==d_true ? conc2 : NodeManager::currentNM()->mkNode( kind::AND, cc, conc2 );
- d_regexp_ant[conc2] = ant;
- vconc.push_back(cc);
- }
- conc = vconc.size()==0 ? Node::null() : vconc.size()==1 ? vconc[0] : NodeManager::currentNM()->mkNode(kind::OR, vconc);
- } else {
- Trace("strings-loop") << "Strings::Loop: Normal Breaking." << std::endl;
- //right
- Node sk_w= NodeManager::currentNM()->mkSkolem( "w_loop", normal_forms[other_n_index][other_index].getType(), "created for loop detection split" );
- Node sk_y= NodeManager::currentNM()->mkSkolem( "y_loop", normal_forms[other_n_index][other_index].getType(), "created for loop detection split" );
- Node sk_z= NodeManager::currentNM()->mkSkolem( "z_loop", normal_forms[other_n_index][other_index].getType(), "created for loop detection split" );
- d_statistics.d_new_skolems += 3;
- //t1 * ... * tn = y * z
- Node conc1 = t_yz.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk_y, sk_z ) );
- // s1 * ... * sk = z * y * r
- vec_r.insert(vec_r.begin(), sk_y);
- vec_r.insert(vec_r.begin(), sk_z);
- Node conc2 = s_zy.eqNode( mkConcat( vec_r ) );
- Node conc3 = normal_forms[other_n_index][other_index].eqNode( mkConcat( sk_y, sk_w ) );
- Node restr = r == d_emptyString ? s_zy : mkConcat( sk_z, sk_y );
- str_in_re = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, sk_w,
- NodeManager::currentNM()->mkNode( kind::REGEXP_STAR,
- NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, restr ) ) );
-
- //Node sk_y_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk_y );
- //Node zz_imp_yz = NodeManager::currentNM()->mkNode( kind::IMPLIES, sk_z.eqNode(d_emptyString), sk_y.eqNode(d_emptyString));
-
- std::vector< Node > vec_conc;
- vec_conc.push_back(conc1); vec_conc.push_back(conc2); vec_conc.push_back(conc3);
- vec_conc.push_back(str_in_re);
- vec_conc.push_back(sk_y.eqNode(d_emptyString).negate());
- conc = NodeManager::currentNM()->mkNode( kind::AND, vec_conc );//, len_x_gt_len_y
- } // normal case
-
- //set its antecedant to ant, to say when it is relevant
- if(!str_in_re.isNull()) {
- d_regexp_ant[str_in_re] = ant;
- }
- sendLemma( ant, conc, "LOOP-BREAK" );
- ++(d_statistics.d_loop_lemmas);
-
- //we will be done
- addNormalFormPair( normal_form_src[i], normal_form_src[j] );
- } else {
- Trace("strings-loop") << "Strings::Loop: loop lemma for " << ant << " has already added." << std::endl;
- addNormalFormPair( normal_form_src[i], normal_form_src[j] );
- return false;
- }
- }
- return true;
+ Node conc;
+ Trace("strings-loop") << "Detected possible loop for " << normal_forms[loop_n_index][loop_index] << std::endl;
+ Trace("strings-loop") << " ... (X)= " << normal_forms[other_n_index][other_index] << std::endl;
+
+ Trace("strings-loop") << " ... T(Y.Z)= ";
+ std::vector< Node > vec_t;
+ for(int lp=index; lp<loop_index; ++lp) {
+ if(lp != index) Trace("strings-loop") << " ++ ";
+ Trace("strings-loop") << normal_forms[loop_n_index][lp];
+ vec_t.push_back( normal_forms[loop_n_index][lp] );
+ }
+ Node t_yz = mkConcat( vec_t );
+ Trace("strings-loop") << " (" << t_yz << ")" << std::endl;
+ Trace("strings-loop") << " ... S(Z.Y)= ";
+ std::vector< Node > vec_s;
+ for(int lp=other_index+1; lp<(int)normal_forms[other_n_index].size(); ++lp) {
+ if(lp != other_index+1) Trace("strings-loop") << " ++ ";
+ Trace("strings-loop") << normal_forms[other_n_index][lp];
+ vec_s.push_back( normal_forms[other_n_index][lp] );
+ }
+ Node s_zy = mkConcat( vec_s );
+ Trace("strings-loop") << " (" << s_zy << ")" << std::endl;
+ Trace("strings-loop") << " ... R= ";
+ std::vector< Node > vec_r;
+ for(int lp=loop_index+1; lp<(int)normal_forms[loop_n_index].size(); ++lp) {
+ if(lp != loop_index+1) Trace("strings-loop") << " ++ ";
+ Trace("strings-loop") << normal_forms[loop_n_index][lp];
+ vec_r.push_back( normal_forms[loop_n_index][lp] );
+ }
+ Node r = mkConcat( vec_r );
+ Trace("strings-loop") << " (" << r << ")" << std::endl;
+
+ //Trace("strings-loop") << "Lemma Cache: " << normal_form_src[i] << " vs " << normal_form_src[j] << std::endl;
+ //TODO: can be more general
+ if( s_zy.isConst() && r.isConst() && r != d_emptyString) {
+ int c;
+ bool flag = true;
+ if(s_zy.getConst<String>().tailcmp( r.getConst<String>(), c ) ) {
+ if(c >= 0) {
+ s_zy = NodeManager::currentNM()->mkConst( s_zy.getConst<String>().substr(0, c) );
+ r = d_emptyString;
+ vec_r.clear();
+ Trace("strings-loop") << "Strings::Loop: Refactor S(Z.Y)= " << s_zy << ", c=" << c << std::endl;
+ flag = false;
+ }
+ }
+ if(flag) {
+ Trace("strings-loop") << "Strings::Loop: tails are different." << std::endl;
+ Node ant = mkExplain( antec );
+ sendLemma( ant, conc, "Conflict" );
+ return true;
+ }
+ }
+
+ //require that x is non-empty
+ if( !areDisequal( normal_forms[loop_n_index][loop_index], d_emptyString ) ){
+ //try to make normal_forms[loop_n_index][loop_index] equal to empty to avoid loop
+ sendSplit( normal_forms[loop_n_index][loop_index], d_emptyString, "Loop-X-E-Split" );
+ } else if( !areDisequal( t_yz, d_emptyString ) && t_yz.getKind()!=kind::CONST_STRING ) {
+ //try to make normal_forms[loop_n_index][loop_index] equal to empty to avoid loop
+ sendSplit( t_yz, d_emptyString, "Loop-YZ-E-SPlit" );
+ } else {
+ //need to break
+ antec.push_back( normal_forms[loop_n_index][loop_index].eqNode( d_emptyString ).negate() );
+ if( t_yz.getKind()!=kind::CONST_STRING ) {
+ antec.push_back( t_yz.eqNode( d_emptyString ).negate() );
+ }
+ Node ant = mkExplain( antec );
+ if(d_loop_antec.find(ant) == d_loop_antec.end()) {
+ d_loop_antec.insert(ant);
+
+ Node str_in_re;
+ if( s_zy == t_yz &&
+ r == d_emptyString &&
+ s_zy.isConst() &&
+ s_zy.getConst<String>().isRepeated()
+ ) {
+ Node rep_c = NodeManager::currentNM()->mkConst( s_zy.getConst<String>().substr(0, 1) );
+ Trace("strings-loop") << "Special case (X)=" << normal_forms[other_n_index][other_index] << " " << std::endl;
+ Trace("strings-loop") << "... (C)=" << rep_c << " " << std::endl;
+ //special case
+ str_in_re = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, normal_forms[other_n_index][other_index],
+ NodeManager::currentNM()->mkNode( kind::REGEXP_STAR,
+ NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, rep_c ) ) );
+ conc = str_in_re;
+ } else if(t_yz.isConst()) {
+ CVC4::String s = t_yz.getConst< CVC4::String >();
+ unsigned size = s.size();
+ std::vector< Node > vconc;
+ for(unsigned len=1; len<=size; len++) {
+ Node y = NodeManager::currentNM()->mkConst(s.substr(0, len));
+ Node z = NodeManager::currentNM()->mkConst(s.substr(len, size - len));
+ Node restr = s_zy;
+ Node cc;
+ if(r != d_emptyString) {
+ std::vector< Node > v2(vec_r);
+ v2.insert(v2.begin(), y);
+ v2.insert(v2.begin(), z);
+ restr = mkConcat( z, y );
+ cc = Rewriter::rewrite(s_zy.eqNode( mkConcat( v2 ) ));
+ } else {
+ cc = Rewriter::rewrite(s_zy.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, z, y) ));
+ }
+ if(cc == d_false) {
+ continue;
+ }
+ Node conc2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, normal_forms[other_n_index][other_index],
+ NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
+ NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, y),
+ NodeManager::currentNM()->mkNode(kind::REGEXP_STAR,
+ NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, restr))));
+ cc = cc==d_true ? conc2 : NodeManager::currentNM()->mkNode( kind::AND, cc, conc2 );
+ d_regexp_ant[conc2] = ant;
+ vconc.push_back(cc);
+ }
+ conc = vconc.size()==0 ? Node::null() : vconc.size()==1 ? vconc[0] : NodeManager::currentNM()->mkNode(kind::OR, vconc);
+ } else {
+ Trace("strings-loop") << "Strings::Loop: Normal Breaking." << std::endl;
+ //right
+ Node sk_w= NodeManager::currentNM()->mkSkolem( "w_loop", normal_forms[other_n_index][other_index].getType(), "created for loop detection split" );
+ Node sk_y= NodeManager::currentNM()->mkSkolem( "y_loop", normal_forms[other_n_index][other_index].getType(), "created for loop detection split" );
+ Node sk_z= NodeManager::currentNM()->mkSkolem( "z_loop", normal_forms[other_n_index][other_index].getType(), "created for loop detection split" );
+ d_statistics.d_new_skolems += 3;
+ //t1 * ... * tn = y * z
+ Node conc1 = t_yz.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk_y, sk_z ) );
+ // s1 * ... * sk = z * y * r
+ vec_r.insert(vec_r.begin(), sk_y);
+ vec_r.insert(vec_r.begin(), sk_z);
+ Node conc2 = s_zy.eqNode( mkConcat( vec_r ) );
+ Node conc3 = normal_forms[other_n_index][other_index].eqNode( mkConcat( sk_y, sk_w ) );
+ Node restr = r == d_emptyString ? s_zy : mkConcat( sk_z, sk_y );
+ str_in_re = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, sk_w,
+ NodeManager::currentNM()->mkNode( kind::REGEXP_STAR,
+ NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, restr ) ) );
+
+ //Node sk_y_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk_y );
+ //Node zz_imp_yz = NodeManager::currentNM()->mkNode( kind::IMPLIES, sk_z.eqNode(d_emptyString), sk_y.eqNode(d_emptyString));
+
+ std::vector< Node > vec_conc;
+ vec_conc.push_back(conc1); vec_conc.push_back(conc2); vec_conc.push_back(conc3);
+ vec_conc.push_back(str_in_re);
+ vec_conc.push_back(sk_y.eqNode(d_emptyString).negate());
+ conc = NodeManager::currentNM()->mkNode( kind::AND, vec_conc );//, len_x_gt_len_y
+ } // normal case
+
+ //set its antecedant to ant, to say when it is relevant
+ if(!str_in_re.isNull()) {
+ d_regexp_ant[str_in_re] = ant;
+ }
+ sendLemma( ant, conc, "LOOP-BREAK" );
+ ++(d_statistics.d_loop_lemmas);
+
+ //we will be done
+ addNormalFormPair( normal_form_src[i], normal_form_src[j] );
+ } else {
+ Trace("strings-loop") << "Strings::Loop: loop lemma for " << ant << " has already added." << std::endl;
+ addNormalFormPair( normal_form_src[i], normal_form_src[j] );
+ return false;
+ }
+ }
+ return true;
}
bool TheoryStrings::processNEqc(std::vector< std::vector< Node > > &normal_forms,
std::vector< std::vector< Node > > &normal_forms_exp,
std::vector< Node > &normal_form_src) {
- bool flag_lb = false;
- std::vector< Node > c_lb_exp;
- int c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index, c_other_index;
- for(unsigned i=0; i<normal_forms.size()-1; i++) {
- //unify each normalform[j] with normal_forms[i]
- for(unsigned j=i+1; j<normal_forms.size(); j++ ) {
- Trace("strings-solve") << "Strings: Process normal form #" << i << " against #" << j << "..." << std::endl;
- if( isNormalFormPair( normal_form_src[i], normal_form_src[j] ) ) {
- Trace("strings-solve") << "Strings: Already cached." << std::endl;
- } else {
- //the current explanation for why the prefix is equal
- std::vector< Node > curr_exp;
- curr_exp.insert(curr_exp.end(), normal_forms_exp[i].begin(), normal_forms_exp[i].end() );
- curr_exp.insert(curr_exp.end(), normal_forms_exp[j].begin(), normal_forms_exp[j].end() );
- curr_exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, normal_form_src[i], normal_form_src[j] ) );
-
- //process the reverse direction first (check for easy conflicts and inferences)
- if( processReverseNEq( normal_forms, normal_form_src, curr_exp, i, j ) ){
- return true;
- }
-
- //ensure that normal_forms[i] and normal_forms[j] are the same modulo equality
- unsigned index_i = 0;
- unsigned index_j = 0;
- bool success;
- do
- {
- //simple check
- if( processSimpleNEq( normal_forms, normal_form_src, curr_exp, i, j, index_i, index_j, false ) ){
- //added a lemma, return
- return true;
- }
-
- success = false;
- //if we are at the end
- if(index_i==normal_forms[i].size() || index_j==normal_forms[j].size() ) {
- Assert( index_i==normal_forms[i].size() && index_j==normal_forms[j].size() );
- //we're done
- //addNormalFormPair( normal_form_src[i], normal_form_src[j] );
- } else {
- Node length_term_i = getLength( normal_forms[i][index_i] );
- Node length_term_j = getLength( normal_forms[j][index_j] );
- //check length(normal_forms[i][index]) == length(normal_forms[j][index])
- if( !areDisequal(length_term_i, length_term_j) &&
- !areEqual(length_term_i, length_term_j) &&
- normal_forms[i][index_i].getKind()!=kind::CONST_STRING &&
- normal_forms[j][index_j].getKind()!=kind::CONST_STRING ) {
- //length terms are equal, merge equivalence classes if not already done so
- Node length_eq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j );
- Trace("strings-solve-debug") << "Non-simple Case 1 : string lengths neither equal nor disequal" << std::endl;
- //try to make the lengths equal via splitting on demand
- sendSplit( length_term_i, length_term_j, "Length" );
- length_eq = Rewriter::rewrite( length_eq );
- d_pending_req_phase[ length_eq ] = true;
- return true;
- } else {
- Trace("strings-solve-debug") << "Non-simple Case 2 : must compare strings" << std::endl;
- int loop_in_i = -1;
- int loop_in_j = -1;
- if(detectLoop(normal_forms, i, j, index_i, index_j, loop_in_i, loop_in_j)) {
- if(!flag_lb) {
- c_i = i;
- c_j = j;
- c_loop_n_index = loop_in_i!=-1 ? i : j;
- c_other_n_index = loop_in_i!=-1 ? j : i;
- c_loop_index = loop_in_i!=-1 ? loop_in_i : loop_in_j;
- c_index = loop_in_i!=-1 ? index_i : index_j;
- c_other_index = loop_in_i!=-1 ? index_j : index_i;
-
- c_lb_exp = curr_exp;
-
- if(options::stringLB() == 0) {
- flag_lb = true;
- } else {
- if(processLoop(c_lb_exp, normal_forms, normal_form_src,
- c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index, c_other_index)) {
- return true;
- }
- }
- }
- } else {
- Node conc;
- std::vector< Node > antec;
- Trace("strings-solve-debug") << "No loops detected." << std::endl;
- if( normal_forms[i][index_i].getKind() == kind::CONST_STRING ||
- normal_forms[j][index_j].getKind() == kind::CONST_STRING) {
- unsigned const_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? i : j;
- unsigned const_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_i : index_j;
- unsigned nconst_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? j : i;
- unsigned nconst_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_j : index_i;
- Node const_str = normal_forms[const_k][const_index_k];
- Node other_str = normal_forms[nconst_k][nconst_index_k];
- Assert( other_str.getKind()!=kind::CONST_STRING, "Other string is not constant." );
- Assert( other_str.getKind()!=kind::STRING_CONCAT, "Other string is not CONCAT." );
- antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
- //Opt
- bool optflag = false;
- if( normal_forms[nconst_k].size() > nconst_index_k + 1 &&
- normal_forms[nconst_k][nconst_index_k + 1].isConst() ) {
- CVC4::String stra = const_str.getConst<String>();
- CVC4::String strb = normal_forms[nconst_k][nconst_index_k + 1].getConst<String>();
- CVC4::String fc = strb.substr(0, 1);
- if( stra.find(fc) == std::string::npos ||
- (stra.find(strb) == std::string::npos &&
- !stra.overlap(strb)) ) {
- Node sk = NodeManager::currentNM()->mkSkolem( "sopt", NodeManager::currentNM()->stringType(), "created for string sp" );
- Node eq = other_str.eqNode( mkConcat(const_str, sk) );
- Node ant = mkExplain( antec );
- sendLemma(ant, eq, "CST-EPS");
- optflag = true;
- }
- }
- if(!optflag){
- Node firstChar = const_str.getConst<String>().size() == 1 ? const_str :
- NodeManager::currentNM()->mkConst( const_str.getConst<String>().substr(0, 1) );
- //split the string
- Node eq1 = Rewriter::rewrite( other_str.eqNode( d_emptyString ) );
- Node eq2 = mkSplitEq( "c_spt", "created for v/c split", other_str, firstChar, false );
- d_pending_req_phase[ eq1 ] = true;
- conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
- Trace("strings-solve-debug") << "Break normal form constant/variable " << std::endl;
-
- Node ant = mkExplain( antec );
- sendLemma( ant, conc, "CST-SPLIT" );
- ++(d_statistics.d_eq_splits);
- }
- return true;
- } else {
- std::vector< Node > antec_new_lits;
- antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
-
- Node ldeq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ).negate();
- if( d_equalityEngine.areDisequal( length_term_i, length_term_j, true ) ){
- antec.push_back( ldeq );
- }else{
- antec_new_lits.push_back(ldeq);
- }
-
- //x!=e /\ y!=e
- for(unsigned xory=0; xory<2; xory++) {
- Node x = xory==0 ? normal_forms[i][index_i] : normal_forms[j][index_j];
- Node xgtz = x.eqNode( d_emptyString ).negate();
- if( d_equalityEngine.areDisequal( x, d_emptyString, true ) ) {
- antec.push_back( xgtz );
- } else {
- antec_new_lits.push_back( xgtz );
- }
- }
-
- Node eq1 = mkSplitEq( "v_spt_l", "created for v/v split", normal_forms[i][index_i], normal_forms[j][index_j], true );
- Node eq2 = mkSplitEq( "v_spt_r", "created for v/v split", normal_forms[j][index_j], normal_forms[i][index_i], true );
- conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
-
- Node ant = mkExplain( antec, antec_new_lits );
- sendLemma( ant, conc, "VAR-SPLIT" );
- ++(d_statistics.d_eq_splits);
- return true;
- }
- }
- }
- }
- } while(success);
- }
- }
- if(!flag_lb) {
- return false;
- }
- }
- if(flag_lb) {
- if(processLoop(c_lb_exp, normal_forms, normal_form_src,
- c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index, c_other_index)) {
- return true;
- }
- }
-
- return false;
+ bool flag_lb = false;
+ std::vector< Node > c_lb_exp;
+ int c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index, c_other_index;
+ for(unsigned i=0; i<normal_forms.size()-1; i++) {
+ //unify each normalform[j] with normal_forms[i]
+ for(unsigned j=i+1; j<normal_forms.size(); j++ ) {
+ Trace("strings-solve") << "Strings: Process normal form #" << i << " against #" << j << "..." << std::endl;
+ if( isNormalFormPair( normal_form_src[i], normal_form_src[j] ) ) {
+ Trace("strings-solve") << "Strings: Already cached." << std::endl;
+ } else {
+ //the current explanation for why the prefix is equal
+ std::vector< Node > curr_exp;
+ curr_exp.insert(curr_exp.end(), normal_forms_exp[i].begin(), normal_forms_exp[i].end() );
+ curr_exp.insert(curr_exp.end(), normal_forms_exp[j].begin(), normal_forms_exp[j].end() );
+ curr_exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, normal_form_src[i], normal_form_src[j] ) );
+
+ //process the reverse direction first (check for easy conflicts and inferences)
+ if( processReverseNEq( normal_forms, normal_form_src, curr_exp, i, j ) ){
+ return true;
+ }
+
+ //ensure that normal_forms[i] and normal_forms[j] are the same modulo equality
+ unsigned index_i = 0;
+ unsigned index_j = 0;
+ bool success;
+ do
+ {
+ //simple check
+ if( processSimpleNEq( normal_forms, normal_form_src, curr_exp, i, j, index_i, index_j, false ) ){
+ //added a lemma, return
+ return true;
+ }
+
+ success = false;
+ //if we are at the end
+ if(index_i==normal_forms[i].size() || index_j==normal_forms[j].size() ) {
+ Assert( index_i==normal_forms[i].size() && index_j==normal_forms[j].size() );
+ //we're done
+ //addNormalFormPair( normal_form_src[i], normal_form_src[j] );
+ } else {
+ Node length_term_i = getLength( normal_forms[i][index_i] );
+ Node length_term_j = getLength( normal_forms[j][index_j] );
+ //check length(normal_forms[i][index]) == length(normal_forms[j][index])
+ if( !areDisequal(length_term_i, length_term_j) &&
+ !areEqual(length_term_i, length_term_j) &&
+ normal_forms[i][index_i].getKind()!=kind::CONST_STRING &&
+ normal_forms[j][index_j].getKind()!=kind::CONST_STRING ) {
+ //length terms are equal, merge equivalence classes if not already done so
+ Node length_eq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j );
+ Trace("strings-solve-debug") << "Non-simple Case 1 : string lengths neither equal nor disequal" << std::endl;
+ //try to make the lengths equal via splitting on demand
+ sendSplit( length_term_i, length_term_j, "Length" );
+ length_eq = Rewriter::rewrite( length_eq );
+ d_pending_req_phase[ length_eq ] = true;
+ return true;
+ } else {
+ Trace("strings-solve-debug") << "Non-simple Case 2 : must compare strings" << std::endl;
+ int loop_in_i = -1;
+ int loop_in_j = -1;
+ if(detectLoop(normal_forms, i, j, index_i, index_j, loop_in_i, loop_in_j)) {
+ if(!flag_lb) {
+ c_i = i;
+ c_j = j;
+ c_loop_n_index = loop_in_i!=-1 ? i : j;
+ c_other_n_index = loop_in_i!=-1 ? j : i;
+ c_loop_index = loop_in_i!=-1 ? loop_in_i : loop_in_j;
+ c_index = loop_in_i!=-1 ? index_i : index_j;
+ c_other_index = loop_in_i!=-1 ? index_j : index_i;
+
+ c_lb_exp = curr_exp;
+
+ if(options::stringLB() == 0) {
+ flag_lb = true;
+ } else {
+ if(processLoop(c_lb_exp, normal_forms, normal_form_src,
+ c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index, c_other_index)) {
+ return true;
+ }
+ }
+ }
+ } else {
+ Node conc;
+ std::vector< Node > antec;
+ Trace("strings-solve-debug") << "No loops detected." << std::endl;
+ if( normal_forms[i][index_i].getKind() == kind::CONST_STRING ||
+ normal_forms[j][index_j].getKind() == kind::CONST_STRING) {
+ unsigned const_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? i : j;
+ unsigned const_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_i : index_j;
+ unsigned nconst_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? j : i;
+ unsigned nconst_index_k = normal_forms[i][index_i].getKind() == kind::CONST_STRING ? index_j : index_i;
+ Node const_str = normal_forms[const_k][const_index_k];
+ Node other_str = normal_forms[nconst_k][nconst_index_k];
+ Assert( other_str.getKind()!=kind::CONST_STRING, "Other string is not constant." );
+ Assert( other_str.getKind()!=kind::STRING_CONCAT, "Other string is not CONCAT." );
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ //Opt
+ bool optflag = false;
+ if( normal_forms[nconst_k].size() > nconst_index_k + 1 &&
+ normal_forms[nconst_k][nconst_index_k + 1].isConst() ) {
+ CVC4::String stra = const_str.getConst<String>();
+ CVC4::String strb = normal_forms[nconst_k][nconst_index_k + 1].getConst<String>();
+ CVC4::String fc = strb.substr(0, 1);
+ if( stra.find(fc) == std::string::npos ||
+ (stra.find(strb) == std::string::npos &&
+ !stra.overlap(strb)) ) {
+ Node sk = NodeManager::currentNM()->mkSkolem( "sopt", NodeManager::currentNM()->stringType(), "created for string sp" );
+ Node eq = other_str.eqNode( mkConcat(const_str, sk) );
+ Node ant = mkExplain( antec );
+ sendLemma(ant, eq, "CST-EPS");
+ optflag = true;
+ }
+ }
+ if(!optflag){
+ Node firstChar = const_str.getConst<String>().size() == 1 ? const_str :
+ NodeManager::currentNM()->mkConst( const_str.getConst<String>().substr(0, 1) );
+ //split the string
+ Node eq1 = Rewriter::rewrite( other_str.eqNode( d_emptyString ) );
+ Node eq2 = mkSplitEq( "c_spt", "created for v/c split", other_str, firstChar, false );
+ d_pending_req_phase[ eq1 ] = true;
+ conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
+ Trace("strings-solve-debug") << "Break normal form constant/variable " << std::endl;
+
+ Node ant = mkExplain( antec );
+ sendLemma( ant, conc, "CST-SPLIT" );
+ ++(d_statistics.d_eq_splits);
+ }
+ return true;
+ } else {
+ std::vector< Node > antec_new_lits;
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+
+ Node ldeq = NodeManager::currentNM()->mkNode( kind::EQUAL, length_term_i, length_term_j ).negate();
+ if( d_equalityEngine.areDisequal( length_term_i, length_term_j, true ) ){
+ antec.push_back( ldeq );
+ }else{
+ antec_new_lits.push_back(ldeq);
+ }
+
+ //x!=e /\ y!=e
+ for(unsigned xory=0; xory<2; xory++) {
+ Node x = xory==0 ? normal_forms[i][index_i] : normal_forms[j][index_j];
+ Node xgtz = x.eqNode( d_emptyString ).negate();
+ if( d_equalityEngine.areDisequal( x, d_emptyString, true ) ) {
+ antec.push_back( xgtz );
+ } else {
+ antec_new_lits.push_back( xgtz );
+ }
+ }
+
+ Node eq1 = mkSplitEq( "v_spt_l", "created for v/v split", normal_forms[i][index_i], normal_forms[j][index_j], true );
+ Node eq2 = mkSplitEq( "v_spt_r", "created for v/v split", normal_forms[j][index_j], normal_forms[i][index_i], true );
+ conc = NodeManager::currentNM()->mkNode( kind::OR, eq1, eq2 );
+
+ Node ant = mkExplain( antec, antec_new_lits );
+ sendLemma( ant, conc, "VAR-SPLIT" );
+ ++(d_statistics.d_eq_splits);
+ return true;
+ }
+ }
+ }
+ }
+ } while(success);
+ }
+ }
+ if(!flag_lb) {
+ return false;
+ }
+ }
+ if(flag_lb) {
+ if(processLoop(c_lb_exp, normal_forms, normal_form_src,
+ c_i, c_j, c_loop_n_index, c_other_n_index, c_loop_index, c_index, c_other_index)) {
+ return true;
+ }
+ }
+
+ return false;
}
bool TheoryStrings::processReverseNEq( std::vector< std::vector< Node > > &normal_forms,
std::vector< Node > &normal_form_src, std::vector< Node > &curr_exp, unsigned i, unsigned j ) {
- //reverse normal form of i, j
- std::reverse( normal_forms[i].begin(), normal_forms[i].end() );
- std::reverse( normal_forms[j].begin(), normal_forms[j].end() );
+ //reverse normal form of i, j
+ std::reverse( normal_forms[i].begin(), normal_forms[i].end() );
+ std::reverse( normal_forms[j].begin(), normal_forms[j].end() );
- std::vector< Node > t_curr_exp;
- t_curr_exp.insert( t_curr_exp.begin(), curr_exp.begin(), curr_exp.end() );
- unsigned index_i = 0;
- unsigned index_j = 0;
- bool ret = processSimpleNEq( normal_forms, normal_form_src, t_curr_exp, i, j, index_i, index_j, true );
+ std::vector< Node > t_curr_exp;
+ t_curr_exp.insert( t_curr_exp.begin(), curr_exp.begin(), curr_exp.end() );
+ unsigned index_i = 0;
+ unsigned index_j = 0;
+ bool ret = processSimpleNEq( normal_forms, normal_form_src, t_curr_exp, i, j, index_i, index_j, true );
- //reverse normal form of i, j
- std::reverse( normal_forms[i].begin(), normal_forms[i].end() );
- std::reverse( normal_forms[j].begin(), normal_forms[j].end() );
+ //reverse normal form of i, j
+ std::reverse( normal_forms[i].begin(), normal_forms[i].end() );
+ std::reverse( normal_forms[j].begin(), normal_forms[j].end() );
- return ret;
+ return ret;
}
bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal_forms,
std::vector< Node > &normal_form_src, std::vector< Node > &curr_exp,
unsigned i, unsigned j, unsigned& index_i, unsigned& index_j, bool isRev ) {
- bool success;
- do {
- success = false;
- //if we are at the end
- if(index_i==normal_forms[i].size() || index_j==normal_forms[j].size() ) {
- if( index_i==normal_forms[i].size() && index_j==normal_forms[j].size() ) {
- //we're done
- } else {
- //the remainder must be empty
- unsigned k = index_i==normal_forms[i].size() ? j : i;
- unsigned index_k = index_i==normal_forms[i].size() ? index_j : index_i;
- Node eq_exp = mkAnd( curr_exp );
- while(!d_conflict && index_k<normal_forms[k].size()) {
- //can infer that this string must be empty
- Node eq = normal_forms[k][index_k].eqNode( d_emptyString );
- Trace("strings-lemma") << "Strings: Infer " << eq << " from " << eq_exp << std::endl;
- Assert( !areEqual( d_emptyString, normal_forms[k][index_k] ) );
- sendInfer( eq_exp, eq, "EQ_Endpoint" );
- index_k++;
- }
- return true;
- }
- }else{
- Trace("strings-solve-debug") << "Process " << normal_forms[i][index_i] << " ... " << normal_forms[j][index_j] << std::endl;
- if(areEqual(normal_forms[i][index_i], normal_forms[j][index_j])) {
- Trace("strings-solve-debug") << "Simple Case 1 : strings are equal" << std::endl;
- //terms are equal, continue
- if( normal_forms[i][index_i]!=normal_forms[j][index_j] ) {
- Node eq = normal_forms[i][index_i].eqNode(normal_forms[j][index_j]);
- Trace("strings-solve-debug") << "Add to explanation : " << eq << std::endl;
- curr_exp.push_back(eq);
- }
- index_j++;
- index_i++;
- success = true;
- } else {
- Node length_term_i = getLength( normal_forms[i][index_i] );
- Node length_term_j = getLength( normal_forms[j][index_j] );
- //check length(normal_forms[i][index]) == length(normal_forms[j][index])
- if( areEqual(length_term_i, length_term_j) ) {
- Trace("strings-solve-debug") << "Simple Case 2 : string lengths are equal" << std::endl;
- Node eq = normal_forms[i][index_i].eqNode( normal_forms[j][index_j] );
- //eq = Rewriter::rewrite( eq );
- Node length_eq = length_term_i.eqNode( length_term_j );
- std::vector< Node > temp_exp;
- temp_exp.insert(temp_exp.end(), curr_exp.begin(), curr_exp.end() );
- temp_exp.push_back(length_eq);
- Node eq_exp = temp_exp.empty() ? d_true :
- temp_exp.size() == 1 ? temp_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, temp_exp );
- sendInfer( eq_exp, eq, "LengthEq" );
- return true;
- } else if(( normal_forms[i][index_i].getKind()!=kind::CONST_STRING && index_i==normal_forms[i].size()-1 ) ||
- ( normal_forms[j][index_j].getKind()!=kind::CONST_STRING && index_j==normal_forms[j].size()-1 ) ) {
- Trace("strings-solve-debug") << "Simple Case 3 : at endpoint" << std::endl;
- Node conc;
- std::vector< Node > antec;
- antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
- std::vector< Node > eqn;
- for( unsigned r=0; r<2; r++ ) {
- int index_k = r==0 ? index_i : index_j;
- int k = r==0 ? i : j;
- std::vector< Node > eqnc;
- for( unsigned index_l=index_k; index_l<normal_forms[k].size(); index_l++ ) {
- if(isRev) {
- eqnc.insert(eqnc.begin(), normal_forms[k][index_l] );
- } else {
- eqnc.push_back( normal_forms[k][index_l] );
- }
- }
- eqn.push_back( mkConcat( eqnc ) );
- }
- if( !areEqual( eqn[0], eqn[1] ) ) {
- conc = eqn[0].eqNode( eqn[1] );
- Node ant = mkExplain( antec );
- sendLemma( ant, conc, "ENDPOINT" );
- return true;
- }else{
- index_i = normal_forms[i].size();
- index_j = normal_forms[j].size();
- }
- } else if(normal_forms[i][index_i].isConst() && normal_forms[j][index_j].isConst()) {
- Node const_str = normal_forms[i][index_i];
- Node other_str = normal_forms[j][index_j];
- Trace("strings-solve-debug") << "Simple Case 3 : Const Split : " << const_str << " vs " << other_str << std::endl;
- unsigned len_short = const_str.getConst<String>().size() <= other_str.getConst<String>().size() ? const_str.getConst<String>().size() : other_str.getConst<String>().size();
- bool isSameFix = isRev ? const_str.getConst<String>().rstrncmp(other_str.getConst<String>(), len_short): const_str.getConst<String>().strncmp(other_str.getConst<String>(), len_short);
- if( isSameFix ) {
- //same prefix/suffix
- //k is the index of the string that is shorter
- int k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? i : j;
- int index_k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_i : index_j;
- int l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? j : i;
- int index_l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_j : index_i;
- if(isRev) {
- int new_len = normal_forms[l][index_l].getConst<String>().size() - len_short;
- Node remainderStr = NodeManager::currentNM()->mkConst( normal_forms[l][index_l].getConst<String>().substr(0, new_len) );
- Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index_l] << " into " << normal_forms[k][index_k] << ", " << remainderStr << std::endl;
- normal_forms[l].insert( normal_forms[l].begin()+index_l + 1, remainderStr );
- } else {
- Node remainderStr = NodeManager::currentNM()->mkConst(normal_forms[l][index_l].getConst<String>().substr(len_short));
- Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index_l] << " into " << normal_forms[k][index_k] << ", " << remainderStr << std::endl;
- normal_forms[l].insert( normal_forms[l].begin()+index_l + 1, remainderStr );
- }
- normal_forms[l][index_l] = normal_forms[k][index_k];
- index_i++;
- index_j++;
- success = true;
- } else {
- Node conc;
- std::vector< Node > antec;
- //curr_exp is conflict
- antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
- Node ant = mkExplain( antec );
- sendLemma( ant, conc, "Const Conflict" );
- return true;
- }
- }
- }
- }
- }while( success );
- return false;
+ bool success;
+ do {
+ success = false;
+ //if we are at the end
+ if(index_i==normal_forms[i].size() || index_j==normal_forms[j].size() ) {
+ if( index_i==normal_forms[i].size() && index_j==normal_forms[j].size() ) {
+ //we're done
+ } else {
+ //the remainder must be empty
+ unsigned k = index_i==normal_forms[i].size() ? j : i;
+ unsigned index_k = index_i==normal_forms[i].size() ? index_j : index_i;
+ Node eq_exp = mkAnd( curr_exp );
+ while(!d_conflict && index_k<normal_forms[k].size()) {
+ //can infer that this string must be empty
+ Node eq = normal_forms[k][index_k].eqNode( d_emptyString );
+ Trace("strings-lemma") << "Strings: Infer " << eq << " from " << eq_exp << std::endl;
+ Assert( !areEqual( d_emptyString, normal_forms[k][index_k] ) );
+ sendInfer( eq_exp, eq, "EQ_Endpoint" );
+ index_k++;
+ }
+ return true;
+ }
+ }else{
+ Trace("strings-solve-debug") << "Process " << normal_forms[i][index_i] << " ... " << normal_forms[j][index_j] << std::endl;
+ if(areEqual(normal_forms[i][index_i], normal_forms[j][index_j])) {
+ Trace("strings-solve-debug") << "Simple Case 1 : strings are equal" << std::endl;
+ //terms are equal, continue
+ if( normal_forms[i][index_i]!=normal_forms[j][index_j] ) {
+ Node eq = normal_forms[i][index_i].eqNode(normal_forms[j][index_j]);
+ Trace("strings-solve-debug") << "Add to explanation : " << eq << std::endl;
+ curr_exp.push_back(eq);
+ }
+ index_j++;
+ index_i++;
+ success = true;
+ } else {
+ Node length_term_i = getLength( normal_forms[i][index_i] );
+ Node length_term_j = getLength( normal_forms[j][index_j] );
+ //check length(normal_forms[i][index]) == length(normal_forms[j][index])
+ if( areEqual(length_term_i, length_term_j) ) {
+ Trace("strings-solve-debug") << "Simple Case 2 : string lengths are equal" << std::endl;
+ Node eq = normal_forms[i][index_i].eqNode( normal_forms[j][index_j] );
+ //eq = Rewriter::rewrite( eq );
+ Node length_eq = length_term_i.eqNode( length_term_j );
+ std::vector< Node > temp_exp;
+ temp_exp.insert(temp_exp.end(), curr_exp.begin(), curr_exp.end() );
+ temp_exp.push_back(length_eq);
+ Node eq_exp = temp_exp.empty() ? d_true :
+ temp_exp.size() == 1 ? temp_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, temp_exp );
+ sendInfer( eq_exp, eq, "LengthEq" );
+ return true;
+ } else if(( normal_forms[i][index_i].getKind()!=kind::CONST_STRING && index_i==normal_forms[i].size()-1 ) ||
+ ( normal_forms[j][index_j].getKind()!=kind::CONST_STRING && index_j==normal_forms[j].size()-1 ) ) {
+ Trace("strings-solve-debug") << "Simple Case 3 : at endpoint" << std::endl;
+ Node conc;
+ std::vector< Node > antec;
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ std::vector< Node > eqn;
+ for( unsigned r=0; r<2; r++ ) {
+ int index_k = r==0 ? index_i : index_j;
+ int k = r==0 ? i : j;
+ std::vector< Node > eqnc;
+ for( unsigned index_l=index_k; index_l<normal_forms[k].size(); index_l++ ) {
+ if(isRev) {
+ eqnc.insert(eqnc.begin(), normal_forms[k][index_l] );
+ } else {
+ eqnc.push_back( normal_forms[k][index_l] );
+ }
+ }
+ eqn.push_back( mkConcat( eqnc ) );
+ }
+ if( !areEqual( eqn[0], eqn[1] ) ) {
+ conc = eqn[0].eqNode( eqn[1] );
+ Node ant = mkExplain( antec );
+ sendLemma( ant, conc, "ENDPOINT" );
+ return true;
+ }else{
+ index_i = normal_forms[i].size();
+ index_j = normal_forms[j].size();
+ }
+ } else if(normal_forms[i][index_i].isConst() && normal_forms[j][index_j].isConst()) {
+ Node const_str = normal_forms[i][index_i];
+ Node other_str = normal_forms[j][index_j];
+ Trace("strings-solve-debug") << "Simple Case 3 : Const Split : " << const_str << " vs " << other_str << std::endl;
+ unsigned len_short = const_str.getConst<String>().size() <= other_str.getConst<String>().size() ? const_str.getConst<String>().size() : other_str.getConst<String>().size();
+ bool isSameFix = isRev ? const_str.getConst<String>().rstrncmp(other_str.getConst<String>(), len_short): const_str.getConst<String>().strncmp(other_str.getConst<String>(), len_short);
+ if( isSameFix ) {
+ //same prefix/suffix
+ //k is the index of the string that is shorter
+ int k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? i : j;
+ int index_k = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_i : index_j;
+ int l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? j : i;
+ int index_l = const_str.getConst<String>().size()<other_str.getConst<String>().size() ? index_j : index_i;
+ if(isRev) {
+ int new_len = normal_forms[l][index_l].getConst<String>().size() - len_short;
+ Node remainderStr = NodeManager::currentNM()->mkConst( normal_forms[l][index_l].getConst<String>().substr(0, new_len) );
+ Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index_l] << " into " << normal_forms[k][index_k] << ", " << remainderStr << std::endl;
+ normal_forms[l].insert( normal_forms[l].begin()+index_l + 1, remainderStr );
+ } else {
+ Node remainderStr = NodeManager::currentNM()->mkConst(normal_forms[l][index_l].getConst<String>().substr(len_short));
+ Trace("strings-solve-debug-test") << "Break normal form of " << normal_forms[l][index_l] << " into " << normal_forms[k][index_k] << ", " << remainderStr << std::endl;
+ normal_forms[l].insert( normal_forms[l].begin()+index_l + 1, remainderStr );
+ }
+ normal_forms[l][index_l] = normal_forms[k][index_k];
+ index_i++;
+ index_j++;
+ success = true;
+ } else {
+ Node conc;
+ std::vector< Node > antec;
+ //curr_exp is conflict
+ antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
+ Node ant = mkExplain( antec );
+ sendLemma( ant, conc, "Const Conflict" );
+ return true;
+ }
+ }
+ }
+ }
+ }while( success );
+ return false;
}
//return true for lemma, false if we succeed
bool TheoryStrings::processDeq( Node ni, Node nj ) {
- //Assert( areDisequal( ni, nj ) );
- if( d_normal_forms[ni].size()>1 || d_normal_forms[nj].size()>1 ){
- std::vector< Node > nfi;
- nfi.insert( nfi.end(), d_normal_forms[ni].begin(), d_normal_forms[ni].end() );
- std::vector< Node > nfj;
- nfj.insert( nfj.end(), d_normal_forms[nj].begin(), d_normal_forms[nj].end() );
-
- int revRet = processReverseDeq( nfi, nfj, ni, nj );
- if( revRet!=0 ){
- return revRet==-1;
- }
-
- nfi.clear();
- nfi.insert( nfi.end(), d_normal_forms[ni].begin(), d_normal_forms[ni].end() );
- nfj.clear();
- nfj.insert( nfj.end(), d_normal_forms[nj].begin(), d_normal_forms[nj].end() );
-
- unsigned index = 0;
- while( index<nfi.size() || index<nfj.size() ){
- int ret = processSimpleDeq( nfi, nfj, ni, nj, index, false );
- if( ret!=0 ) {
- return ret==-1;
- } else {
- Assert( index<nfi.size() && index<nfj.size() );
- Node i = nfi[index];
- Node j = nfj[index];
- Trace("strings-solve-debug") << "...Processing(DEQ) " << i << " " << j << std::endl;
- if( !areEqual( i, j ) ) {
- Assert( i.getKind()!=kind::CONST_STRING || j.getKind()!=kind::CONST_STRING );
- Node li = getLength( i );
- Node lj = getLength( j );
- if( areDisequal(li, lj) ){
- //if( i.getKind()==kind::CONST_STRING || j.getKind()==kind::CONST_STRING ){
-
- Trace("strings-solve") << "Non-Simple Case 1 : add lemma " << std::endl;
- //must add lemma
- std::vector< Node > antec;
- std::vector< Node > antec_new_lits;
- antec.insert( antec.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
- antec.insert( antec.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
- //check disequal
- if( areDisequal( ni, nj ) ){
- antec.push_back( ni.eqNode( nj ).negate() );
- }else{
- antec_new_lits.push_back( ni.eqNode( nj ).negate() );
- }
- antec_new_lits.push_back( li.eqNode( lj ).negate() );
- std::vector< Node > conc;
- Node sk1 = NodeManager::currentNM()->mkSkolem( "x_dsplit", ni.getType(), "created for disequality normalization" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "y_dsplit", ni.getType(), "created for disequality normalization" );
- Node sk3 = NodeManager::currentNM()->mkSkolem( "z_dsplit", ni.getType(), "created for disequality normalization" );
- d_statistics.d_new_skolems += 3;
- //Node nemp = sk1.eqNode(d_emptyString).negate();
- //conc.push_back(nemp);
- //nemp = sk2.eqNode(d_emptyString).negate();
- //conc.push_back(nemp);
- Node nemp = sk3.eqNode(d_emptyString).negate();
- conc.push_back(nemp);
- Node lsk1 = getLength( sk1 );
- conc.push_back( lsk1.eqNode( li ) );
- Node lsk2 = getLength( sk2 );
- conc.push_back( lsk2.eqNode( lj ) );
- conc.push_back( NodeManager::currentNM()->mkNode( kind::OR,
- j.eqNode( mkConcat( sk1, sk3 ) ), i.eqNode( mkConcat( sk2, sk3 ) ) ) );
-
- sendLemma( mkExplain( antec, antec_new_lits ), NodeManager::currentNM()->mkNode( kind::AND, conc ), "D-DISL-Split" );
- ++(d_statistics.d_deq_splits);
- return true;
- }else if( areEqual( li, lj ) ){
- Assert( !areDisequal( i, j ) );
- //splitting on demand : try to make them disequal
- Node eq = i.eqNode( j );
- sendSplit( i, j, "D-EQL-Split" );
- eq = Rewriter::rewrite( eq );
- d_pending_req_phase[ eq ] = false;
- return true;
- }else{
- //splitting on demand : try to make lengths equal
- Node eq = li.eqNode( lj );
- sendSplit( li, lj, "D-UNK-Split" );
- eq = Rewriter::rewrite( eq );
- d_pending_req_phase[ eq ] = true;
- return true;
- }
- }
- index++;
- }
- }
- Assert( false );
- }
- return false;
+ //Assert( areDisequal( ni, nj ) );
+ if( d_normal_forms[ni].size()>1 || d_normal_forms[nj].size()>1 ){
+ std::vector< Node > nfi;
+ nfi.insert( nfi.end(), d_normal_forms[ni].begin(), d_normal_forms[ni].end() );
+ std::vector< Node > nfj;
+ nfj.insert( nfj.end(), d_normal_forms[nj].begin(), d_normal_forms[nj].end() );
+
+ int revRet = processReverseDeq( nfi, nfj, ni, nj );
+ if( revRet!=0 ){
+ return revRet==-1;
+ }
+
+ nfi.clear();
+ nfi.insert( nfi.end(), d_normal_forms[ni].begin(), d_normal_forms[ni].end() );
+ nfj.clear();
+ nfj.insert( nfj.end(), d_normal_forms[nj].begin(), d_normal_forms[nj].end() );
+
+ unsigned index = 0;
+ while( index<nfi.size() || index<nfj.size() ){
+ int ret = processSimpleDeq( nfi, nfj, ni, nj, index, false );
+ if( ret!=0 ) {
+ return ret==-1;
+ } else {
+ Assert( index<nfi.size() && index<nfj.size() );
+ Node i = nfi[index];
+ Node j = nfj[index];
+ Trace("strings-solve-debug") << "...Processing(DEQ) " << i << " " << j << std::endl;
+ if( !areEqual( i, j ) ) {
+ Assert( i.getKind()!=kind::CONST_STRING || j.getKind()!=kind::CONST_STRING );
+ Node li = getLength( i );
+ Node lj = getLength( j );
+ if( areDisequal(li, lj) ){
+ //if( i.getKind()==kind::CONST_STRING || j.getKind()==kind::CONST_STRING ){
+
+ Trace("strings-solve") << "Non-Simple Case 1 : add lemma " << std::endl;
+ //must add lemma
+ std::vector< Node > antec;
+ std::vector< Node > antec_new_lits;
+ antec.insert( antec.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
+ antec.insert( antec.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
+ //check disequal
+ if( areDisequal( ni, nj ) ){
+ antec.push_back( ni.eqNode( nj ).negate() );
+ }else{
+ antec_new_lits.push_back( ni.eqNode( nj ).negate() );
+ }
+ antec_new_lits.push_back( li.eqNode( lj ).negate() );
+ std::vector< Node > conc;
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "x_dsplit", ni.getType(), "created for disequality normalization" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "y_dsplit", ni.getType(), "created for disequality normalization" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "z_dsplit", ni.getType(), "created for disequality normalization" );
+ d_statistics.d_new_skolems += 3;
+ //Node nemp = sk1.eqNode(d_emptyString).negate();
+ //conc.push_back(nemp);
+ //nemp = sk2.eqNode(d_emptyString).negate();
+ //conc.push_back(nemp);
+ Node nemp = sk3.eqNode(d_emptyString).negate();
+ conc.push_back(nemp);
+ Node lsk1 = getLength( sk1 );
+ conc.push_back( lsk1.eqNode( li ) );
+ Node lsk2 = getLength( sk2 );
+ conc.push_back( lsk2.eqNode( lj ) );
+ conc.push_back( NodeManager::currentNM()->mkNode( kind::OR,
+ j.eqNode( mkConcat( sk1, sk3 ) ), i.eqNode( mkConcat( sk2, sk3 ) ) ) );
+
+ sendLemma( mkExplain( antec, antec_new_lits ), NodeManager::currentNM()->mkNode( kind::AND, conc ), "D-DISL-Split" );
+ ++(d_statistics.d_deq_splits);
+ return true;
+ }else if( areEqual( li, lj ) ){
+ Assert( !areDisequal( i, j ) );
+ //splitting on demand : try to make them disequal
+ Node eq = i.eqNode( j );
+ sendSplit( i, j, "D-EQL-Split" );
+ eq = Rewriter::rewrite( eq );
+ d_pending_req_phase[ eq ] = false;
+ return true;
+ }else{
+ //splitting on demand : try to make lengths equal
+ Node eq = li.eqNode( lj );
+ sendSplit( li, lj, "D-UNK-Split" );
+ eq = Rewriter::rewrite( eq );
+ d_pending_req_phase[ eq ] = true;
+ return true;
+ }
+ }
+ index++;
+ }
+ }
+ Assert( false );
+ }
+ return false;
}
int TheoryStrings::processReverseDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj ) {
- //reverse normal form of i, j
- std::reverse( nfi.begin(), nfi.end() );
- std::reverse( nfj.begin(), nfj.end() );
+ //reverse normal form of i, j
+ std::reverse( nfi.begin(), nfi.end() );
+ std::reverse( nfj.begin(), nfj.end() );
- unsigned index = 0;
- int ret = processSimpleDeq( nfi, nfj, ni, nj, index, true );
+ unsigned index = 0;
+ int ret = processSimpleDeq( nfi, nfj, ni, nj, index, true );
- //reverse normal form of i, j
- std::reverse( nfi.begin(), nfi.end() );
- std::reverse( nfj.begin(), nfj.end() );
+ //reverse normal form of i, j
+ std::reverse( nfi.begin(), nfi.end() );
+ std::reverse( nfj.begin(), nfj.end() );
- return ret;
+ return ret;
}
int TheoryStrings::processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj, unsigned& index, bool isRev ) {
- while( index<nfi.size() || index<nfj.size() ) {
- if( index>=nfi.size() || index>=nfj.size() ) {
- std::vector< Node > ant;
- //we have a conflict : because the lengths are equal, the remainder needs to be empty, which will lead to a conflict
- Node lni = getLength( ni );
- Node lnj = getLength( nj );
- ant.push_back( lni.eqNode( lnj ) );
- ant.push_back( getLengthTerm( ni ).eqNode( d_normal_forms_base[ni] ) );
- ant.push_back( getLengthTerm( nj ).eqNode( d_normal_forms_base[nj] ) );
- ant.insert( ant.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
- ant.insert( ant.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
- std::vector< Node > cc;
- std::vector< Node >& nfk = index>=nfi.size() ? nfj : nfi;
- for( unsigned index_k=index; index_k<nfk.size(); index_k++ ){
- cc.push_back( nfk[index_k].eqNode( d_emptyString ) );
- }
- Node conc = cc.size()==1 ? cc[0] : NodeManager::currentNM()->mkNode( kind::AND, cc );
- conc = Rewriter::rewrite( conc );
- sendLemma(mkExplain( ant ), conc, "Disequality Normalize Empty");
- return -1;
- } else {
- Node i = nfi[index];
- Node j = nfj[index];
- Trace("strings-solve-debug") << "...Processing(QED) " << i << " " << j << std::endl;
- if( !areEqual( i, j ) ) {
- if( i.getKind()==kind::CONST_STRING && j.getKind()==kind::CONST_STRING ) {
- unsigned int len_short = i.getConst<String>().size() < j.getConst<String>().size() ? i.getConst<String>().size() : j.getConst<String>().size();
- bool isSameFix = isRev ? i.getConst<String>().rstrncmp(j.getConst<String>(), len_short): i.getConst<String>().strncmp(j.getConst<String>(), len_short);
- if( isSameFix ) {
- //same prefix/suffix
- //k is the index of the string that is shorter
- Node nk = i.getConst<String>().size() < j.getConst<String>().size() ? i : j;
- Node nl = i.getConst<String>().size() < j.getConst<String>().size() ? j : i;
- Node remainderStr;
- if(isRev) {
- int new_len = nl.getConst<String>().size() - len_short;
- remainderStr = NodeManager::currentNM()->mkConst( nl.getConst<String>().substr(0, new_len) );
- Trace("strings-solve-debug-test") << "Rev. Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl;
- } else {
- remainderStr = NodeManager::currentNM()->mkConst( j.getConst<String>().substr(len_short) );
- Trace("strings-solve-debug-test") << "Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl;
- }
- if( i.getConst<String>().size() < j.getConst<String>().size() ) {
- nfj.insert( nfj.begin() + index + 1, remainderStr );
- nfj[index] = nfi[index];
- } else {
- nfi.insert( nfi.begin() + index + 1, remainderStr );
- nfi[index] = nfj[index];
- }
- } else {
- return 1;
- }
- } else {
- Node li = getLength( i );
- Node lj = getLength( j );
- if( areEqual( li, lj ) && areDisequal( i, j ) ) {
- Trace("strings-solve") << "Simple Case 2 : found equal length disequal sub strings " << i << " " << j << std::endl;
- //we are done: D-Remove
- return 1;
- } else {
- return 0;
- }
- }
- }
- index++;
- }
- }
- return 0;
+ while( index<nfi.size() || index<nfj.size() ) {
+ if( index>=nfi.size() || index>=nfj.size() ) {
+ std::vector< Node > ant;
+ //we have a conflict : because the lengths are equal, the remainder needs to be empty, which will lead to a conflict
+ Node lni = getLength( ni );
+ Node lnj = getLength( nj );
+ ant.push_back( lni.eqNode( lnj ) );
+ ant.push_back( getLengthTerm( ni ).eqNode( d_normal_forms_base[ni] ) );
+ ant.push_back( getLengthTerm( nj ).eqNode( d_normal_forms_base[nj] ) );
+ ant.insert( ant.end(), d_normal_forms_exp[ni].begin(), d_normal_forms_exp[ni].end() );
+ ant.insert( ant.end(), d_normal_forms_exp[nj].begin(), d_normal_forms_exp[nj].end() );
+ std::vector< Node > cc;
+ std::vector< Node >& nfk = index>=nfi.size() ? nfj : nfi;
+ for( unsigned index_k=index; index_k<nfk.size(); index_k++ ){
+ cc.push_back( nfk[index_k].eqNode( d_emptyString ) );
+ }
+ Node conc = cc.size()==1 ? cc[0] : NodeManager::currentNM()->mkNode( kind::AND, cc );
+ conc = Rewriter::rewrite( conc );
+ sendLemma(mkExplain( ant ), conc, "Disequality Normalize Empty");
+ return -1;
+ } else {
+ Node i = nfi[index];
+ Node j = nfj[index];
+ Trace("strings-solve-debug") << "...Processing(QED) " << i << " " << j << std::endl;
+ if( !areEqual( i, j ) ) {
+ if( i.getKind()==kind::CONST_STRING && j.getKind()==kind::CONST_STRING ) {
+ unsigned int len_short = i.getConst<String>().size() < j.getConst<String>().size() ? i.getConst<String>().size() : j.getConst<String>().size();
+ bool isSameFix = isRev ? i.getConst<String>().rstrncmp(j.getConst<String>(), len_short): i.getConst<String>().strncmp(j.getConst<String>(), len_short);
+ if( isSameFix ) {
+ //same prefix/suffix
+ //k is the index of the string that is shorter
+ Node nk = i.getConst<String>().size() < j.getConst<String>().size() ? i : j;
+ Node nl = i.getConst<String>().size() < j.getConst<String>().size() ? j : i;
+ Node remainderStr;
+ if(isRev) {
+ int new_len = nl.getConst<String>().size() - len_short;
+ remainderStr = NodeManager::currentNM()->mkConst( nl.getConst<String>().substr(0, new_len) );
+ Trace("strings-solve-debug-test") << "Rev. Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl;
+ } else {
+ remainderStr = NodeManager::currentNM()->mkConst( j.getConst<String>().substr(len_short) );
+ Trace("strings-solve-debug-test") << "Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl;
+ }
+ if( i.getConst<String>().size() < j.getConst<String>().size() ) {
+ nfj.insert( nfj.begin() + index + 1, remainderStr );
+ nfj[index] = nfi[index];
+ } else {
+ nfi.insert( nfi.begin() + index + 1, remainderStr );
+ nfi[index] = nfj[index];
+ }
+ } else {
+ return 1;
+ }
+ } else {
+ Node li = getLength( i );
+ Node lj = getLength( j );
+ if( areEqual( li, lj ) && areDisequal( i, j ) ) {
+ Trace("strings-solve") << "Simple Case 2 : found equal length disequal sub strings " << i << " " << j << std::endl;
+ //we are done: D-Remove
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ index++;
+ }
+ }
+ return 0;
}
void TheoryStrings::addNormalFormPair( Node n1, Node n2 ) {
if( !isNormalFormPair( n1, n2 ) ){
- //Assert( !isNormalFormPair( n1, n2 ) );
+ //Assert( !isNormalFormPair( n1, n2 ) );
NodeList* lst;
NodeListMap::iterator nf_i = d_nf_pairs.find( n1 );
if( nf_i == d_nf_pairs.end() ){
} else {
lst = (*nf_i).second;
}
- Trace("strings-nf") << "Add normal form pair : " << n1 << " " << n2 << std::endl;
+ Trace("strings-nf") << "Add normal form pair : " << n1 << " " << n2 << std::endl;
lst->push_back( n2 );
- Assert( isNormalFormPair( n1, n2 ) );
+ Assert( isNormalFormPair( n1, n2 ) );
} else {
- Trace("strings-nf-debug") << "Already a normal form pair " << n1 << " " << n2 << std::endl;
- }
+ Trace("strings-nf-debug") << "Already a normal form pair " << n1 << " " << n2 << std::endl;
+ }
}
bool TheoryStrings::isNormalFormPair( Node n1, Node n2 ) {
//TODO: modulo equality?
}
void TheoryStrings::sendLemma( Node ant, Node conc, const char * c ) {
- if( conc.isNull() || conc == d_false ) {
- d_out->conflict(ant);
- Trace("strings-conflict") << "Strings::Conflict : " << ant << std::endl;
- d_conflict = true;
- } else {
- Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, ant, conc );
- if( ant == d_true ) {
- lem = conc;
- }
- Trace("strings-lemma") << "Strings::Lemma " << c << " : " << lem << std::endl;
- d_lemma_cache.push_back( lem );
- }
+ if( conc.isNull() || conc == d_false ) {
+ d_out->conflict(ant);
+ Trace("strings-conflict") << "Strings::Conflict : " << ant << std::endl;
+ d_conflict = true;
+ } else {
+ Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, ant, conc );
+ if( ant == d_true ) {
+ lem = conc;
+ }
+ Trace("strings-lemma") << "Strings::Lemma " << c << " : " << lem << std::endl;
+ d_lemma_cache.push_back( lem );
+ }
}
void TheoryStrings::sendInfer( Node eq_exp, Node eq, const char * c ) {
- eq = Rewriter::rewrite( eq );
- if( eq==d_false ) {
- sendLemma( eq_exp, eq, c );
- } else {
- Trace("strings-lemma") << "Strings::Infer " << eq << " from " << eq_exp << " by " << c << std::endl;
- d_pending.push_back( eq );
- d_pending_exp[eq] = eq_exp;
- d_infer.push_back(eq);
- d_infer_exp.push_back(eq_exp);
- }
+ eq = Rewriter::rewrite( eq );
+ if( eq==d_false ) {
+ sendLemma( eq_exp, eq, c );
+ } else {
+ Trace("strings-lemma") << "Strings::Infer " << eq << " from " << eq_exp << " by " << c << std::endl;
+ d_pending.push_back( eq );
+ d_pending_exp[eq] = eq_exp;
+ d_infer.push_back(eq);
+ d_infer_exp.push_back(eq_exp);
+ }
}
void TheoryStrings::sendSplit( Node a, Node b, const char * c, bool preq ) {
- Node eq = a.eqNode( b );
- eq = Rewriter::rewrite( eq );
- Node neq = NodeManager::currentNM()->mkNode( kind::NOT, eq );
- Node lemma_or = NodeManager::currentNM()->mkNode( kind::OR, eq, neq );
- Trace("strings-lemma") << "Strings::Lemma " << c << " SPLIT : " << lemma_or << std::endl;
- d_lemma_cache.push_back(lemma_or);
- d_pending_req_phase[eq] = preq;
- ++(d_statistics.d_splits);
+ Node eq = a.eqNode( b );
+ eq = Rewriter::rewrite( eq );
+ Node neq = NodeManager::currentNM()->mkNode( kind::NOT, eq );
+ Node lemma_or = NodeManager::currentNM()->mkNode( kind::OR, eq, neq );
+ Trace("strings-lemma") << "Strings::Lemma " << c << " SPLIT : " << lemma_or << std::endl;
+ d_lemma_cache.push_back(lemma_or);
+ d_pending_req_phase[eq] = preq;
+ ++(d_statistics.d_splits);
}
Node TheoryStrings::mkConcat( Node n1, Node n2 ) {
- return Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, n1, n2 ) );
+ return Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, n1, n2 ) );
}
Node TheoryStrings::mkConcat( std::vector< Node >& c ) {
Node cc = c.size()>1 ? NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, c ) : ( c.size()==1 ? c[0] : d_emptyString );
- return Rewriter::rewrite( cc );
+ return Rewriter::rewrite( cc );
}
Node TheoryStrings::mkExplain( std::vector< Node >& a ) {
- std::vector< Node > an;
- return mkExplain( a, an );
+ std::vector< Node > an;
+ return mkExplain( a, an );
}
Node TheoryStrings::mkExplain( std::vector< Node >& a, std::vector< Node >& an ) {
} else {
ant = NodeManager::currentNM()->mkNode( kind::AND, antec_exp );
}
- ant = Rewriter::rewrite( ant );
+ ant = Rewriter::rewrite( ant );
return ant;
}
Node TheoryStrings::mkAnd( std::vector< Node >& a ) {
- if( a.empty() ) {
- return d_true;
- } else if( a.size() == 1 ) {
- return a[0];
- } else {
- return NodeManager::currentNM()->mkNode( kind::AND, a );
- }
+ if( a.empty() ) {
+ return d_true;
+ } else if( a.size() == 1 ) {
+ return a[0];
+ } else {
+ return NodeManager::currentNM()->mkNode( kind::AND, a );
+ }
}
void TheoryStrings::getConcatVec( Node n, std::vector< Node >& c ) {
- if( n.getKind()==kind::STRING_CONCAT ) {
- for( unsigned i=0; i<n.getNumChildren(); i++ ) {
- if( !areEqual( n[i], d_emptyString ) ) {
- c.push_back( n[i] );
- }
- }
- } else {
- c.push_back( n );
- }
+ if( n.getKind()==kind::STRING_CONCAT ) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ if( !areEqual( n[i], d_emptyString ) ) {
+ c.push_back( n[i] );
+ }
+ }
+ } else {
+ c.push_back( n );
+ }
}
bool TheoryStrings::checkSimple() {
Trace("strings-lemma") << "Strings::Lemma LENGTH Term : " << eq << std::endl;
d_out->lemma(eq);
//} else {
- // sk = d_length_inst[n];
+ // sk = d_length_inst[n];
//}
Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
Node lsum;
bool TheoryStrings::checkNormalForms() {
Trace("strings-process") << "Normalize equivalence classes...." << std::endl;
- eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
- for( unsigned t=0; t<2; t++ ) {
- Trace("strings-eqc") << (t==0 ? "STRINGS:" : "OTHER:") << std::endl;
- while( !eqcs2_i.isFinished() ){
+ eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
+ for( unsigned t=0; t<2; t++ ) {
+ Trace("strings-eqc") << (t==0 ? "STRINGS:" : "OTHER:") << std::endl;
+ while( !eqcs2_i.isFinished() ){
Node eqc = (*eqcs2_i);
bool print = (t==0 && eqc.getType().isString() ) || (t==1 && !eqc.getType().isString() );
if (print) {
}
}
++eqcs2_i;
- }
- Trace("strings-eqc") << std::endl;
- }
- Trace("strings-eqc") << std::endl;
- for( NodeListMap::const_iterator it = d_nf_pairs.begin(); it != d_nf_pairs.end(); ++it ){
- NodeList* lst = (*it).second;
- NodeList::const_iterator it2 = lst->begin();
- Trace("strings-nf") << (*it).first << " has been unified with ";
- while( it2!=lst->end() ){
- Trace("strings-nf") << (*it2);
- ++it2;
- }
- Trace("strings-nf") << std::endl;
- }
- Trace("strings-nf") << std::endl;
- /*
- Trace("strings-nf") << "Current inductive equations : " << std::endl;
- for( NodeListMap::const_iterator it = d_ind_map1.begin(); it != d_ind_map1.end(); ++it ){
+ }
+ Trace("strings-eqc") << std::endl;
+ }
+ Trace("strings-eqc") << std::endl;
+ for( NodeListMap::const_iterator it = d_nf_pairs.begin(); it != d_nf_pairs.end(); ++it ){
+ NodeList* lst = (*it).second;
+ NodeList::const_iterator it2 = lst->begin();
+ Trace("strings-nf") << (*it).first << " has been unified with ";
+ while( it2!=lst->end() ){
+ Trace("strings-nf") << (*it2);
+ ++it2;
+ }
+ Trace("strings-nf") << std::endl;
+ }
+ Trace("strings-nf") << std::endl;
+ /*
+ Trace("strings-nf") << "Current inductive equations : " << std::endl;
+ for( NodeListMap::const_iterator it = d_ind_map1.begin(); it != d_ind_map1.end(); ++it ){
Node x = (*it).first;
NodeList* lst1 = (*it).second;
NodeList* lst2 = (*d_ind_map2.find(x)).second;
while( i1!=lst1->end() ){
Node y = *i1;
Node z = *i2;
- Trace("strings-nf") << "Inductive equation : " << x << " = ( " << y << " ++ " << z << " ) * " << y << std::endl;
+ Trace("strings-nf") << "Inductive equation : " << x << " = ( " << y << " ++ " << z << " ) * " << y << std::endl;
++i1;
++i2;
}
}
- */
+ */
bool addedFact;
do {
Trace("strings-process") << "Done verifying normal forms are the same for " << eqc << std::endl;
}
- Trace("strings-nf-debug") << "**** Normal forms are : " << std::endl;
- for( std::map< Node, Node >::iterator it = nf_to_eqc.begin(); it != nf_to_eqc.end(); ++it ){
- Trace("strings-nf-debug") << " normal_form(" << it->second << ") = " << it->first << std::endl;
- }
- Trace("strings-nf-debug") << std::endl;
+ Trace("strings-nf-debug") << "**** Normal forms are : " << std::endl;
+ for( std::map< Node, Node >::iterator it = nf_to_eqc.begin(); it != nf_to_eqc.end(); ++it ){
+ Trace("strings-nf-debug") << " normal_form(" << it->second << ") = " << it->first << std::endl;
+ }
+ Trace("strings-nf-debug") << std::endl;
addedFact = !d_pending.empty();
doPendingFacts();
} while ( !d_conflict && d_lemma_cache.empty() && addedFact );
void TheoryStrings::checkDeqNF() {
if( !d_conflict && d_lemma_cache.empty() ){
- std::vector< Node > eqcs;
- getEquivalenceClasses( eqcs );
- std::vector< std::vector< Node > > cols;
- std::vector< Node > lts;
- separateByLength( eqcs, cols, lts );
- for( unsigned i=0; i<cols.size(); i++ ){
- if( cols[i].size()>1 && d_lemma_cache.empty() ){
- Trace("strings-solve") << "- Verify disequalities are processed for ";
- printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
- Trace("strings-solve") << "..." << std::endl;
-
- //must ensure that normal forms are disequal
- for( unsigned j=0; j<cols[i].size(); j++ ){
- for( unsigned k=(j+1); k<cols[i].size(); k++ ){
- Assert( !d_conflict );
- if( !areDisequal( cols[i][j], cols[i][k] ) ){
- sendSplit( cols[i][j], cols[i][k], "D-NORM", false );
- return;
- }else{
- Trace("strings-solve") << "- Compare ";
- printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
- Trace("strings-solve") << " against ";
- printConcat( d_normal_forms[cols[i][k]], "strings-solve" );
- Trace("strings-solve") << "..." << std::endl;
- if( processDeq( cols[i][j], cols[i][k] ) ){
- return;
- }
- }
- }
- }
- }
- }
+ std::vector< Node > eqcs;
+ getEquivalenceClasses( eqcs );
+ std::vector< std::vector< Node > > cols;
+ std::vector< Node > lts;
+ separateByLength( eqcs, cols, lts );
+ for( unsigned i=0; i<cols.size(); i++ ){
+ if( cols[i].size()>1 && d_lemma_cache.empty() ){
+ Trace("strings-solve") << "- Verify disequalities are processed for ";
+ printConcat( d_normal_forms[cols[i][0]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+
+ //must ensure that normal forms are disequal
+ for( unsigned j=0; j<cols[i].size(); j++ ){
+ for( unsigned k=(j+1); k<cols[i].size(); k++ ){
+ Assert( !d_conflict );
+ if( !areDisequal( cols[i][j], cols[i][k] ) ){
+ sendSplit( cols[i][j], cols[i][k], "D-NORM", false );
+ return;
+ }else{
+ Trace("strings-solve") << "- Compare ";
+ printConcat( d_normal_forms[cols[i][j]], "strings-solve" );
+ Trace("strings-solve") << " against ";
+ printConcat( d_normal_forms[cols[i][k]], "strings-solve" );
+ Trace("strings-solve") << "..." << std::endl;
+ if( processDeq( cols[i][j], cols[i][k] ) ){
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
}
}
bool TheoryStrings::checkLengthsEqc() {
- bool addedLemma = false;
- std::vector< Node > nodes;
- getEquivalenceClasses( nodes );
- for( unsigned i=0; i<nodes.size(); i++ ){
- if( d_normal_forms[nodes[i]].size()>1 ) {
- Trace("strings-process-debug") << "Process length constraints for " << nodes[i] << std::endl;
- //check if there is a length term for this equivalence class
- EqcInfo* ei = getOrMakeEqcInfo( nodes[i], false );
- Node lt = ei ? ei->d_length_term : Node::null();
- if( !lt.isNull() ) {
- Node llt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt );
- //now, check if length normalization has occurred
- if( ei->d_normalized_length.get().isNull() ) {
- //if not, add the lemma
- std::vector< Node > ant;
- ant.insert( ant.end(), d_normal_forms_exp[nodes[i]].begin(), d_normal_forms_exp[nodes[i]].end() );
- ant.push_back( d_normal_forms_base[nodes[i]].eqNode( lt ) );
- Node lc = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, mkConcat( d_normal_forms[nodes[i]] ) );
- lc = Rewriter::rewrite( lc );
- Node eq = llt.eqNode( lc );
- ei->d_normalized_length.set( eq );
- sendLemma( mkExplain( ant ), eq, "LEN-NORM" );
- addedLemma = true;
- }
- }
- } else {
- Trace("strings-process-debug") << "Do not process length constraints for " << nodes[i] << " " << d_normal_forms[nodes[i]].size() << std::endl;
- }
- }
- if( addedLemma ){
- doPendingLemmas();
- }
- return addedLemma;
+ bool addedLemma = false;
+ std::vector< Node > nodes;
+ getEquivalenceClasses( nodes );
+ for( unsigned i=0; i<nodes.size(); i++ ){
+ if( d_normal_forms[nodes[i]].size()>1 ) {
+ Trace("strings-process-debug") << "Process length constraints for " << nodes[i] << std::endl;
+ //check if there is a length term for this equivalence class
+ EqcInfo* ei = getOrMakeEqcInfo( nodes[i], false );
+ Node lt = ei ? ei->d_length_term : Node::null();
+ if( !lt.isNull() ) {
+ Node llt = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, lt );
+ //now, check if length normalization has occurred
+ if( ei->d_normalized_length.get().isNull() ) {
+ //if not, add the lemma
+ std::vector< Node > ant;
+ ant.insert( ant.end(), d_normal_forms_exp[nodes[i]].begin(), d_normal_forms_exp[nodes[i]].end() );
+ ant.push_back( d_normal_forms_base[nodes[i]].eqNode( lt ) );
+ Node lc = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, mkConcat( d_normal_forms[nodes[i]] ) );
+ lc = Rewriter::rewrite( lc );
+ Node eq = llt.eqNode( lc );
+ ei->d_normalized_length.set( eq );
+ sendLemma( mkExplain( ant ), eq, "LEN-NORM" );
+ addedLemma = true;
+ }
+ }
+ } else {
+ Trace("strings-process-debug") << "Do not process length constraints for " << nodes[i] << " " << d_normal_forms[nodes[i]].size() << std::endl;
+ }
+ }
+ if( addedLemma ){
+ doPendingLemmas();
+ }
+ return addedLemma;
}
bool TheoryStrings::checkCardinality() {
}
void TheoryStrings::getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp ) {
- if( n!=d_emptyString ) {
- if( n.getKind()==kind::STRING_CONCAT ) {
- for( unsigned i=0; i<n.getNumChildren(); i++ ) {
- getFinalNormalForm( n[i], nf, exp );
- }
- } else {
- Trace("strings-debug") << "Get final normal form " << n << std::endl;
- Assert( d_equalityEngine.hasTerm( n ) );
- Node nr = d_equalityEngine.getRepresentative( n );
- EqcInfo *eqc_n = getOrMakeEqcInfo( nr, false );
- Node nc = eqc_n ? eqc_n->d_const_term.get() : Node::null();
- if( !nc.isNull() ) {
- nf.push_back( nc );
- if( n!=nc ) {
- exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nc ) );
- }
- } else {
- Assert( d_normal_forms.find( nr )!=d_normal_forms.end() );
- if( d_normal_forms[nr][0]==nr ) {
- Assert( d_normal_forms[nr].size()==1 );
- nf.push_back( nr );
- if( n!=nr ) {
- exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nr ) );
- }
- } else {
- for( unsigned i=0; i<d_normal_forms[nr].size(); i++ ) {
- Assert( d_normal_forms[nr][i]!=nr );
- getFinalNormalForm( d_normal_forms[nr][i], nf, exp );
- }
- exp.insert( exp.end(), d_normal_forms_exp[nr].begin(), d_normal_forms_exp[nr].end() );
- }
- }
- Trace("strings-ind-nf") << "The final normal form of " << n << " is " << nf << std::endl;
- }
- }
+ if( n!=d_emptyString ) {
+ if( n.getKind()==kind::STRING_CONCAT ) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ getFinalNormalForm( n[i], nf, exp );
+ }
+ } else {
+ Trace("strings-debug") << "Get final normal form " << n << std::endl;
+ Assert( d_equalityEngine.hasTerm( n ) );
+ Node nr = d_equalityEngine.getRepresentative( n );
+ EqcInfo *eqc_n = getOrMakeEqcInfo( nr, false );
+ Node nc = eqc_n ? eqc_n->d_const_term.get() : Node::null();
+ if( !nc.isNull() ) {
+ nf.push_back( nc );
+ if( n!=nc ) {
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nc ) );
+ }
+ } else {
+ Assert( d_normal_forms.find( nr )!=d_normal_forms.end() );
+ if( d_normal_forms[nr][0]==nr ) {
+ Assert( d_normal_forms[nr].size()==1 );
+ nf.push_back( nr );
+ if( n!=nr ) {
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n, nr ) );
+ }
+ } else {
+ for( unsigned i=0; i<d_normal_forms[nr].size(); i++ ) {
+ Assert( d_normal_forms[nr][i]!=nr );
+ getFinalNormalForm( d_normal_forms[nr][i], nf, exp );
+ }
+ exp.insert( exp.end(), d_normal_forms_exp[nr].begin(), d_normal_forms_exp[nr].end() );
+ }
+ }
+ Trace("strings-ind-nf") << "The final normal form of " << n << " is " << nf << std::endl;
+ }
+ }
}
void TheoryStrings::separateByLength(std::vector< Node >& n,
std::vector< std::vector< Node > >& cols,
- std::vector< Node >& lts ) {
+ std::vector< Node >& lts ) {
unsigned leqc_counter = 0;
std::map< Node, unsigned > eqc_to_leqc;
std::map< unsigned, Node > leqc_to_eqc;
}
void TheoryStrings::printConcat( std::vector< Node >& n, const char * c ) {
- for( unsigned i=0; i<n.size(); i++ ){
- if( i>0 ) Trace(c) << " ++ ";
- Trace(c) << n[i];
- }
+ for( unsigned i=0; i<n.size(); i++ ){
+ if( i>0 ) Trace(c) << " ++ ";
+ Trace(c) << n[i];
+ }
}
//// Measurements
/*
void TheoryStrings::updateMpl( Node n, int b ) {
- if(d_mpl.find(n) == d_mpl.end()) {
- //d_curr_cardinality.get();
- d_mpl[n] = b;
- } else if(b < d_mpl[n]) {
- d_mpl[n] = b;
- }
+ if(d_mpl.find(n) == d_mpl.end()) {
+ //d_curr_cardinality.get();
+ d_mpl[n] = b;
+ } else if(b < d_mpl[n]) {
+ d_mpl[n] = b;
+ }
}
*/
//// Regular Expressions
Node TheoryStrings::mkRegExpAntec(Node atom, Node ant) {
- if(d_regexp_ant.find(atom) == d_regexp_ant.end()) {
- return Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, ant, atom) );
- } else {
- Node n = d_regexp_ant[atom];
- return Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, ant, n) );
- }
+ if(d_regexp_ant.find(atom) == d_regexp_ant.end()) {
+ return Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, ant, atom) );
+ } else {
+ Node n = d_regexp_ant[atom];
+ return Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, ant, n) );
+ }
}
bool TheoryStrings::checkMemberships() {
- bool addedLemma = false;
- bool changed = false;
- std::vector< Node > processed;
- std::vector< Node > cprocessed;
-
- //if(options::stringEIT()) {
- //TODO: Opt for normal forms
- for(NodeListMap::const_iterator itr_xr = d_str_re_map.begin();
- itr_xr != d_str_re_map.end(); ++itr_xr ) {
- bool spflag = false;
- Node x = (*itr_xr).first;
- NodeList* lst = (*itr_xr).second;
- if(d_inter_index.find(x) == d_inter_index.end()) {
- d_inter_index[x] = 0;
- }
- int cur_inter_idx = d_inter_index[x];
- if(cur_inter_idx != (int)lst->size()) {
- if(lst->size() == 1) {
- d_inter_cache[x] = (*lst)[0];
- d_inter_index[x] = 1;
- } else if(lst->size() > 1) {
- Node r;
- if(d_inter_cache.find(x) != d_inter_cache.end()) {
- r = d_inter_cache[x];
- }
- if(r.isNull()) {
- r = (*lst)[0];
- cur_inter_idx = 1;
- }
- NodeList::const_iterator itr_lst = lst->begin();
- for(int i=0; i<cur_inter_idx; i++) {
- ++itr_lst;
- }
- for(;itr_lst != lst->end(); ++itr_lst) {
- Node r2 = *itr_lst;
- r = d_regexp_opr.intersect(r, r2, spflag);
- if(spflag) {
- break;
- } else if(r == d_emptyRegexp) {
- std::vector< Node > vec_nodes;
- ++itr_lst;
- for(NodeList::const_iterator itr2 = lst->begin();
- itr2 != itr_lst; ++itr2) {
- Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, *itr2);
- vec_nodes.push_back( n );
- }
- Node antec = vec_nodes.size() == 1? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- Node conc;
- sendLemma(antec, conc, "INTERSEC CONFLICT");
- addedLemma = true;
- break;
- }
- if(d_conflict) {
- break;
- }
- }
- //updates
- if(!d_conflict && !spflag) {
- d_inter_cache[x] = r;
- d_inter_index[x] = (int)lst->size();
- }
- }
- }
- }
- //}
-
- if(!addedLemma) {
- for( unsigned i=0; i<d_regexp_memberships.size(); i++ ) {
+ bool addedLemma = false;
+ bool changed = false;
+ std::vector< Node > processed;
+ std::vector< Node > cprocessed;
+
+ //if(options::stringEIT()) {
+ //TODO: Opt for normal forms
+ for(NodeListMap::const_iterator itr_xr = d_str_re_map.begin();
+ itr_xr != d_str_re_map.end(); ++itr_xr ) {
+ bool spflag = false;
+ Node x = (*itr_xr).first;
+ NodeList* lst = (*itr_xr).second;
+ if(d_inter_index.find(x) == d_inter_index.end()) {
+ d_inter_index[x] = 0;
+ }
+ int cur_inter_idx = d_inter_index[x];
+ if(cur_inter_idx != (int)lst->size()) {
+ if(lst->size() == 1) {
+ d_inter_cache[x] = (*lst)[0];
+ d_inter_index[x] = 1;
+ } else if(lst->size() > 1) {
+ Node r;
+ if(d_inter_cache.find(x) != d_inter_cache.end()) {
+ r = d_inter_cache[x];
+ }
+ if(r.isNull()) {
+ r = (*lst)[0];
+ cur_inter_idx = 1;
+ }
+ NodeList::const_iterator itr_lst = lst->begin();
+ for(int i=0; i<cur_inter_idx; i++) {
+ ++itr_lst;
+ }
+ for(;itr_lst != lst->end(); ++itr_lst) {
+ Node r2 = *itr_lst;
+ r = d_regexp_opr.intersect(r, r2, spflag);
+ if(spflag) {
+ break;
+ } else if(r == d_emptyRegexp) {
+ std::vector< Node > vec_nodes;
+ ++itr_lst;
+ for(NodeList::const_iterator itr2 = lst->begin();
+ itr2 != itr_lst; ++itr2) {
+ Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, *itr2);
+ vec_nodes.push_back( n );
+ }
+ Node antec = vec_nodes.size() == 1? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
+ Node conc;
+ sendLemma(antec, conc, "INTERSEC CONFLICT");
+ addedLemma = true;
+ break;
+ }
+ if(d_conflict) {
+ break;
+ }
+ }
+ //updates
+ if(!d_conflict && !spflag) {
+ d_inter_cache[x] = r;
+ d_inter_index[x] = (int)lst->size();
+ }
+ }
+ }
+ }
+ //}
+
+ if(!addedLemma) {
+ for( unsigned i=0; i<d_regexp_memberships.size(); i++ ) {
//check regular expression membership
Node assertion = d_regexp_memberships[i];
- if( d_regexp_ucached.find(assertion) == d_regexp_ucached.end()
+ if( d_regexp_ucached.find(assertion) == d_regexp_ucached.end()
&& d_regexp_ccached.find(assertion) == d_regexp_ccached.end() ) {
Trace("strings-regexp") << "We have regular expression assertion : " << assertion << std::endl;
Node atom = assertion.getKind()==kind::NOT ? assertion[0] : assertion;
Node bi = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
Node bj = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, bi, bj);
- Node g1 = NodeManager::currentNM()->mkNode(kind::AND,
+ Node g1 = NodeManager::currentNM()->mkNode(kind::AND,
NodeManager::currentNM()->mkNode(kind::GEQ, bi, d_zero),
NodeManager::currentNM()->mkNode(kind::GEQ, len1, bi),
NodeManager::currentNM()->mkNode(kind::GEQ, bj, d_zero),
if(d_conflict) {
break;
}
- }
- }
- if( addedLemma ) {
- if( !d_conflict ){
- for( unsigned i=0; i<processed.size(); i++ ) {
- d_regexp_ucached.insert(processed[i]);
- }
- for( unsigned i=0; i<cprocessed.size(); i++ ) {
- d_regexp_ccached.insert(cprocessed[i]);
- }
- }
- doPendingLemmas();
- return true;
- } else {
- return false;
- }
+ }
+ }
+ if( addedLemma ) {
+ if( !d_conflict ){
+ for( unsigned i=0; i<processed.size(); i++ ) {
+ d_regexp_ucached.insert(processed[i]);
+ }
+ for( unsigned i=0; i<cprocessed.size(); i++ ) {
+ d_regexp_ccached.insert(cprocessed[i]);
+ }
+ }
+ doPendingLemmas();
+ return true;
+ } else {
+ return false;
+ }
}
bool TheoryStrings::checkPDerivative(Node x, Node r, Node atom, bool &addedLemma,
- std::vector< Node > &processed, std::vector< Node > &cprocessed, std::vector< Node > &nf_exp) {
- /*if(d_opt_regexp_gcd) {
- if(d_membership_length.find(atom) == d_membership_length.end()) {
- addedLemma = addMembershipLength(atom);
- d_membership_length[atom] = true;
- } else {
- Trace("strings-regexp") << "Membership length is already added." << std::endl;
- }
- }*/
- Node antnf = mkExplain(nf_exp);
-
- if(areEqual(x, d_emptyString)) {
- Node exp;
- switch(d_regexp_opr.delta(r, exp)) {
- case 0: {
- Node antec = mkRegExpAntec(atom, x.eqNode(d_emptyString));
- antec = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, antec, antnf));
- sendLemma(antec, exp, "RegExp Delta");
- addedLemma = true;
- d_regexp_ccached.insert(atom);
- return false;
- }
- case 1: {
- d_regexp_ccached.insert(atom);
- break;
- }
- case 2: {
- Node antec = mkRegExpAntec(atom, x.eqNode(d_emptyString));
- antec = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, antec, antnf));
- Node conc = Node::null();
- sendLemma(antec, conc, "RegExp Delta CONFLICT");
- addedLemma = true;
- d_regexp_ccached.insert(atom);
- return false;
- }
- default:
- //Impossible
- break;
- }
- } else {
- /*Node xr = getRepresentative( x );
- if(x != xr) {
- Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, xr, r);
- Node nn = Rewriter::rewrite( n );
- if(nn == d_true) {
- d_regexp_ccached.insert(atom);
- return false;
- } else if(nn == d_false) {
- Node antec = mkRegExpAntec(atom, x.eqNode(xr));
- Node conc = Node::null();
- sendLemma(antec, conc, "RegExp Delta CONFLICT");
- addedLemma = true;
- d_regexp_ccached.insert(atom);
- return false;
- }
- }*/
- Node sREant = mkRegExpAntec(atom, d_true);
- sREant = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, sREant, antnf));
- if(deriveRegExp( x, r, sREant )) {
- addedLemma = true;
- processed.push_back( atom );
- return false;
- }
- }
- return true;
+ std::vector< Node > &processed, std::vector< Node > &cprocessed, std::vector< Node > &nf_exp) {
+ /*if(d_opt_regexp_gcd) {
+ if(d_membership_length.find(atom) == d_membership_length.end()) {
+ addedLemma = addMembershipLength(atom);
+ d_membership_length[atom] = true;
+ } else {
+ Trace("strings-regexp") << "Membership length is already added." << std::endl;
+ }
+ }*/
+ Node antnf = mkExplain(nf_exp);
+
+ if(areEqual(x, d_emptyString)) {
+ Node exp;
+ switch(d_regexp_opr.delta(r, exp)) {
+ case 0: {
+ Node antec = mkRegExpAntec(atom, x.eqNode(d_emptyString));
+ antec = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, antec, antnf));
+ sendLemma(antec, exp, "RegExp Delta");
+ addedLemma = true;
+ d_regexp_ccached.insert(atom);
+ return false;
+ }
+ case 1: {
+ d_regexp_ccached.insert(atom);
+ break;
+ }
+ case 2: {
+ Node antec = mkRegExpAntec(atom, x.eqNode(d_emptyString));
+ antec = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, antec, antnf));
+ Node conc = Node::null();
+ sendLemma(antec, conc, "RegExp Delta CONFLICT");
+ addedLemma = true;
+ d_regexp_ccached.insert(atom);
+ return false;
+ }
+ default:
+ //Impossible
+ break;
+ }
+ } else {
+ /*Node xr = getRepresentative( x );
+ if(x != xr) {
+ Node n = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, xr, r);
+ Node nn = Rewriter::rewrite( n );
+ if(nn == d_true) {
+ d_regexp_ccached.insert(atom);
+ return false;
+ } else if(nn == d_false) {
+ Node antec = mkRegExpAntec(atom, x.eqNode(xr));
+ Node conc = Node::null();
+ sendLemma(antec, conc, "RegExp Delta CONFLICT");
+ addedLemma = true;
+ d_regexp_ccached.insert(atom);
+ return false;
+ }
+ }*/
+ Node sREant = mkRegExpAntec(atom, d_true);
+ sREant = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, sREant, antnf));
+ if(deriveRegExp( x, r, sREant )) {
+ addedLemma = true;
+ processed.push_back( atom );
+ return false;
+ }
+ }
+ return true;
}
bool TheoryStrings::checkContains() {
- bool addedLemma = checkPosContains();
- Trace("strings-process") << "Done check positive contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkNegContains();
- Trace("strings-process") << "Done check negative contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- }
- return addedLemma;
+ bool addedLemma = checkPosContains();
+ Trace("strings-process") << "Done check positive contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkNegContains();
+ Trace("strings-process") << "Done check negative contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ return addedLemma;
}
bool TheoryStrings::checkPosContains() {
- bool addedLemma = false;
- for( unsigned i=0; i<d_str_pos_ctn.size(); i++ ) {
- if( !d_conflict ){
- Node atom = d_str_pos_ctn[i];
- Trace("strings-ctn") << "We have positive contain assertion : " << atom << std::endl;
- Assert( atom.getKind()==kind::STRING_STRCTN );
- Node x = atom[0];
- Node s = atom[1];
- if( !areEqual( s, d_emptyString ) && !areEqual( s, x ) ) {
- if(d_pos_ctn_cached.find(atom) == d_pos_ctn_cached.end()) {
- Node sk1 = NodeManager::currentNM()->mkSkolem( "sc1", s.getType(), "created for contain" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "sc2", s.getType(), "created for contain" );
- d_statistics.d_new_skolems += 2;
- Node eq = Rewriter::rewrite( x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, s, sk2 ) ) );
- sendLemma( atom, eq, "POS-INC" );
- addedLemma = true;
- d_pos_ctn_cached.insert( atom );
- } else {
- Trace("strings-ctn") << "... is already rewritten." << std::endl;
- }
- } else {
- Trace("strings-ctn") << "... is satisfied." << std::endl;
- }
- }
- }
- if( addedLemma ){
- doPendingLemmas();
- return true;
- } else {
- return false;
- }
+ bool addedLemma = false;
+ for( unsigned i=0; i<d_str_pos_ctn.size(); i++ ) {
+ if( !d_conflict ){
+ Node atom = d_str_pos_ctn[i];
+ Trace("strings-ctn") << "We have positive contain assertion : " << atom << std::endl;
+ Assert( atom.getKind()==kind::STRING_STRCTN );
+ Node x = atom[0];
+ Node s = atom[1];
+ if( !areEqual( s, d_emptyString ) && !areEqual( s, x ) ) {
+ if(d_pos_ctn_cached.find(atom) == d_pos_ctn_cached.end()) {
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "sc1", s.getType(), "created for contain" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "sc2", s.getType(), "created for contain" );
+ d_statistics.d_new_skolems += 2;
+ Node eq = Rewriter::rewrite( x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, s, sk2 ) ) );
+ sendLemma( atom, eq, "POS-INC" );
+ addedLemma = true;
+ d_pos_ctn_cached.insert( atom );
+ } else {
+ Trace("strings-ctn") << "... is already rewritten." << std::endl;
+ }
+ } else {
+ Trace("strings-ctn") << "... is satisfied." << std::endl;
+ }
+ }
+ }
+ if( addedLemma ){
+ doPendingLemmas();
+ return true;
+ } else {
+ return false;
+ }
}
bool TheoryStrings::checkNegContains() {
- bool addedLemma = false;
- for( unsigned i=0; i<d_str_neg_ctn.size(); i++ ){
- if( !d_conflict ){
- Node atom = d_str_neg_ctn[i];
- Trace("strings-ctn") << "We have nagetive contain assertion : (not " << atom << " )" << std::endl;
- if( areEqual( atom[1], d_emptyString ) ) {
- Node ant = NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), atom[1].eqNode( d_emptyString ) );
- Node conc = Node::null();
- sendLemma( ant, conc, "NEG-CTN Conflict 1" );
- addedLemma = true;
- } else if( areEqual( atom[1], atom[0] ) ) {
- Node ant = NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), atom[1].eqNode( atom[0] ) );
- Node conc = Node::null();
- sendLemma( ant, conc, "NEG-CTN Conflict 2" );
- addedLemma = true;
- } else {
- if(options::stringExp()) {
- Node x = atom[0];
- Node s = atom[1];
- Node lenx = getLength(x);
- Node lens = getLength(s);
- if(areEqual(lenx, lens)) {
- if(d_neg_ctn_eqlen.find(atom) == d_neg_ctn_eqlen.end()) {
- Node eq = lenx.eqNode(lens);
- Node antc = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), eq ) );
- Node xneqs = x.eqNode(s).negate();
- d_neg_ctn_eqlen.insert( atom );
- sendLemma( antc, xneqs, "NEG-CTN-EQL" );
- addedLemma = true;
- }
- } else if(!areDisequal(lenx, lens)) {
- if(d_neg_ctn_ulen.find(atom) == d_neg_ctn_ulen.end()) {
- d_neg_ctn_ulen.insert( atom );
- sendSplit(lenx, lens, "NEG-CTN-SP");
- addedLemma = true;
- }
- } else {
- if(d_neg_ctn_cached.find(atom) == d_neg_ctn_cached.end()) {
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::GEQ, b1, d_zero ),
- NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode( kind::MINUS, lenx, lens ), b1 ) ) );
- Node b2 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, x, NodeManager::currentNM()->mkNode( kind::PLUS, b1, b2 ), d_one);
- Node s5 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b2, d_one);
-
- Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b2);//, s1, s3, s4, s6);
-
- std::vector< Node > vec_nodes;
- Node cc = NodeManager::currentNM()->mkNode( kind::GEQ, b2, d_zero );
- vec_nodes.push_back(cc);
- cc = NodeManager::currentNM()->mkNode( kind::GEQ, lens, b2 );
- vec_nodes.push_back(cc);
-
- cc = s2.eqNode(s5).negate();
- vec_nodes.push_back(cc);
-
- Node conc = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, vec_nodes) );
- Node xlss = NodeManager::currentNM()->mkNode( kind::GT, lens, lenx );
- conc = NodeManager::currentNM()->mkNode( kind::OR, xlss, conc );
- conc = NodeManager::currentNM()->mkNode( kind::EXISTS, b2v, conc );
- conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, g1, conc );
- conc = NodeManager::currentNM()->mkNode( kind::FORALL, b1v, conc );
-
- d_neg_ctn_cached.insert( atom );
- sendLemma( atom.negate(), conc, "NEG-CTN-BRK" );
- //d_pending_req_phase[xlss] = true;
- addedLemma = true;
- }
- }
- } else {
- throw LogicException("Strings Incomplete (due to Negative Contain) by default, try --strings-exp option.");
- }
- }
- }
- }
- if( addedLemma ){
- doPendingLemmas();
- return true;
- } else {
- return false;
- }
+ bool addedLemma = false;
+ for( unsigned i=0; i<d_str_neg_ctn.size(); i++ ){
+ if( !d_conflict ){
+ Node atom = d_str_neg_ctn[i];
+ Trace("strings-ctn") << "We have nagetive contain assertion : (not " << atom << " )" << std::endl;
+ if( areEqual( atom[1], d_emptyString ) ) {
+ Node ant = NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), atom[1].eqNode( d_emptyString ) );
+ Node conc = Node::null();
+ sendLemma( ant, conc, "NEG-CTN Conflict 1" );
+ addedLemma = true;
+ } else if( areEqual( atom[1], atom[0] ) ) {
+ Node ant = NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), atom[1].eqNode( atom[0] ) );
+ Node conc = Node::null();
+ sendLemma( ant, conc, "NEG-CTN Conflict 2" );
+ addedLemma = true;
+ } else {
+ if(options::stringExp()) {
+ Node x = atom[0];
+ Node s = atom[1];
+ Node lenx = getLength(x);
+ Node lens = getLength(s);
+ if(areEqual(lenx, lens)) {
+ if(d_neg_ctn_eqlen.find(atom) == d_neg_ctn_eqlen.end()) {
+ Node eq = lenx.eqNode(lens);
+ Node antc = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), eq ) );
+ Node xneqs = x.eqNode(s).negate();
+ d_neg_ctn_eqlen.insert( atom );
+ sendLemma( antc, xneqs, "NEG-CTN-EQL" );
+ addedLemma = true;
+ }
+ } else if(!areDisequal(lenx, lens)) {
+ if(d_neg_ctn_ulen.find(atom) == d_neg_ctn_ulen.end()) {
+ d_neg_ctn_ulen.insert( atom );
+ sendSplit(lenx, lens, "NEG-CTN-SP");
+ addedLemma = true;
+ }
+ } else {
+ if(d_neg_ctn_cached.find(atom) == d_neg_ctn_cached.end()) {
+ Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
+ Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
+ Node g1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::GEQ, b1, d_zero ),
+ NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode( kind::MINUS, lenx, lens ), b1 ) ) );
+ Node b2 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
+ Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, x, NodeManager::currentNM()->mkNode( kind::PLUS, b1, b2 ), d_one);
+ Node s5 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b2, d_one);
+
+ Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b2);//, s1, s3, s4, s6);
+
+ std::vector< Node > vec_nodes;
+ Node cc = NodeManager::currentNM()->mkNode( kind::GEQ, b2, d_zero );
+ vec_nodes.push_back(cc);
+ cc = NodeManager::currentNM()->mkNode( kind::GEQ, lens, b2 );
+ vec_nodes.push_back(cc);
+
+ cc = s2.eqNode(s5).negate();
+ vec_nodes.push_back(cc);
+
+ Node conc = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, vec_nodes) );
+ Node xlss = NodeManager::currentNM()->mkNode( kind::GT, lens, lenx );
+ conc = NodeManager::currentNM()->mkNode( kind::OR, xlss, conc );
+ conc = NodeManager::currentNM()->mkNode( kind::EXISTS, b2v, conc );
+ conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, g1, conc );
+ conc = NodeManager::currentNM()->mkNode( kind::FORALL, b1v, conc );
+
+ d_neg_ctn_cached.insert( atom );
+ sendLemma( atom.negate(), conc, "NEG-CTN-BRK" );
+ //d_pending_req_phase[xlss] = true;
+ addedLemma = true;
+ }
+ }
+ } else {
+ throw LogicException("Strings Incomplete (due to Negative Contain) by default, try --strings-exp option.");
+ }
+ }
+ }
+ }
+ if( addedLemma ){
+ doPendingLemmas();
+ return true;
+ } else {
+ return false;
+ }
}
CVC4::String TheoryStrings::getHeadConst( Node x ) {
- if( x.isConst() ) {
- return x.getConst< String >();
- } else if( x.getKind() == kind::STRING_CONCAT ) {
- if( x[0].isConst() ) {
- return x[0].getConst< String >();
- } else {
- return d_emptyString.getConst< String >();
- }
- } else {
- return d_emptyString.getConst< String >();
- }
+ if( x.isConst() ) {
+ return x.getConst< String >();
+ } else if( x.getKind() == kind::STRING_CONCAT ) {
+ if( x[0].isConst() ) {
+ return x[0].getConst< String >();
+ } else {
+ return d_emptyString.getConst< String >();
+ }
+ } else {
+ return d_emptyString.getConst< String >();
+ }
}
bool TheoryStrings::addMembershipLength(Node atom) {
- //Node x = atom[0];
- //Node r = atom[1];
-
- /*std::vector< int > co;
- co.push_back(0);
- for(unsigned int k=0; k<lts.size(); ++k) {
- if(lts[k].isConst() && lts[k].getType().isInteger()) {
- int len = lts[k].getConst<Rational>().getNumerator().toUnsignedInt();
- co[0] += cols[k].size() * len;
- } else {
- co.push_back( cols[k].size() );
- }
- }
- int g_co = co[0];
- for(unsigned k=1; k<co.size(); ++k) {
- g_co = gcd(g_co, co[k]);
- }*/
- return false;
+ //Node x = atom[0];
+ //Node r = atom[1];
+
+ /*std::vector< int > co;
+ co.push_back(0);
+ for(unsigned int k=0; k<lts.size(); ++k) {
+ if(lts[k].isConst() && lts[k].getType().isInteger()) {
+ int len = lts[k].getConst<Rational>().getNumerator().toUnsignedInt();
+ co[0] += cols[k].size() * len;
+ } else {
+ co.push_back( cols[k].size() );
+ }
+ }
+ int g_co = co[0];
+ for(unsigned k=1; k<co.size(); ++k) {
+ g_co = gcd(g_co, co[k]);
+ }*/
+ return false;
}
bool TheoryStrings::deriveRegExp( Node x, Node r, Node ant ) {
- // TODO cstr in vre
- Assert(x != d_emptyString);
- Trace("regexp-derive") << "TheoryStrings::deriveRegExp: x=" << x << ", r= " << r << std::endl;
- //if(x.isConst()) {
- // Node n = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, x, r );
- // Node r = Rewriter::rewrite( n );
- // if(n != r) {
- // sendLemma(ant, r, "REGEXP REWRITE");
- // return true;
- // }
- //}
- CVC4::String s = getHeadConst( x );
- if( !s.isEmptyString() && d_regexp_opr.checkConstRegExp( r ) ) {
- Node conc = Node::null();
- Node dc = r;
- bool flag = true;
- for(unsigned i=0; i<s.size(); ++i) {
- CVC4::String c = s.substr(i, 1);
- Node dc2;
- int rt = d_regexp_opr.derivativeS(dc, c, dc2);
- if(rt == 0) {
- //TODO
- } else if(rt == 2) {
- // CONFLICT
- flag = false;
- break;
- }
- }
- // send lemma
- if(flag) {
- if(x.isConst()) {
- Assert(false, "Impossible: TheoryStrings::deriveRegExp: const string in const regular expression.");
- return false;
- } else {
- Assert( x.getKind() == kind::STRING_CONCAT );
- std::vector< Node > vec_nodes;
- for(unsigned int i=1; i<x.getNumChildren(); ++i ) {
- vec_nodes.push_back( x[i] );
- }
- Node left = vec_nodes.size() == 1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, vec_nodes );
- left = Rewriter::rewrite( left );
- conc = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, left, dc );
-
- std::vector< Node > sdc;
- d_regexp_opr.simplify(conc, sdc, true);
- if(sdc.size() == 1) {
- conc = sdc[0];
- } else {
- conc = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, conc));
- }
- }
- }
- sendLemma(ant, conc, "RegExp-Derive");
- return true;
- } else {
- return false;
- }
+ // TODO cstr in vre
+ Assert(x != d_emptyString);
+ Trace("regexp-derive") << "TheoryStrings::deriveRegExp: x=" << x << ", r= " << r << std::endl;
+ //if(x.isConst()) {
+ // Node n = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, x, r );
+ // Node r = Rewriter::rewrite( n );
+ // if(n != r) {
+ // sendLemma(ant, r, "REGEXP REWRITE");
+ // return true;
+ // }
+ //}
+ CVC4::String s = getHeadConst( x );
+ if( !s.isEmptyString() && d_regexp_opr.checkConstRegExp( r ) ) {
+ Node conc = Node::null();
+ Node dc = r;
+ bool flag = true;
+ for(unsigned i=0; i<s.size(); ++i) {
+ CVC4::String c = s.substr(i, 1);
+ Node dc2;
+ int rt = d_regexp_opr.derivativeS(dc, c, dc2);
+ if(rt == 0) {
+ //TODO
+ } else if(rt == 2) {
+ // CONFLICT
+ flag = false;
+ break;
+ }
+ }
+ // send lemma
+ if(flag) {
+ if(x.isConst()) {
+ Assert(false, "Impossible: TheoryStrings::deriveRegExp: const string in const regular expression.");
+ return false;
+ } else {
+ Assert( x.getKind() == kind::STRING_CONCAT );
+ std::vector< Node > vec_nodes;
+ for(unsigned int i=1; i<x.getNumChildren(); ++i ) {
+ vec_nodes.push_back( x[i] );
+ }
+ Node left = vec_nodes.size() == 1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, vec_nodes );
+ left = Rewriter::rewrite( left );
+ conc = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, left, dc );
+
+ std::vector< Node > sdc;
+ d_regexp_opr.simplify(conc, sdc, true);
+ if(sdc.size() == 1) {
+ conc = sdc[0];
+ } else {
+ conc = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, conc));
+ }
+ }
+ }
+ sendLemma(ant, conc, "RegExp-Derive");
+ return true;
+ } else {
+ return false;
+ }
}
void TheoryStrings::addMembership(Node assertion) {
- bool polarity = assertion.getKind() != kind::NOT;
- TNode atom = polarity ? assertion : assertion[0];
- Node x = atom[0];
- Node r = atom[1];
- if(polarity) {
- NodeList* lst;
- NodeListMap::iterator itr_xr = d_str_re_map.find( x );
- if( itr_xr == d_str_re_map.end() ){
- lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
- d_str_re_map.insertDataFromContextMemory( x, lst );
- } else {
- lst = (*itr_xr).second;
- }
- //check
- for( NodeList::const_iterator itr = lst->begin(); itr != lst->end(); ++itr ) {
- if( r == *itr ) {
- return;
- }
- }
- lst->push_back( r );
- }/* else {
- if(options::stringEIT() && d_regexp_opr.checkConstRegExp(r)) {
- int rt;
- Node r2 = d_regexp_opr.complement(r, rt);
- Node a = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, r2);
- d_regexp_memberships.push_back( a );
- } else {
- d_regexp_memberships.push_back( assertion );
- }
- }*/
- d_regexp_memberships.push_back( assertion );
+ bool polarity = assertion.getKind() != kind::NOT;
+ TNode atom = polarity ? assertion : assertion[0];
+ Node x = atom[0];
+ Node r = atom[1];
+ if(polarity) {
+ NodeList* lst;
+ NodeListMap::iterator itr_xr = d_str_re_map.find( x );
+ if( itr_xr == d_str_re_map.end() ){
+ lst = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_str_re_map.insertDataFromContextMemory( x, lst );
+ } else {
+ lst = (*itr_xr).second;
+ }
+ //check
+ for( NodeList::const_iterator itr = lst->begin(); itr != lst->end(); ++itr ) {
+ if( r == *itr ) {
+ return;
+ }
+ }
+ lst->push_back( r );
+ }/* else {
+ if(options::stringEIT() && d_regexp_opr.checkConstRegExp(r)) {
+ int rt;
+ Node r2 = d_regexp_opr.complement(r, rt);
+ Node a = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, x, r2);
+ d_regexp_memberships.push_back( a );
+ } else {
+ d_regexp_memberships.push_back( assertion );
+ }
+ }*/
+ d_regexp_memberships.push_back( assertion );
}
Node TheoryStrings::getNormalString(Node x, std::vector<Node> &nf_exp) {
- Node ret = x;
- if(x.getKind() == kind::STRING_CONCAT) {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<x.getNumChildren(); i++) {
- if(x[i].isConst()) {
- vec_nodes.push_back(x[i]);
- } else {
- Node tmp = x[i];
- if(d_normal_forms.find( tmp ) != d_normal_forms.end()) {
- Trace("regexp-debug") << "Term: " << tmp << " has a normal form." << std::endl;
- vec_nodes.insert(vec_nodes.end(), d_normal_forms[tmp].begin(), d_normal_forms[tmp].end());
- nf_exp.insert(nf_exp.end(), d_normal_forms_exp[tmp].begin(), d_normal_forms_exp[tmp].end());
- } else {
- Trace("regexp-debug") << "Term: " << tmp << " has NO normal form." << std::endl;
- vec_nodes.push_back(tmp);
- }
- }
- }
- ret = mkConcat(vec_nodes);
- } else {
- if(d_normal_forms.find( x ) != d_normal_forms.end()) {
- ret = mkConcat( d_normal_forms[x] );
- nf_exp.insert(nf_exp.end(), d_normal_forms_exp[x].begin(), d_normal_forms_exp[x].end());
- Trace("regexp-debug") << "Term: " << x << " has a normal form " << ret << std::endl;
- } else {
- Trace("regexp-debug") << "Term: " << x << " has NO normal form." << std::endl;
- }
- }
- return ret;
+ Node ret = x;
+ if(x.getKind() == kind::STRING_CONCAT) {
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<x.getNumChildren(); i++) {
+ if(x[i].isConst()) {
+ vec_nodes.push_back(x[i]);
+ } else {
+ Node tmp = x[i];
+ if(d_normal_forms.find( tmp ) != d_normal_forms.end()) {
+ Trace("regexp-debug") << "Term: " << tmp << " has a normal form." << std::endl;
+ vec_nodes.insert(vec_nodes.end(), d_normal_forms[tmp].begin(), d_normal_forms[tmp].end());
+ nf_exp.insert(nf_exp.end(), d_normal_forms_exp[tmp].begin(), d_normal_forms_exp[tmp].end());
+ } else {
+ Trace("regexp-debug") << "Term: " << tmp << " has NO normal form." << std::endl;
+ vec_nodes.push_back(tmp);
+ }
+ }
+ }
+ ret = mkConcat(vec_nodes);
+ } else {
+ if(d_normal_forms.find( x ) != d_normal_forms.end()) {
+ ret = mkConcat( d_normal_forms[x] );
+ nf_exp.insert(nf_exp.end(), d_normal_forms_exp[x].begin(), d_normal_forms_exp[x].end());
+ Trace("regexp-debug") << "Term: " << x << " has a normal form " << ret << std::endl;
+ } else {
+ Trace("regexp-debug") << "Term: " << x << " has NO normal form." << std::endl;
+ }
+ }
+ return ret;
}
Node TheoryStrings::getNormalSymRegExp(Node r, std::vector<Node> &nf_exp) {
- Node ret = r;
- switch( r.getKind() ) {
- case kind::REGEXP_EMPTY:
- case kind::REGEXP_SIGMA:
- break;
- case kind::STRING_TO_REGEXP: {
- if(!r[0].isConst()) {
- Node tmp = getNormalString( r[0], nf_exp );
- if(tmp != r[0]) {
- ret = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, tmp);
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- vec_nodes.push_back( getNormalSymRegExp(r[i], nf_exp) );
- }
- ret = mkConcat(vec_nodes);
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- vec_nodes.push_back( getNormalSymRegExp(r[i], nf_exp) );
- }
- ret = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes) );
- break;
- }
- case kind::REGEXP_INTER: {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- vec_nodes.push_back( getNormalSymRegExp(r[i], nf_exp) );
- }
- ret = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_INTER, vec_nodes) );
- break;
- }
- case kind::REGEXP_STAR: {
- ret = getNormalSymRegExp( r[0], nf_exp );
- ret = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, ret) );
- break;
- }
- //case kind::REGEXP_PLUS:
- //case kind::REGEXP_OPT:
- //case kind::REGEXP_RANGE:
- default: {
- Trace("strings-error") << "Unsupported term: " << r << " in normalization SymRegExp." << std::endl;
- Assert( false );
- //return Node::null();
- }
- }
-
- return ret;
+ Node ret = r;
+ switch( r.getKind() ) {
+ case kind::REGEXP_EMPTY:
+ case kind::REGEXP_SIGMA:
+ break;
+ case kind::STRING_TO_REGEXP: {
+ if(!r[0].isConst()) {
+ Node tmp = getNormalString( r[0], nf_exp );
+ if(tmp != r[0]) {
+ ret = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, tmp);
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ vec_nodes.push_back( getNormalSymRegExp(r[i], nf_exp) );
+ }
+ ret = mkConcat(vec_nodes);
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ vec_nodes.push_back( getNormalSymRegExp(r[i], nf_exp) );
+ }
+ ret = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes) );
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ vec_nodes.push_back( getNormalSymRegExp(r[i], nf_exp) );
+ }
+ ret = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_INTER, vec_nodes) );
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ ret = getNormalSymRegExp( r[0], nf_exp );
+ ret = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, ret) );
+ break;
+ }
+ //case kind::REGEXP_PLUS:
+ //case kind::REGEXP_OPT:
+ //case kind::REGEXP_RANGE:
+ default: {
+ Trace("strings-error") << "Unsupported term: " << r << " in normalization SymRegExp." << std::endl;
+ Assert( false );
+ //return Node::null();
+ }
+ }
+
+ return ret;
}
//// Finite Model Finding
Node TheoryStrings::getNextDecisionRequest() {
- if(d_opt_fmf && !d_conflict) {
- Node in_var_lsum = d_input_var_lsum.get();
- //Trace("strings-fmf-debug") << "Strings::FMF: Assertion Level = " << d_valuation.getAssertionLevel() << std::endl;
- //initialize the term we will minimize
- if( in_var_lsum.isNull() && !d_input_vars.empty() ){
- Trace("strings-fmf-debug") << "Input variables: ";
- std::vector< Node > ll;
- for(NodeSet::const_iterator itr = d_input_vars.begin();
- itr != d_input_vars.end(); ++itr) {
- Trace("strings-fmf-debug") << " " << (*itr) ;
- ll.push_back( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr ) );
- }
- Trace("strings-fmf-debug") << std::endl;
- in_var_lsum = ll.size()==1 ? ll[0] : NodeManager::currentNM()->mkNode( kind::PLUS, ll );
- in_var_lsum = Rewriter::rewrite( in_var_lsum );
- d_input_var_lsum.set( in_var_lsum );
- }
- if( !in_var_lsum.isNull() ){
- //Trace("strings-fmf") << "Get next decision request." << std::endl;
- //check if we need to decide on something
- int decideCard = d_curr_cardinality.get();
- if( d_cardinality_lits.find( decideCard )!=d_cardinality_lits.end() ){
- bool value;
- Node cnode = d_cardinality_lits[ d_curr_cardinality.get() ];
- if( d_valuation.hasSatValue( cnode, value ) ) {
- if( !value ){
- d_curr_cardinality.set( d_curr_cardinality.get() + 1 );
- decideCard = d_curr_cardinality.get();
- Trace("strings-fmf-debug") << "Has false SAT value, increment and decide." << std::endl;
- }else{
- decideCard = -1;
- Trace("strings-fmf-debug") << "Has true SAT value, do not decide." << std::endl;
- }
- }else{
- Trace("strings-fmf-debug") << "No SAT value, decide." << std::endl;
- }
- }
- if( decideCard!=-1 ){
- if( d_cardinality_lits.find( decideCard )==d_cardinality_lits.end() ){
- Node lit = NodeManager::currentNM()->mkNode( kind::LEQ, in_var_lsum, NodeManager::currentNM()->mkConst( Rational( decideCard ) ) );
- lit = Rewriter::rewrite( lit );
- d_cardinality_lits[decideCard] = lit;
- Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit, lit.negate() );
- Trace("strings-fmf") << "Strings::FMF: Add decision lemma " << lem << ", decideCard = " << decideCard << std::endl;
- d_out->lemma( lem );
- d_out->requirePhase( lit, true );
- }
- Node lit = d_cardinality_lits[ decideCard ];
- Trace("strings-fmf") << "Strings::FMF: Decide positive on " << lit << std::endl;
- return lit;
- }
- }
- }
-
- return Node::null();
+ if(d_opt_fmf && !d_conflict) {
+ Node in_var_lsum = d_input_var_lsum.get();
+ //Trace("strings-fmf-debug") << "Strings::FMF: Assertion Level = " << d_valuation.getAssertionLevel() << std::endl;
+ //initialize the term we will minimize
+ if( in_var_lsum.isNull() && !d_input_vars.empty() ){
+ Trace("strings-fmf-debug") << "Input variables: ";
+ std::vector< Node > ll;
+ for(NodeSet::const_iterator itr = d_input_vars.begin();
+ itr != d_input_vars.end(); ++itr) {
+ Trace("strings-fmf-debug") << " " << (*itr) ;
+ ll.push_back( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, *itr ) );
+ }
+ Trace("strings-fmf-debug") << std::endl;
+ in_var_lsum = ll.size()==1 ? ll[0] : NodeManager::currentNM()->mkNode( kind::PLUS, ll );
+ in_var_lsum = Rewriter::rewrite( in_var_lsum );
+ d_input_var_lsum.set( in_var_lsum );
+ }
+ if( !in_var_lsum.isNull() ){
+ //Trace("strings-fmf") << "Get next decision request." << std::endl;
+ //check if we need to decide on something
+ int decideCard = d_curr_cardinality.get();
+ if( d_cardinality_lits.find( decideCard )!=d_cardinality_lits.end() ){
+ bool value;
+ Node cnode = d_cardinality_lits[ d_curr_cardinality.get() ];
+ if( d_valuation.hasSatValue( cnode, value ) ) {
+ if( !value ){
+ d_curr_cardinality.set( d_curr_cardinality.get() + 1 );
+ decideCard = d_curr_cardinality.get();
+ Trace("strings-fmf-debug") << "Has false SAT value, increment and decide." << std::endl;
+ }else{
+ decideCard = -1;
+ Trace("strings-fmf-debug") << "Has true SAT value, do not decide." << std::endl;
+ }
+ }else{
+ Trace("strings-fmf-debug") << "No SAT value, decide." << std::endl;
+ }
+ }
+ if( decideCard!=-1 ){
+ if( d_cardinality_lits.find( decideCard )==d_cardinality_lits.end() ){
+ Node lit = NodeManager::currentNM()->mkNode( kind::LEQ, in_var_lsum, NodeManager::currentNM()->mkConst( Rational( decideCard ) ) );
+ lit = Rewriter::rewrite( lit );
+ d_cardinality_lits[decideCard] = lit;
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit, lit.negate() );
+ Trace("strings-fmf") << "Strings::FMF: Add decision lemma " << lem << ", decideCard = " << decideCard << std::endl;
+ d_out->lemma( lem );
+ d_out->requirePhase( lit, true );
+ }
+ Node lit = d_cardinality_lits[ decideCard ];
+ Trace("strings-fmf") << "Strings::FMF: Decide positive on " << lit << std::endl;
+ return lit;
+ }
+ }
+ }
+
+ return Node::null();
}
void TheoryStrings::assertNode( Node lit ) {
}
Node TheoryStrings::mkSplitEq( const char * c, const char * info, Node lhs, Node rhs, bool lgtZero ) {
- Node sk = NodeManager::currentNM()->mkSkolem( c, NodeManager::currentNM()->stringType(), info );
- d_statistics.d_new_skolems += 1;
- Node cc = mkConcat( rhs, sk );
- //if(rhs.isConst()) {
- // d_length_inst[cc] = lhs;
- //}
- Node eq = lhs.eqNode( cc );
- eq = Rewriter::rewrite( eq );
- if( lgtZero ) {
- Node sk_gt_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, d_emptyString).negate();
- Trace("strings-lemma") << "Strings::Lemma SK-NON-EMPTY: " << sk_gt_zero << std::endl;
- d_lemma_cache.push_back( sk_gt_zero );
- }
- return eq;
+ Node sk = NodeManager::currentNM()->mkSkolem( c, NodeManager::currentNM()->stringType(), info );
+ d_statistics.d_new_skolems += 1;
+ Node cc = mkConcat( rhs, sk );
+ //if(rhs.isConst()) {
+ // d_length_inst[cc] = lhs;
+ //}
+ Node eq = lhs.eqNode( cc );
+ eq = Rewriter::rewrite( eq );
+ if( lgtZero ) {
+ Node sk_gt_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, d_emptyString).negate();
+ Trace("strings-lemma") << "Strings::Lemma SK-NON-EMPTY: " << sk_gt_zero << std::endl;
+ d_lemma_cache.push_back( sk_gt_zero );
+ }
+ return eq;
}
// Stats
*/
class TheoryStrings : public Theory {
- typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
- typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
- typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
- typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
- typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+ typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
public:
- TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
- ~TheoryStrings();
+ TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
+ ~TheoryStrings();
- void setMasterEqualityEngine(eq::EqualityEngine* eq);
+ void setMasterEqualityEngine(eq::EqualityEngine* eq);
- std::string identify() const { return std::string("TheoryStrings"); }
+ std::string identify() const { return std::string("TheoryStrings"); }
public:
- void propagate(Effort e);
- bool propagate(TNode literal);
- void explain( TNode literal, std::vector<TNode>& assumptions );
- Node explain( TNode literal );
-
-
- // NotifyClass for equality engine
- class NotifyClass : public eq::EqualityEngineNotify {
- TheoryStrings& d_str;
- public:
- NotifyClass(TheoryStrings& t_str): d_str(t_str) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) {
- Debug("strings") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
- if (value) {
- return d_str.propagate(equality);
- } else {
+ void propagate(Effort e);
+ bool propagate(TNode literal);
+ void explain( TNode literal, std::vector<TNode>& assumptions );
+ Node explain( TNode literal );
+
+
+ // NotifyClass for equality engine
+ class NotifyClass : public eq::EqualityEngineNotify {
+ TheoryStrings& d_str;
+ public:
+ NotifyClass(TheoryStrings& t_str): d_str(t_str) {}
+ bool eqNotifyTriggerEquality(TNode equality, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
+ if (value) {
+ return d_str.propagate(equality);
+ } else {
// We use only literal triggers so taking not is safe
return d_str.propagate(equality.notNode());
- }
- }
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
- Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
- if (value) {
+ }
+ }
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
return d_str.propagate(predicate);
- } else {
+ } else {
return d_str.propagate(predicate.notNode());
- }
- }
- bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
- Debug("strings") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl;
- if (value) {
- return d_str.propagate(t1.eqNode(t2));
- } else {
- return d_str.propagate(t1.eqNode(t2).notNode());
- }
- }
- void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
- Debug("strings") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
- d_str.conflict(t1, t2);
- }
- void eqNotifyNewClass(TNode t) {
- Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t << std::endl;
- d_str.eqNotifyNewClass(t);
- }
- void eqNotifyPreMerge(TNode t1, TNode t2) {
- Debug("strings") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl;
- d_str.eqNotifyPreMerge(t1, t2);
- }
- void eqNotifyPostMerge(TNode t1, TNode t2) {
- Debug("strings") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl;
- d_str.eqNotifyPostMerge(t1, t2);
- }
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
- Debug("strings") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl;
- d_str.eqNotifyDisequal(t1, t2, reason);
- }
- };/* class TheoryStrings::NotifyClass */
+ }
+ }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("strings") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl;
+ if (value) {
+ return d_str.propagate(t1.eqNode(t2));
+ } else {
+ return d_str.propagate(t1.eqNode(t2).notNode());
+ }
+ }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
+ d_str.conflict(t1, t2);
+ }
+ void eqNotifyNewClass(TNode t) {
+ Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t << std::endl;
+ d_str.eqNotifyNewClass(t);
+ }
+ void eqNotifyPreMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl;
+ d_str.eqNotifyPreMerge(t1, t2);
+ }
+ void eqNotifyPostMerge(TNode t1, TNode t2) {
+ Debug("strings") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl;
+ d_str.eqNotifyPostMerge(t1, t2);
+ }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Debug("strings") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl;
+ d_str.eqNotifyDisequal(t1, t2, reason);
+ }
+ };/* class TheoryStrings::NotifyClass */
private:
- /**
- * Function symbol used to implement uninterpreted undefined string
- * semantics. Needed to deal with partial charat/substr function.
- */
- Node d_ufSubstr;
+ /**
+ * Function symbol used to implement uninterpreted undefined string
+ * semantics. Needed to deal with partial charat/substr function.
+ */
+ Node d_ufSubstr;
- // Constants
+ // Constants
Node d_emptyString;
- Node d_emptyRegexp;
+ Node d_emptyRegexp;
Node d_true;
Node d_false;
Node d_zero;
- Node d_one;
- // Options
- bool d_opt_fmf;
- bool d_opt_regexp_gcd;
- // Helper functions
- Node getRepresentative( Node t );
- bool hasTerm( Node a );
- bool areEqual( Node a, Node b );
- bool areDisequal( Node a, Node b );
- Node getLengthTerm( Node t );
- Node getLength( Node t );
+ Node d_one;
+ // Options
+ bool d_opt_fmf;
+ bool d_opt_regexp_gcd;
+ // Helper functions
+ Node getRepresentative( Node t );
+ bool hasTerm( Node a );
+ bool areEqual( Node a, Node b );
+ bool areDisequal( Node a, Node b );
+ Node getLengthTerm( Node t );
+ Node getLength( Node t );
private:
/** The notify class */
eq::EqualityEngine d_equalityEngine;
/** Are we in conflict */
context::CDO<bool> d_conflict;
- //list of pairs of nodes to merge
- std::map< Node, Node > d_pending_exp;
- std::vector< Node > d_pending;
- std::vector< Node > d_lemma_cache;
- std::map< Node, bool > d_pending_req_phase;
- /** inferences */
- NodeList d_infer;
- NodeList d_infer_exp;
- /** normal forms */
- std::map< Node, Node > d_normal_forms_base;
- std::map< Node, std::vector< Node > > d_normal_forms;
- std::map< Node, std::vector< Node > > d_normal_forms_exp;
- //map of pairs of terms that have the same normal form
- NodeListMap d_nf_pairs;
- void addNormalFormPair( Node n1, Node n2 );
- bool isNormalFormPair( Node n1, Node n2 );
- bool isNormalFormPair2( Node n1, Node n2 );
- // loop ant
- NodeSet d_loop_antec;
- NodeSet d_length_intro_vars;
- // preReg cache
- NodeSet d_prereg_cached;
-
- /////////////////////////////////////////////////////////////////////////////
- // MODEL GENERATION
- /////////////////////////////////////////////////////////////////////////////
+ //list of pairs of nodes to merge
+ std::map< Node, Node > d_pending_exp;
+ std::vector< Node > d_pending;
+ std::vector< Node > d_lemma_cache;
+ std::map< Node, bool > d_pending_req_phase;
+ /** inferences */
+ NodeList d_infer;
+ NodeList d_infer_exp;
+ /** normal forms */
+ std::map< Node, Node > d_normal_forms_base;
+ std::map< Node, std::vector< Node > > d_normal_forms;
+ std::map< Node, std::vector< Node > > d_normal_forms_exp;
+ //map of pairs of terms that have the same normal form
+ NodeListMap d_nf_pairs;
+ void addNormalFormPair( Node n1, Node n2 );
+ bool isNormalFormPair( Node n1, Node n2 );
+ bool isNormalFormPair2( Node n1, Node n2 );
+ // loop ant
+ NodeSet d_loop_antec;
+ NodeSet d_length_intro_vars;
+ // preReg cache
+ NodeSet d_prereg_cached;
+
+ /////////////////////////////////////////////////////////////////////////////
+ // MODEL GENERATION
+ /////////////////////////////////////////////////////////////////////////////
public:
- void collectModelInfo(TheoryModel* m, bool fullModel);
+ void collectModelInfo(TheoryModel* m, bool fullModel);
- /////////////////////////////////////////////////////////////////////////////
- // NOTIFICATIONS
- /////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////
+ // NOTIFICATIONS
+ /////////////////////////////////////////////////////////////////////////////
public:
- void presolve();
- void shutdown() { }
+ void presolve();
+ void shutdown() { }
- /////////////////////////////////////////////////////////////////////////////
- // MAIN SOLVER
- /////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////
+ // MAIN SOLVER
+ /////////////////////////////////////////////////////////////////////////////
private:
- void addSharedTerm(TNode n);
- EqualityStatus getEqualityStatus(TNode a, TNode b);
+ void addSharedTerm(TNode n);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
private:
- class EqcInfo {
- public:
- EqcInfo( context::Context* c );
- ~EqcInfo(){}
- //constant in this eqc
- context::CDO< Node > d_const_term;
- context::CDO< Node > d_length_term;
- context::CDO< unsigned > d_cardinality_lem_k;
- // 1 = added length lemma
- context::CDO< Node > d_normalized_length;
- };
- /** map from representatives to information necessary for equivalence classes */
- std::map< Node, EqcInfo* > d_eqc_info;
- EqcInfo * getOrMakeEqcInfo( Node eqc, bool doMake = true );
- //maintain which concat terms have the length lemma instantiated
- NodeSet d_length_nodes;
- NodeNodeMap d_length_inst;
+ class EqcInfo {
+ public:
+ EqcInfo( context::Context* c );
+ ~EqcInfo(){}
+ //constant in this eqc
+ context::CDO< Node > d_const_term;
+ context::CDO< Node > d_length_term;
+ context::CDO< unsigned > d_cardinality_lem_k;
+ // 1 = added length lemma
+ context::CDO< Node > d_normalized_length;
+ };
+ /** map from representatives to information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ EqcInfo * getOrMakeEqcInfo( Node eqc, bool doMake = true );
+ //maintain which concat terms have the length lemma instantiated
+ NodeSet d_length_nodes;
+ NodeNodeMap d_length_inst;
private:
- void mergeCstVec(std::vector< Node > &vec_strings);
+ void mergeCstVec(std::vector< Node > &vec_strings);
bool getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
std::vector< std::vector< Node > > &normal_forms,
std::vector< std::vector< Node > > &normal_forms_exp,
std::vector< Node > &normal_form_src);
- bool detectLoop(std::vector< std::vector< Node > > &normal_forms,
- int i, int j, int index_i, int index_j,
+ bool detectLoop(std::vector< std::vector< Node > > &normal_forms,
+ int i, int j, int index_i, int index_j,
int &loop_in_i, int &loop_in_j);
- bool processLoop(std::vector< Node > &antec,
+ bool processLoop(std::vector< Node > &antec,
std::vector< std::vector< Node > > &normal_forms,
std::vector< Node > &normal_form_src,
int i, int j, int loop_n_index, int other_n_index,
int loop_index, int index, int other_index);
- bool processNEqc(std::vector< std::vector< Node > > &normal_forms,
+ bool processNEqc(std::vector< std::vector< Node > > &normal_forms,
std::vector< std::vector< Node > > &normal_forms_exp,
std::vector< Node > &normal_form_src);
- bool processReverseNEq(std::vector< std::vector< Node > > &normal_forms,
+ bool processReverseNEq(std::vector< std::vector< Node > > &normal_forms,
std::vector< Node > &normal_form_src, std::vector< Node > &curr_exp, unsigned i, unsigned j );
- bool processSimpleNEq( std::vector< std::vector< Node > > &normal_forms,
+ bool processSimpleNEq( std::vector< std::vector< Node > > &normal_forms,
std::vector< Node > &normal_form_src, std::vector< Node > &curr_exp, unsigned i, unsigned j,
unsigned& index_i, unsigned& index_j, bool isRev );
bool normalizeEquivalenceClass( Node n, std::vector< Node > & visited, std::vector< Node > & nf, std::vector< Node > & nf_exp );
bool processDeq( Node n1, Node n2 );
- int processReverseDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj );
- int processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj, unsigned& index, bool isRev );
- //bool unrollStar( Node atom );
- Node mkRegExpAntec(Node atom, Node ant);
+ int processReverseDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj );
+ int processSimpleDeq( std::vector< Node >& nfi, std::vector< Node >& nfj, Node ni, Node nj, unsigned& index, bool isRev );
+ //bool unrollStar( Node atom );
+ Node mkRegExpAntec(Node atom, Node ant);
- bool checkSimple();
+ bool checkSimple();
bool checkNormalForms();
- void checkDeqNF();
- bool checkLengthsEqc();
+ void checkDeqNF();
+ bool checkLengthsEqc();
bool checkCardinality();
bool checkInductiveEquations();
- bool checkMemberships();
- bool checkPDerivative(Node x, Node r, Node atom, bool &addedLemma,
- std::vector< Node > &processed, std::vector< Node > &cprocessed,
- std::vector< Node > &nf_exp);
- bool checkContains();
- bool checkPosContains();
- bool checkNegContains();
+ bool checkMemberships();
+ bool checkPDerivative(Node x, Node r, Node atom, bool &addedLemma,
+ std::vector< Node > &processed, std::vector< Node > &cprocessed,
+ std::vector< Node > &nf_exp);
+ bool checkContains();
+ bool checkPosContains();
+ bool checkNegContains();
public:
- void preRegisterTerm(TNode n);
- Node expandDefinition(LogicRequest &logicRequest, Node n);
- void check(Effort e);
-
- /** Conflict when merging two constants */
- void conflict(TNode a, TNode b);
- /** called when a new equivalence class is created */
- void eqNotifyNewClass(TNode t);
- /** called when two equivalence classes will merge */
- void eqNotifyPreMerge(TNode t1, TNode t2);
- /** called when two equivalence classes have merged */
- void eqNotifyPostMerge(TNode t1, TNode t2);
- /** called when two equivalence classes are made disequal */
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+ void preRegisterTerm(TNode n);
+ Node expandDefinition(LogicRequest &logicRequest, Node n);
+ void check(Effort e);
+
+ /** Conflict when merging two constants */
+ void conflict(TNode a, TNode b);
+ /** called when a new equivalence class is created */
+ void eqNotifyNewClass(TNode t);
+ /** called when two equivalence classes will merge */
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes have merged */
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes are made disequal */
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
protected:
- /** compute care graph */
- void computeCareGraph();
-
- //do pending merges
- void doPendingFacts();
- void doPendingLemmas();
-
- void sendLemma( Node ant, Node conc, const char * c );
- void sendInfer( Node eq_exp, Node eq, const char * c );
- void sendSplit( Node a, Node b, const char * c, bool preq = true );
- /** mkConcat **/
- inline Node mkConcat( Node n1, Node n2 );
- inline Node mkConcat( std::vector< Node >& c );
- /** mkExplain **/
- Node mkExplain( std::vector< Node >& a );
- Node mkExplain( std::vector< Node >& a, std::vector< Node >& an );
- /** mkAnd **/
- Node mkAnd( std::vector< Node >& a );
- /** get concat vector */
- void getConcatVec( Node n, std::vector< Node >& c );
-
- //get equivalence classes
- void getEquivalenceClasses( std::vector< Node >& eqcs );
- //get final normal form
- void getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp );
-
- //separate into collections with equal length
- void separateByLength( std::vector< Node >& n, std::vector< std::vector< Node > >& col, std::vector< Node >& lts );
- void printConcat( std::vector< Node >& n, const char * c );
+ /** compute care graph */
+ void computeCareGraph();
+
+ //do pending merges
+ void doPendingFacts();
+ void doPendingLemmas();
+
+ void sendLemma( Node ant, Node conc, const char * c );
+ void sendInfer( Node eq_exp, Node eq, const char * c );
+ void sendSplit( Node a, Node b, const char * c, bool preq = true );
+ /** mkConcat **/
+ inline Node mkConcat( Node n1, Node n2 );
+ inline Node mkConcat( std::vector< Node >& c );
+ /** mkExplain **/
+ Node mkExplain( std::vector< Node >& a );
+ Node mkExplain( std::vector< Node >& a, std::vector< Node >& an );
+ /** mkAnd **/
+ Node mkAnd( std::vector< Node >& a );
+ /** get concat vector */
+ void getConcatVec( Node n, std::vector< Node >& c );
+
+ //get equivalence classes
+ void getEquivalenceClasses( std::vector< Node >& eqcs );
+ //get final normal form
+ void getFinalNormalForm( Node n, std::vector< Node >& nf, std::vector< Node >& exp );
+
+ //separate into collections with equal length
+ void separateByLength( std::vector< Node >& n, std::vector< std::vector< Node > >& col, std::vector< Node >& lts );
+ void printConcat( std::vector< Node >& n, const char * c );
private:
- Node mkSplitEq( const char * c, const char * info, Node lhs, Node rhs, bool lgtZero );
+ Node mkSplitEq( const char * c, const char * info, Node lhs, Node rhs, bool lgtZero );
- // Special String Functions
- NodeList d_str_pos_ctn;
- NodeList d_str_neg_ctn;
- NodeSet d_neg_ctn_eqlen;
- NodeSet d_neg_ctn_ulen;
- NodeSet d_pos_ctn_cached;
- NodeSet d_neg_ctn_cached;
+ // Special String Functions
+ NodeList d_str_pos_ctn;
+ NodeList d_str_neg_ctn;
+ NodeSet d_neg_ctn_eqlen;
+ NodeSet d_neg_ctn_ulen;
+ NodeSet d_pos_ctn_cached;
+ NodeSet d_neg_ctn_cached;
- // Symbolic Regular Expression
+ // Symbolic Regular Expression
private:
- // regular expression memberships
- NodeList d_regexp_memberships;
- NodeSet d_regexp_ucached;
- NodeSet d_regexp_ccached;
- // intersection
- NodeListMap d_str_re_map;
- NodeNodeMap d_inter_cache;
- NodeIntMap d_inter_index;
- // antecedant for why regexp membership must be true
- NodeNodeMap d_regexp_ant;
- // membership length
- //std::map< Node, bool > d_membership_length;
- // regular expression operations
- RegExpOpr d_regexp_opr;
-
- CVC4::String getHeadConst( Node x );
- bool deriveRegExp( Node x, Node r, Node ant );
- bool addMembershipLength(Node atom);
- void addMembership(Node assertion);
- Node getNormalString(Node x, std::vector<Node> &nf_exp);
- Node getNormalSymRegExp(Node r, std::vector<Node> &nf_exp);
-
-
- // Finite Model Finding
+ // regular expression memberships
+ NodeList d_regexp_memberships;
+ NodeSet d_regexp_ucached;
+ NodeSet d_regexp_ccached;
+ // intersection
+ NodeListMap d_str_re_map;
+ NodeNodeMap d_inter_cache;
+ NodeIntMap d_inter_index;
+ // antecedant for why regexp membership must be true
+ NodeNodeMap d_regexp_ant;
+ // membership length
+ //std::map< Node, bool > d_membership_length;
+ // regular expression operations
+ RegExpOpr d_regexp_opr;
+
+ CVC4::String getHeadConst( Node x );
+ bool deriveRegExp( Node x, Node r, Node ant );
+ bool addMembershipLength(Node atom);
+ void addMembership(Node assertion);
+ Node getNormalString(Node x, std::vector<Node> &nf_exp);
+ Node getNormalSymRegExp(Node r, std::vector<Node> &nf_exp);
+
+
+ // Finite Model Finding
private:
- NodeSet d_input_vars;
- context::CDO< Node > d_input_var_lsum;
- context::CDHashMap< int, Node > d_cardinality_lits;
- context::CDO< int > d_curr_cardinality;
+ NodeSet d_input_vars;
+ context::CDO< Node > d_input_var_lsum;
+ context::CDHashMap< int, Node > d_cardinality_lits;
+ context::CDO< int > d_curr_cardinality;
public:
- //for finite model finding
+ //for finite model finding
Node getNextDecisionRequest();
- void assertNode( Node lit );
+ void assertNode( Node lit );
public:
/** statistics class */
namespace strings {
StringsPreprocess::StringsPreprocess() {
- //Constants
- d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
+ //Constants
+ d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
}
void StringsPreprocess::processRegExp( Node s, Node r, std::vector< Node > &ret ) {
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- Node eq = NodeManager::currentNM()->mkConst( false );
- ret.push_back( eq );
- break;
- }
- case kind::REGEXP_SIGMA: {
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- Node eq = one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));
- ret.push_back( eq );
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node eq = s.eqNode( r[0] );
- ret.push_back( eq );
- break;
- }
- case kind::REGEXP_CONCAT: {
- bool flag = true;
- std::vector< Node > cc;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- cc.push_back( r[i][0] );
- } else {
- flag = false;
- break;
- }
- }
- if(flag) {
- Node eq = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc));
- ret.push_back(eq);
- } else {
- Node eq = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, s, r );
- ret.push_back( eq );
- }
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > c_or;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- std::vector< Node > ntmp;
- processRegExp( s, r[i], ntmp );
- Node lem = ntmp.size()==1 ? ntmp[0] : NodeManager::currentNM()->mkNode(kind::AND, ntmp);
- c_or.push_back( lem );
- }
- Node eq = NodeManager::currentNM()->mkNode(kind::OR, c_or);
- ret.push_back( eq );
- break;
- }
- case kind::REGEXP_INTER: {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- processRegExp( s, r[i], ret );
- }
- break;
- }
- case kind::REGEXP_STAR: {
- if(r[0].getKind() == kind::REGEXP_SIGMA) {
- ret.push_back(NodeManager::currentNM()->mkConst(true));
- } else {
- Node eq = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, s, r );
- ret.push_back( eq );
- }
- break;
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << r << " in simplifyRegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
+ int k = r.getKind();
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ Node eq = NodeManager::currentNM()->mkConst( false );
+ ret.push_back( eq );
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
+ Node eq = one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));
+ ret.push_back( eq );
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ Node eq = s.eqNode( r[0] );
+ ret.push_back( eq );
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ bool flag = true;
+ std::vector< Node > cc;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {
+ cc.push_back( r[i][0] );
+ } else {
+ flag = false;
+ break;
+ }
+ }
+ if(flag) {
+ Node eq = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc));
+ ret.push_back(eq);
+ } else {
+ Node eq = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, s, r );
+ ret.push_back( eq );
+ }
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ std::vector< Node > c_or;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ std::vector< Node > ntmp;
+ processRegExp( s, r[i], ntmp );
+ Node lem = ntmp.size()==1 ? ntmp[0] : NodeManager::currentNM()->mkNode(kind::AND, ntmp);
+ c_or.push_back( lem );
+ }
+ Node eq = NodeManager::currentNM()->mkNode(kind::OR, c_or);
+ ret.push_back( eq );
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ processRegExp( s, r[i], ret );
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ if(r[0].getKind() == kind::REGEXP_SIGMA) {
+ ret.push_back(NodeManager::currentNM()->mkConst(true));
+ } else {
+ Node eq = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, s, r );
+ ret.push_back( eq );
+ }
+ break;
+ }
+ default: {
+ Trace("strings-error") << "Unsupported term: " << r << " in simplifyRegExp." << std::endl;
+ Assert( false, "Unsupported Term" );
+ }
+ }
}
bool StringsPreprocess::checkStarPlus( Node t ) {
- if( t.getKind() != kind::REGEXP_STAR && t.getKind() != kind::REGEXP_PLUS ) {
- for( unsigned i = 0; i<t.getNumChildren(); ++i ) {
- if( checkStarPlus(t[i]) ) return true;
- }
- return false;
- } else {
- return true;
- }
+ if( t.getKind() != kind::REGEXP_STAR && t.getKind() != kind::REGEXP_PLUS ) {
+ for( unsigned i = 0; i<t.getNumChildren(); ++i ) {
+ if( checkStarPlus(t[i]) ) return true;
+ }
+ return false;
+ } else {
+ return true;
+ }
}
int StringsPreprocess::checkFixLenVar( Node t ) {
- int ret = 2;
- if(t.getKind() == kind::EQUAL) {
- if(t[0].getType().isInteger() && t[0].isConst() && t[1].getKind() == kind::STRING_LENGTH) {
- if(t[1][0].getKind() == kind::VARIABLE) {
- ret = 0;
- }
- } else if(t[1].getType().isInteger() && t[1].isConst() && t[0].getKind() == kind::STRING_LENGTH) {
- if(t[0][0].getKind() == kind::VARIABLE) {
- ret = 1;
- }
- }
- }
- if(ret != 2) {
- int len = t[ret].getConst<Rational>().getNumerator().toUnsignedInt();
- if(len < 2) {
- ret = 2;
- }
- }
- if(!options::stringExp()) {
- ret = 2;
- }
- return ret;
+ int ret = 2;
+ if(t.getKind() == kind::EQUAL) {
+ if(t[0].getType().isInteger() && t[0].isConst() && t[1].getKind() == kind::STRING_LENGTH) {
+ if(t[1][0].getKind() == kind::VARIABLE) {
+ ret = 0;
+ }
+ } else if(t[1].getType().isInteger() && t[1].isConst() && t[0].getKind() == kind::STRING_LENGTH) {
+ if(t[0][0].getKind() == kind::VARIABLE) {
+ ret = 1;
+ }
+ }
+ }
+ if(ret != 2) {
+ int len = t[ret].getConst<Rational>().getNumerator().toUnsignedInt();
+ if(len < 2) {
+ ret = 2;
+ }
+ }
+ if(!options::stringExp()) {
+ ret = 2;
+ }
+ return ret;
}
Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
std::hash_map<TNode, Node, TNodeHashFunction>::const_iterator i = d_cache.find(t);
return (*i).second.isNull() ? t : (*i).second;
}
- Trace("strings-preprocess") << "StringsPreprocess::simplify: " << t << std::endl;
- Node retNode = t;
- /*int c_id = checkFixLenVar(t);
- if( c_id != 2 ) {
- int v_id = 1 - c_id;
- int len = t[c_id].getConst<Rational>().getNumerator().toUnsignedInt();
- if(len > 1) {
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- std::vector< Node > vec;
- for(int i=0; i<len; i++) {
- Node num = NodeManager::currentNM()->mkConst( ::CVC4::Rational(i) );
- //Node sk = NodeManager::currentNM()->mkNode(kind::STRING_CHARAT, t[v_id][0], num);
- Node sk = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, t[v_id][0], num, one);
- vec.push_back(sk);
- Node cc = one.eqNode(NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk ));
- new_nodes.push_back( cc );
- }
- Node lem = t[v_id][0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, vec ) );
- lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, t, lem );
- new_nodes.push_back( lem );
- d_cache[t] = t;
- retNode = t;
- }
- } else */
- if( t.getKind() == kind::STRING_IN_REGEXP ) {
- Node t0 = simplify( t[0], new_nodes );
-
- //rewrite it
- std::vector< Node > ret;
- processRegExp( t0, t[1], ret );
+ Trace("strings-preprocess") << "StringsPreprocess::simplify: " << t << std::endl;
+ Node retNode = t;
+ /*int c_id = checkFixLenVar(t);
+ if( c_id != 2 ) {
+ int v_id = 1 - c_id;
+ int len = t[c_id].getConst<Rational>().getNumerator().toUnsignedInt();
+ if(len > 1) {
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
+ std::vector< Node > vec;
+ for(int i=0; i<len; i++) {
+ Node num = NodeManager::currentNM()->mkConst( ::CVC4::Rational(i) );
+ //Node sk = NodeManager::currentNM()->mkNode(kind::STRING_CHARAT, t[v_id][0], num);
+ Node sk = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, t[v_id][0], num, one);
+ vec.push_back(sk);
+ Node cc = one.eqNode(NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk ));
+ new_nodes.push_back( cc );
+ }
+ Node lem = t[v_id][0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, vec ) );
+ lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, t, lem );
+ new_nodes.push_back( lem );
+ d_cache[t] = t;
+ retNode = t;
+ }
+ } else */
+ if( t.getKind() == kind::STRING_IN_REGEXP ) {
+ Node t0 = simplify( t[0], new_nodes );
+
+ //rewrite it
+ std::vector< Node > ret;
+ processRegExp( t0, t[1], ret );
- Node n = ret.size() == 1 ? ret[0] : NodeManager::currentNM()->mkNode( kind::AND, ret );
- n = Rewriter::rewrite(n);
- d_cache[t] = (t == n) ? Node::null() : n;
- retNode = n;
- } else if( t.getKind() == kind::STRING_SUBSTR_TOTAL ) {
- Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
+ Node n = ret.size() == 1 ? ret[0] : NodeManager::currentNM()->mkNode( kind::AND, ret );
+ n = Rewriter::rewrite(n);
+ d_cache[t] = (t == n) ? Node::null() : n;
+ retNode = n;
+ } else if( t.getKind() == kind::STRING_SUBSTR_TOTAL ) {
+ Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ),
NodeManager::currentNM()->mkNode( kind::PLUS, t[1], t[2] ) );
- Node t1geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, t[1], d_zero);
- Node t2geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, t[2], d_zero);
- Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1geq0, t2geq0 ));
- Node sk1 = NodeManager::currentNM()->mkSkolem( "ss1", NodeManager::currentNM()->stringType(), "created for charat/substr" );
- Node sk3 = NodeManager::currentNM()->mkSkolem( "ss3", NodeManager::currentNM()->stringType(), "created for charat/substr" );
- Node x_eq_123 = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, t, sk3 ) );
- Node len_sk1_eq_i = t[1].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
- Node lemma = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::ITE, cond,
- NodeManager::currentNM()->mkNode( kind::AND, x_eq_123, len_sk1_eq_i ),
- t.eqNode(NodeManager::currentNM()->mkConst( ::CVC4::String("") )) ));
- new_nodes.push_back( lemma );
- retNode = t;
- d_cache[t] = t;
- } else if( t.getKind() == kind::STRING_STRIDOF ) {
- if(options::stringExp()) {
- Node sk1 = NodeManager::currentNM()->mkSkolem( "io1", t[0].getType(), "created for indexof" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "io2", t[0].getType(), "created for indexof" );
- Node sk3 = NodeManager::currentNM()->mkSkolem( "io3", t[0].getType(), "created for indexof" );
- Node sk4 = NodeManager::currentNM()->mkSkolem( "io4", t[0].getType(), "created for indexof" );
- Node skk = NodeManager::currentNM()->mkSkolem( "iok", t[2].getType(), "created for indexof" );
- Node eq = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3, sk4 ) );
- new_nodes.push_back( eq );
- Node negone = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
- Node krange = NodeManager::currentNM()->mkNode( kind::GEQ, skk, negone );
- new_nodes.push_back( krange );
- krange = NodeManager::currentNM()->mkNode( kind::GT,
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ), skk);
- new_nodes.push_back( krange );
+ Node t1geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, t[1], d_zero);
+ Node t2geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, t[2], d_zero);
+ Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1geq0, t2geq0 ));
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "ss1", NodeManager::currentNM()->stringType(), "created for charat/substr" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "ss3", NodeManager::currentNM()->stringType(), "created for charat/substr" );
+ Node x_eq_123 = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, t, sk3 ) );
+ Node len_sk1_eq_i = t[1].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ Node lemma = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::ITE, cond,
+ NodeManager::currentNM()->mkNode( kind::AND, x_eq_123, len_sk1_eq_i ),
+ t.eqNode(NodeManager::currentNM()->mkConst( ::CVC4::String("") )) ));
+ new_nodes.push_back( lemma );
+ retNode = t;
+ d_cache[t] = t;
+ } else if( t.getKind() == kind::STRING_STRIDOF ) {
+ if(options::stringExp()) {
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "io1", t[0].getType(), "created for indexof" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "io2", t[0].getType(), "created for indexof" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "io3", t[0].getType(), "created for indexof" );
+ Node sk4 = NodeManager::currentNM()->mkSkolem( "io4", t[0].getType(), "created for indexof" );
+ Node skk = NodeManager::currentNM()->mkSkolem( "iok", t[2].getType(), "created for indexof" );
+ Node eq = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3, sk4 ) );
+ new_nodes.push_back( eq );
+ Node negone = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
+ Node krange = NodeManager::currentNM()->mkNode( kind::GEQ, skk, negone );
+ new_nodes.push_back( krange );
+ krange = NodeManager::currentNM()->mkNode( kind::GT,
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ), skk);
+ new_nodes.push_back( krange );
- //str.len(s1) < y + str.len(s2)
- Node c1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::GT,
- NodeManager::currentNM()->mkNode( kind::PLUS, t[2], NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[1] )),
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] )));
- //str.len(t1) = y
- Node c2 = t[2].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
- //~contain(t234, s2)
- Node c3 = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::STRING_STRCTN,
- NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk2, sk3, sk4), t[1] ).negate());
- //left
- Node left = NodeManager::currentNM()->mkNode( kind::OR, c1, NodeManager::currentNM()->mkNode( kind::AND, c2, c3 ) );
- //t3 = s2
- Node c4 = t[1].eqNode( sk3 );
- //~contain(t2, s2)
- Node c5 = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, sk2, t[1] ).negate();
- //k=str.len(s1, s2)
- Node c6 = skk.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH,
- NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2 )));
- //right
- Node right = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::AND, c2, c4, c5, c6 ));
- Node cond = skk.eqNode( negone );
- Node rr = NodeManager::currentNM()->mkNode( kind::ITE, cond, left, right );
- new_nodes.push_back( rr );
- d_cache[t] = skk;
- retNode = skk;
- } else {
- throw LogicException("string indexof not supported in default mode, try --string-exp");
- }
- } else if( t.getKind() == kind::STRING_ITOS || t.getKind() == kind::STRING_U16TOS || t.getKind() == kind::STRING_U32TOS ) {
- if(options::stringExp()) {
- //Node num = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE,
- // NodeManager::currentNM()->mkNode(kind::GEQ, t[0], d_zero),
- // t[0], NodeManager::currentNM()->mkNode(kind::UMINUS, t[0])));
- Node num = t[0];
- Node pret = NodeManager::currentNM()->mkNode(kind::STRING_ITOS, num);
- Node lenp = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, pret);
+ //str.len(s1) < y + str.len(s2)
+ Node c1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::GT,
+ NodeManager::currentNM()->mkNode( kind::PLUS, t[2], NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[1] )),
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] )));
+ //str.len(t1) = y
+ Node c2 = t[2].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ //~contain(t234, s2)
+ Node c3 = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::STRING_STRCTN,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk2, sk3, sk4), t[1] ).negate());
+ //left
+ Node left = NodeManager::currentNM()->mkNode( kind::OR, c1, NodeManager::currentNM()->mkNode( kind::AND, c2, c3 ) );
+ //t3 = s2
+ Node c4 = t[1].eqNode( sk3 );
+ //~contain(t2, s2)
+ Node c5 = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, sk2, t[1] ).negate();
+ //k=str.len(s1, s2)
+ Node c6 = skk.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2 )));
+ //right
+ Node right = Rewriter::rewrite(NodeManager::currentNM()->mkNode( kind::AND, c2, c4, c5, c6 ));
+ Node cond = skk.eqNode( negone );
+ Node rr = NodeManager::currentNM()->mkNode( kind::ITE, cond, left, right );
+ new_nodes.push_back( rr );
+ d_cache[t] = skk;
+ retNode = skk;
+ } else {
+ throw LogicException("string indexof not supported in default mode, try --strings-exp");
+ }
+ } else if( t.getKind() == kind::STRING_ITOS || t.getKind() == kind::STRING_U16TOS || t.getKind() == kind::STRING_U32TOS ) {
+ if(options::stringExp()) {
+ //Node num = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE,
+ // NodeManager::currentNM()->mkNode(kind::GEQ, t[0], d_zero),
+ // t[0], NodeManager::currentNM()->mkNode(kind::UMINUS, t[0])));
+ Node num = t[0];
+ Node pret = NodeManager::currentNM()->mkNode(kind::STRING_ITOS, num);
+ Node lenp = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, pret);
+
+ Node nonneg = NodeManager::currentNM()->mkNode(kind::GEQ, t[0], d_zero);
+ if(t.getKind()==kind::STRING_U16TOS) {
+ nonneg = NodeManager::currentNM()->mkNode(kind::AND, nonneg, NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(UINT16_MAX) ), t[0]));
+ Node lencond = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(5) ), lenp);
+ new_nodes.push_back(lencond);
+ } else if(t.getKind()==kind::STRING_U32TOS) {
+ nonneg = NodeManager::currentNM()->mkNode(kind::AND, nonneg, NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(UINT32_MAX) ), t[0]));
+ Node lencond = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(10) ), lenp);
+ new_nodes.push_back(lencond);
+ }
- Node nonneg = NodeManager::currentNM()->mkNode(kind::GEQ, t[0], d_zero);
- if(t.getKind()==kind::STRING_U16TOS) {
- nonneg = NodeManager::currentNM()->mkNode(kind::AND, nonneg, NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(UINT16_MAX) ), t[0]));
- Node lencond = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(5) ), lenp);
- new_nodes.push_back(lencond);
- } else if(t.getKind()==kind::STRING_U32TOS) {
- nonneg = NodeManager::currentNM()->mkNode(kind::AND, nonneg, NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(UINT32_MAX) ), t[0]));
- Node lencond = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst( ::CVC4::Rational(10) ), lenp);
- new_nodes.push_back(lencond);
- }
+ Node lem = NodeManager::currentNM()->mkNode(kind::IFF, nonneg.negate(),
+ pret.eqNode(NodeManager::currentNM()->mkConst( ::CVC4::String("") ))//lenp.eqNode(d_zero)
+ );
+ new_nodes.push_back(lem);
- Node lem = NodeManager::currentNM()->mkNode(kind::IFF, nonneg.negate(),
- pret.eqNode(NodeManager::currentNM()->mkConst( ::CVC4::String("") ))//lenp.eqNode(d_zero)
- );
- new_nodes.push_back(lem);
+ //non-neg
+ Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
+ Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
+ Node g1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::GEQ, b1, d_zero ),
+ NodeManager::currentNM()->mkNode( kind::GT, lenp, b1 ) ) );
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
+ Node nine = NodeManager::currentNM()->mkConst( ::CVC4::Rational(9) );
+ Node ten = NodeManager::currentNM()->mkConst( ::CVC4::Rational(10) );
- //non-neg
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode( kind::GEQ, b1, d_zero ),
- NodeManager::currentNM()->mkNode( kind::GT, lenp, b1 ) ) );
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- Node nine = NodeManager::currentNM()->mkConst( ::CVC4::Rational(9) );
- Node ten = NodeManager::currentNM()->mkConst( ::CVC4::Rational(10) );
-
- std::vector< TypeNode > argTypes;
- argTypes.push_back(NodeManager::currentNM()->integerType());
- Node ufP = NodeManager::currentNM()->mkSkolem("ufP",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->integerType()),
- "uf type conv P");
- Node ufM = NodeManager::currentNM()->mkSkolem("ufM",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->integerType()),
- "uf type conv M");
-
- lem = num.eqNode(NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, d_zero));
- new_nodes.push_back( lem );
+ std::vector< TypeNode > argTypes;
+ argTypes.push_back(NodeManager::currentNM()->integerType());
+ Node ufP = NodeManager::currentNM()->mkSkolem("ufP",
+ NodeManager::currentNM()->mkFunctionType(
+ argTypes, NodeManager::currentNM()->integerType()),
+ "uf type conv P");
+ Node ufM = NodeManager::currentNM()->mkSkolem("ufM",
+ NodeManager::currentNM()->mkFunctionType(
+ argTypes, NodeManager::currentNM()->integerType()),
+ "uf type conv M");
- Node ufx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, b1);
- Node ufx1 = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, NodeManager::currentNM()->mkNode(kind::MINUS,b1,one));
- Node ufMx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufM, b1);
- Node b1gtz = NodeManager::currentNM()->mkNode(kind::GT, b1, d_zero);
- Node cc1 = ufx1.eqNode( NodeManager::currentNM()->mkNode(kind::PLUS,
- NodeManager::currentNM()->mkNode(kind::MULT, ufx, ten),
- NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufM, NodeManager::currentNM()->mkNode(kind::MINUS,b1,one)) ));
- cc1 = NodeManager::currentNM()->mkNode(kind::IMPLIES, b1gtz, cc1);
- Node lstx = lenp.eqNode(NodeManager::currentNM()->mkNode(kind::PLUS, b1, one));
- Node cc2 = ufx.eqNode(ufMx);
- cc2 = NodeManager::currentNM()->mkNode(kind::IMPLIES, lstx, cc2);
- // leading zero
- Node cl = NodeManager::currentNM()->mkNode(kind::AND, lstx, d_zero.eqNode(b1).negate());
- Node cc21 = NodeManager::currentNM()->mkNode(kind::IMPLIES, cl, NodeManager::currentNM()->mkNode(kind::GT, ufMx, d_zero));
- //cc3
- Node cc3 = NodeManager::currentNM()->mkNode(kind::GEQ, ufMx, d_zero);
- Node cc4 = NodeManager::currentNM()->mkNode(kind::GEQ, nine, ufMx);
-
- Node b21 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->stringType());
- Node b22 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->stringType());
- Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b21, b22);
+ lem = num.eqNode(NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, d_zero));
+ new_nodes.push_back( lem );
- Node c21 = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, b21).eqNode(
- NodeManager::currentNM()->mkNode(kind::MINUS, lenp, NodeManager::currentNM()->mkNode(kind::PLUS, b1, one) ));
- Node ch =
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(0))),
- NodeManager::currentNM()->mkConst(::CVC4::String("0")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(1))),
- NodeManager::currentNM()->mkConst(::CVC4::String("1")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(2))),
- NodeManager::currentNM()->mkConst(::CVC4::String("2")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(3))),
- NodeManager::currentNM()->mkConst(::CVC4::String("3")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(4))),
- NodeManager::currentNM()->mkConst(::CVC4::String("4")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(5))),
- NodeManager::currentNM()->mkConst(::CVC4::String("5")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(6))),
- NodeManager::currentNM()->mkConst(::CVC4::String("6")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(7))),
- NodeManager::currentNM()->mkConst(::CVC4::String("7")),
- NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(8))),
- NodeManager::currentNM()->mkConst(::CVC4::String("8")),
- NodeManager::currentNM()->mkConst(::CVC4::String("9")))))))))));
- Node c22 = pret.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, b21, ch, b22) );
- Node cc5 = NodeManager::currentNM()->mkNode(kind::EXISTS, b2v, NodeManager::currentNM()->mkNode(kind::AND, c21, c22));
- std::vector< Node > svec;
- svec.push_back(cc1);svec.push_back(cc2);
- svec.push_back(cc21);
- svec.push_back(cc3);svec.push_back(cc4);svec.push_back(cc5);
- Node conc = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, svec) );
- conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, g1, conc );
- conc = NodeManager::currentNM()->mkNode( kind::FORALL, b1v, conc );
- conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, nonneg, conc );
- new_nodes.push_back( conc );
-
- /*conc = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::IMPLIES,
- NodeManager::currentNM()->mkNode(kind::LT, t[0], d_zero),
- t.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,
- NodeManager::currentNM()->mkConst(::CVC4::String("-")), pret))));
- new_nodes.push_back( conc );*/
+ Node ufx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, b1);
+ Node ufx1 = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, NodeManager::currentNM()->mkNode(kind::MINUS,b1,one));
+ Node ufMx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufM, b1);
+ Node b1gtz = NodeManager::currentNM()->mkNode(kind::GT, b1, d_zero);
+ Node cc1 = ufx1.eqNode( NodeManager::currentNM()->mkNode(kind::PLUS,
+ NodeManager::currentNM()->mkNode(kind::MULT, ufx, ten),
+ NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufM, NodeManager::currentNM()->mkNode(kind::MINUS,b1,one)) ));
+ cc1 = NodeManager::currentNM()->mkNode(kind::IMPLIES, b1gtz, cc1);
+ Node lstx = lenp.eqNode(NodeManager::currentNM()->mkNode(kind::PLUS, b1, one));
+ Node cc2 = ufx.eqNode(ufMx);
+ cc2 = NodeManager::currentNM()->mkNode(kind::IMPLIES, lstx, cc2);
+ // leading zero
+ Node cl = NodeManager::currentNM()->mkNode(kind::AND, lstx, d_zero.eqNode(b1).negate());
+ Node cc21 = NodeManager::currentNM()->mkNode(kind::IMPLIES, cl, NodeManager::currentNM()->mkNode(kind::GT, ufMx, d_zero));
+ //cc3
+ Node cc3 = NodeManager::currentNM()->mkNode(kind::GEQ, ufMx, d_zero);
+ Node cc4 = NodeManager::currentNM()->mkNode(kind::GEQ, nine, ufMx);
- d_cache[t] = pret;
- if(t != pret) {
- d_cache[pret] = pret;
- }
- retNode = pret;
- } else {
- throw LogicException("string int.to.str not supported in default mode, try --string-exp");
- }
- } else if( t.getKind() == kind::STRING_STOI || t.getKind() == kind::STRING_STOU16 || t.getKind() == kind::STRING_STOU32 ) {
- if(options::stringExp()) {
- Node str = t[0];
- Node pret = NodeManager::currentNM()->mkNode(kind::STRING_STOI, str);
- Node lenp = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, str);
+ Node b21 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->stringType());
+ Node b22 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->stringType());
+ Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b21, b22);
- Node negone = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- Node nine = NodeManager::currentNM()->mkConst( ::CVC4::Rational(9) );
- Node ten = NodeManager::currentNM()->mkConst( ::CVC4::Rational(10) );
- std::vector< TypeNode > argTypes;
- argTypes.push_back(NodeManager::currentNM()->integerType());
- Node ufP = NodeManager::currentNM()->mkSkolem("ufP",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->integerType()),
- "uf type conv P");
- Node ufM = NodeManager::currentNM()->mkSkolem("ufM",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->integerType()),
- "uf type conv M");
+ Node c21 = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, b21).eqNode(
+ NodeManager::currentNM()->mkNode(kind::MINUS, lenp, NodeManager::currentNM()->mkNode(kind::PLUS, b1, one) ));
+ Node ch =
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(0))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("0")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(1))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("1")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(2))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("2")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(3))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("3")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(4))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("4")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(5))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("5")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(6))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("6")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(7))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("7")),
+ NodeManager::currentNM()->mkNode(kind::ITE, ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(8))),
+ NodeManager::currentNM()->mkConst(::CVC4::String("8")),
+ NodeManager::currentNM()->mkConst(::CVC4::String("9")))))))))));
+ Node c22 = pret.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, b21, ch, b22) );
+ Node cc5 = NodeManager::currentNM()->mkNode(kind::EXISTS, b2v, NodeManager::currentNM()->mkNode(kind::AND, c21, c22));
+ std::vector< Node > svec;
+ svec.push_back(cc1);svec.push_back(cc2);
+ svec.push_back(cc21);
+ svec.push_back(cc3);svec.push_back(cc4);svec.push_back(cc5);
+ Node conc = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, svec) );
+ conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, g1, conc );
+ conc = NodeManager::currentNM()->mkNode( kind::FORALL, b1v, conc );
+ conc = NodeManager::currentNM()->mkNode( kind::IMPLIES, nonneg, conc );
+ new_nodes.push_back( conc );
- //Node ufP0 = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, d_zero);
- //new_nodes.push_back(pret.eqNode(ufP0));
- //lemma
- Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES,
- str.eqNode(NodeManager::currentNM()->mkConst(::CVC4::String(""))),
- pret.eqNode(negone));
- new_nodes.push_back(lem);
- /*lem = NodeManager::currentNM()->mkNode(kind::IFF,
- t[0].eqNode(NodeManager::currentNM()->mkConst(::CVC4::String("0"))),
- t.eqNode(d_zero));
- new_nodes.push_back(lem);*/
- if(t.getKind()==kind::STRING_U16TOS) {
- lem = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst(::CVC4::String("5")), lenp);
- new_nodes.push_back(lem);
- } else if(t.getKind()==kind::STRING_U32TOS) {
- lem = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst(::CVC4::String("9")), lenp);
- new_nodes.push_back(lem);
- }
- //cc1
- Node cc1 = str.eqNode(NodeManager::currentNM()->mkConst(::CVC4::String("")));
- //cc1 = NodeManager::currentNM()->mkNode(kind::AND, ufP0.eqNode(negone), cc1);
- //cc2
- std::vector< Node > vec_n;
+ /*conc = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::IMPLIES,
+ NodeManager::currentNM()->mkNode(kind::LT, t[0], d_zero),
+ t.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,
+ NodeManager::currentNM()->mkConst(::CVC4::String("-")), pret))));
+ new_nodes.push_back( conc );*/
+
+ d_cache[t] = pret;
+ if(t != pret) {
+ d_cache[pret] = pret;
+ }
+ retNode = pret;
+ } else {
+ throw LogicException("string int.to.str not supported in default mode, try --strings-exp");
+ }
+ } else if( t.getKind() == kind::STRING_STOI || t.getKind() == kind::STRING_STOU16 || t.getKind() == kind::STRING_STOU32 ) {
+ if(options::stringExp()) {
+ Node str = t[0];
+ Node pret = NodeManager::currentNM()->mkNode(kind::STRING_STOI, str);
+ Node lenp = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, str);
+
+ Node negone = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
+ Node nine = NodeManager::currentNM()->mkConst( ::CVC4::Rational(9) );
+ Node ten = NodeManager::currentNM()->mkConst( ::CVC4::Rational(10) );
+ std::vector< TypeNode > argTypes;
+ argTypes.push_back(NodeManager::currentNM()->integerType());
+ Node ufP = NodeManager::currentNM()->mkSkolem("ufP",
+ NodeManager::currentNM()->mkFunctionType(
+ argTypes, NodeManager::currentNM()->integerType()),
+ "uf type conv P");
+ Node ufM = NodeManager::currentNM()->mkSkolem("ufM",
+ NodeManager::currentNM()->mkFunctionType(
+ argTypes, NodeManager::currentNM()->integerType()),
+ "uf type conv M");
+
+ //Node ufP0 = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, d_zero);
+ //new_nodes.push_back(pret.eqNode(ufP0));
+ //lemma
+ Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES,
+ str.eqNode(NodeManager::currentNM()->mkConst(::CVC4::String(""))),
+ pret.eqNode(negone));
+ new_nodes.push_back(lem);
+ /*lem = NodeManager::currentNM()->mkNode(kind::IFF,
+ t[0].eqNode(NodeManager::currentNM()->mkConst(::CVC4::String("0"))),
+ t.eqNode(d_zero));
+ new_nodes.push_back(lem);*/
+ if(t.getKind()==kind::STRING_U16TOS) {
+ lem = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst(::CVC4::String("5")), lenp);
+ new_nodes.push_back(lem);
+ } else if(t.getKind()==kind::STRING_U32TOS) {
+ lem = NodeManager::currentNM()->mkNode(kind::GEQ, NodeManager::currentNM()->mkConst(::CVC4::String("9")), lenp);
+ new_nodes.push_back(lem);
+ }
+ //cc1
+ Node cc1 = str.eqNode(NodeManager::currentNM()->mkConst(::CVC4::String("")));
+ //cc1 = NodeManager::currentNM()->mkNode(kind::AND, ufP0.eqNode(negone), cc1);
+ //cc2
+ std::vector< Node > vec_n;
Node p = NodeManager::currentNM()->mkSkolem("p", NodeManager::currentNM()->integerType());
Node g = NodeManager::currentNM()->mkNode(kind::GEQ, p, d_zero);
- vec_n.push_back(g);
+ vec_n.push_back(g);
g = NodeManager::currentNM()->mkNode(kind::GT, lenp, p);
- vec_n.push_back(g);
+ vec_n.push_back(g);
Node z2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, str, p, one);
- char chtmp[2];
- chtmp[1] = '\0';
- for(unsigned i=0; i<=9; i++) {
- chtmp[0] = i + '0';
- std::string stmp(chtmp);
- g = z2.eqNode( NodeManager::currentNM()->mkConst(::CVC4::String(stmp)) ).negate();
- vec_n.push_back(g);
- }
- Node cc2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, vec_n));
- //cc3
- Node b2 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b2);
- Node g2 = NodeManager::currentNM()->mkNode(kind::AND,
- NodeManager::currentNM()->mkNode(kind::GEQ, b2, d_zero),
- NodeManager::currentNM()->mkNode(kind::GT, lenp, b2));
- Node ufx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, b2);
- Node ufx1 = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, NodeManager::currentNM()->mkNode(kind::MINUS,b2,one));
- Node ufMx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufM, b2);
- std::vector< Node > vec_c3;
- std::vector< Node > vec_c3b;
+ char chtmp[2];
+ chtmp[1] = '\0';
+ for(unsigned i=0; i<=9; i++) {
+ chtmp[0] = i + '0';
+ std::string stmp(chtmp);
+ g = z2.eqNode( NodeManager::currentNM()->mkConst(::CVC4::String(stmp)) ).negate();
+ vec_n.push_back(g);
+ }
+ Node cc2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, vec_n));
+ //cc3
+ Node b2 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
+ Node b2v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b2);
+ Node g2 = NodeManager::currentNM()->mkNode(kind::AND,
+ NodeManager::currentNM()->mkNode(kind::GEQ, b2, d_zero),
+ NodeManager::currentNM()->mkNode(kind::GT, lenp, b2));
+ Node ufx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, b2);
+ Node ufx1 = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, NodeManager::currentNM()->mkNode(kind::MINUS,b2,one));
+ Node ufMx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufM, b2);
+ std::vector< Node > vec_c3;
+ std::vector< Node > vec_c3b;
//qx between 0 and 9
- Node c3cc = NodeManager::currentNM()->mkNode(kind::GEQ, ufMx, d_zero);
+ Node c3cc = NodeManager::currentNM()->mkNode(kind::GEQ, ufMx, d_zero);
vec_c3b.push_back(c3cc);
- c3cc = NodeManager::currentNM()->mkNode(kind::GEQ, nine, ufMx);
+ c3cc = NodeManager::currentNM()->mkNode(kind::GEQ, nine, ufMx);
vec_c3b.push_back(c3cc);
Node sx = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, str, b2, one);
for(unsigned i=0; i<=9; i++) {
- chtmp[0] = i + '0';
- std::string stmp(chtmp);
- c3cc = NodeManager::currentNM()->mkNode(kind::IFF,
+ chtmp[0] = i + '0';
+ std::string stmp(chtmp);
+ c3cc = NodeManager::currentNM()->mkNode(kind::IFF,
ufMx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::Rational(i))),
sx.eqNode(NodeManager::currentNM()->mkConst(::CVC4::String(stmp))));
- vec_c3b.push_back(c3cc);
+ vec_c3b.push_back(c3cc);
}
//c312
- Node b2gtz = NodeManager::currentNM()->mkNode(kind::GT, b2, d_zero);
- c3cc = NodeManager::currentNM()->mkNode(kind::IMPLIES, b2gtz,
- ufx.eqNode(NodeManager::currentNM()->mkNode(kind::PLUS,
+ Node b2gtz = NodeManager::currentNM()->mkNode(kind::GT, b2, d_zero);
+ c3cc = NodeManager::currentNM()->mkNode(kind::IMPLIES, b2gtz,
+ ufx.eqNode(NodeManager::currentNM()->mkNode(kind::PLUS,
NodeManager::currentNM()->mkNode(kind::MULT, ufx1, ten),
ufMx)));
- vec_c3b.push_back(c3cc);
+ vec_c3b.push_back(c3cc);
c3cc = NodeManager::currentNM()->mkNode(kind::AND, vec_c3b);
c3cc = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::IMPLIES, g2, c3cc) );
- c3cc = NodeManager::currentNM()->mkNode(kind::FORALL, b2v, c3cc);
- vec_c3.push_back(c3cc);
+ c3cc = NodeManager::currentNM()->mkNode(kind::FORALL, b2v, c3cc);
+ vec_c3.push_back(c3cc);
//unbound
c3cc = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, d_zero).eqNode(NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufM, d_zero));
- vec_c3.push_back(c3cc);
- Node lstx = NodeManager::currentNM()->mkNode(kind::MINUS, lenp, one);
+ vec_c3.push_back(c3cc);
+ Node lstx = NodeManager::currentNM()->mkNode(kind::MINUS, lenp, one);
Node upflstx = NodeManager::currentNM()->mkNode(kind::APPLY_UF, ufP, lstx);
c3cc = upflstx.eqNode(pret);
- vec_c3.push_back(c3cc);
+ vec_c3.push_back(c3cc);
Node cc3 = NodeManager::currentNM()->mkNode(kind::AND, vec_c3);
Node conc = NodeManager::currentNM()->mkNode(kind::ITE, pret.eqNode(negone),
- NodeManager::currentNM()->mkNode(kind::OR, cc1, cc2), cc3);
- new_nodes.push_back( conc );
+ NodeManager::currentNM()->mkNode(kind::OR, cc1, cc2), cc3);
+ new_nodes.push_back( conc );
- d_cache[t] = pret;
- if(t != pret) {
- d_cache[pret] = pret;
- }
- retNode = pret;
- } else {
- throw LogicException("string int.to.str not supported in default mode, try --string-exp");
- }
- } else if( t.getKind() == kind::STRING_STRREPL ) {
- if(options::stringExp()) {
- Node x = t[0];
- Node y = t[1];
- Node z = t[2];
- Node sk1 = NodeManager::currentNM()->mkSkolem( "rp1", t[0].getType(), "created for replace" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "rp2", t[0].getType(), "created for replace" );
- Node skw = NodeManager::currentNM()->mkSkolem( "rpw", t[0].getType(), "created for replace" );
- Node cond = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, x, y );
- Node c1 = x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, y, sk2 ) );
- Node c2 = skw.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, z, sk2 ) );
- Node c3 = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, sk1, y ).negate();
- Node rr = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::ITE, cond,
- NodeManager::currentNM()->mkNode( kind::AND, c1, c2, c3 ),
- skw.eqNode(x) ) );
- new_nodes.push_back( rr );
+ d_cache[t] = pret;
+ if(t != pret) {
+ d_cache[pret] = pret;
+ }
+ retNode = pret;
+ } else {
+ throw LogicException("string int.to.str not supported in default mode, try --strings-exp");
+ }
+ } else if( t.getKind() == kind::STRING_STRREPL ) {
+ if(options::stringExp()) {
+ Node x = t[0];
+ Node y = t[1];
+ Node z = t[2];
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "rp1", t[0].getType(), "created for replace" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "rp2", t[0].getType(), "created for replace" );
+ Node skw = NodeManager::currentNM()->mkSkolem( "rpw", t[0].getType(), "created for replace" );
+ Node cond = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, x, y );
+ Node c1 = x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, y, sk2 ) );
+ Node c2 = skw.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, z, sk2 ) );
+ Node c3 = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, sk1, y ).negate();
+ Node rr = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::ITE, cond,
+ NodeManager::currentNM()->mkNode( kind::AND, c1, c2, c3 ),
+ skw.eqNode(x) ) );
+ new_nodes.push_back( rr );
+
+ d_cache[t] = skw;
+ retNode = skw;
+ } else {
+ throw LogicException("string replace not supported in default mode, try --strings-exp");
+ }
+ } else{
+ d_cache[t] = Node::null();
+ retNode = t;
+ }
- d_cache[t] = skw;
- retNode = skw;
- } else {
- throw LogicException("string replace not supported in default mode, try --string-exp");
- }
- } else{
- d_cache[t] = Node::null();
- retNode = t;
- }
-
- /*if( t.getNumChildren()>0 ) {
- std::vector< Node > cc;
- if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
- cc.push_back(t.getOperator());
- }
- bool changed = false;
- for( unsigned i=0; i<t.getNumChildren(); i++ ){
- Node tn = simplify( t[i], new_nodes );
- cc.push_back( tn );
- changed = changed || tn!=t[i];
- }
- if(changed) {
- Node n = NodeManager::currentNM()->mkNode( t.getKind(), cc );
- d_cache[t] = n;
- retNode = n;
- } else {
- d_cache[t] = Node::null();
- retNode = t;
- }
- }*/
+ /*if( t.getNumChildren()>0 ) {
+ std::vector< Node > cc;
+ if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ cc.push_back(t.getOperator());
+ }
+ bool changed = false;
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ Node tn = simplify( t[i], new_nodes );
+ cc.push_back( tn );
+ changed = changed || tn!=t[i];
+ }
+ if(changed) {
+ Node n = NodeManager::currentNM()->mkNode( t.getKind(), cc );
+ d_cache[t] = n;
+ retNode = n;
+ } else {
+ d_cache[t] = Node::null();
+ retNode = t;
+ }
+ }*/
- Trace("strings-preprocess") << "StringsPreprocess::simplify returns: " << retNode << std::endl;
- if(!new_nodes.empty()) {
- Trace("strings-preprocess") << " ... new nodes (" << new_nodes.size() << "):\n";
- for(unsigned int i=0; i<new_nodes.size(); ++i) {
- Trace("strings-preprocess") << "\t" << new_nodes[i] << "\n";
- }
- }
+ Trace("strings-preprocess") << "StringsPreprocess::simplify returns: " << retNode << std::endl;
+ if(!new_nodes.empty()) {
+ Trace("strings-preprocess") << " ... new nodes (" << new_nodes.size() << "):\n";
+ for(unsigned int i=0; i<new_nodes.size(); ++i) {
+ Trace("strings-preprocess") << "\t" << new_nodes[i] << "\n";
+ }
+ }
- return retNode;
+ return retNode;
}
Node StringsPreprocess::decompose(Node t, std::vector< Node > & new_nodes) {
return (*i).second.isNull() ? t : (*i).second;
}
- unsigned num = t.getNumChildren();
- if(num == 0) {
- return simplify(t, new_nodes);
- } else {
- bool changed = false;
- std::vector< Node > cc;
- if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
- cc.push_back(t.getOperator());
- }
- for(unsigned i=0; i<t.getNumChildren(); i++) {
- Node s = decompose(t[i], new_nodes);
- cc.push_back( s );
- if(s != t[i]) {
- changed = true;
- }
- }
- if(changed) {
- Node tmp = NodeManager::currentNM()->mkNode( t.getKind(), cc );
- return simplify(tmp, new_nodes);
- } else {
- return simplify(t, new_nodes);
- }
- }
+ unsigned num = t.getNumChildren();
+ if(num == 0) {
+ return simplify(t, new_nodes);
+ } else {
+ bool changed = false;
+ std::vector< Node > cc;
+ if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ cc.push_back(t.getOperator());
+ }
+ for(unsigned i=0; i<t.getNumChildren(); i++) {
+ Node s = decompose(t[i], new_nodes);
+ cc.push_back( s );
+ if(s != t[i]) {
+ changed = true;
+ }
+ }
+ if(changed) {
+ Node tmp = NodeManager::currentNM()->mkNode( t.getKind(), cc );
+ return simplify(tmp, new_nodes);
+ } else {
+ return simplify(t, new_nodes);
+ }
+ }
}
void StringsPreprocess::simplify(std::vector< Node > &vec_node, std::vector< Node > &new_nodes) {
- for( unsigned i=0; i<vec_node.size(); i++ ){
- vec_node[i] = decompose( vec_node[i], new_nodes );
- }
+ for( unsigned i=0; i<vec_node.size(); i++ ){
+ vec_node[i] = decompose( vec_node[i], new_nodes );
+ }
}
void StringsPreprocess::simplify(std::vector< Node > &vec_node) {
- std::vector< Node > new_nodes;
- simplify(vec_node, new_nodes);
- vec_node.insert( vec_node.end(), new_nodes.begin(), new_nodes.end() );
+ std::vector< Node > new_nodes;
+ simplify(vec_node, new_nodes);
+ vec_node.insert( vec_node.end(), new_nodes.begin(), new_nodes.end() );
}
}/* CVC4::theory::strings namespace */
namespace strings {
class StringsPreprocess {
- // NOTE: this class is NOT context-dependent
- std::hash_map<TNode, Node, TNodeHashFunction> d_cache;
- //Constants
- Node d_zero;
+ // NOTE: this class is NOT context-dependent
+ std::hash_map<TNode, Node, TNodeHashFunction> d_cache;
+ //Constants
+ Node d_zero;
private:
- bool checkStarPlus( Node t );
- int checkFixLenVar( Node t );
- void processRegExp( Node s, Node r, std::vector< Node > &ret );
- Node simplify( Node t, std::vector< Node > &new_nodes );
- Node decompose( Node t, std::vector< Node > &new_nodes );
+ bool checkStarPlus( Node t );
+ int checkFixLenVar( Node t );
+ void processRegExp( Node s, Node r, std::vector< Node > &ret );
+ Node simplify( Node t, std::vector< Node > &new_nodes );
+ Node decompose( Node t, std::vector< Node > &new_nodes );
public:
void simplify(std::vector< Node > &vec_node, std::vector< Node > &new_nodes);
void simplify(std::vector< Node > &vec_node);
- StringsPreprocess();
+ StringsPreprocess();
};
}/* CVC4::theory::strings namespace */
Node preNode = Node::null();
for(unsigned int i=0; i<node.getNumChildren(); ++i) {
Node tmpNode = node[i];
- if(node[i].getKind() == kind::STRING_CONCAT) {
+ if(node[i].getKind() == kind::STRING_CONCAT) {
tmpNode = rewriteConcatString(node[i]);
if(tmpNode.getKind() == kind::STRING_CONCAT) {
- unsigned j=0;
+ unsigned j=0;
if(!preNode.isNull()) {
if(tmpNode[0].isConst()) {
preNode = NodeManager::currentNM()->mkConst( preNode.getConst<String>().concat( tmpNode[0].getConst<String>() ) );
}
}
}
- if(preNode != Node::null()) {
- node_vec.push_back( preNode );
- }
- if(node_vec.size() > 1) {
- retNode = NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, node_vec);
- } else {
- retNode = node_vec[0];
- }
+ if(preNode != Node::null()) {
+ node_vec.push_back( preNode );
+ }
+ if(node_vec.size() > 1) {
+ retNode = NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, node_vec);
+ } else {
+ retNode = node_vec[0];
+ }
Trace("strings-prerewrite") << "Strings::rewriteConcatString end " << retNode << std::endl;
return retNode;
}
Node preNode = Node::null();
bool emptyflag = false;
for(unsigned int i=0; i<node.getNumChildren(); ++i) {
- Trace("strings-prerewrite") << "Strings::prerewriteConcatRegExp preNode: " << preNode << std::endl;
+ Trace("strings-prerewrite") << "Strings::prerewriteConcatRegExp preNode: " << preNode << std::endl;
Node tmpNode = node[i];
if(tmpNode.getKind() == kind::REGEXP_CONCAT) {
tmpNode = prerewriteConcatRegExp(node[i]);
} else if( tmpNode.getKind() == kind::REGEXP_EMPTY ) {
emptyflag = true;
break;
- } else {
+ } else {
if(!preNode.isNull()) {
if(preNode.getKind() == kind::CONST_STRING && preNode.getConst<String>().isEmptyString() ) {
preNode = Node::null();
node_vec.push_back( tmpNode );
}
}
- if(emptyflag) {
- std::vector< Node > nvec;
- retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec );
- } else {
- if(!preNode.isNull()) {
- node_vec.push_back( NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, preNode ) );
- }
- if(node_vec.size() > 1) {
- retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, node_vec);
- } else {
- retNode = node_vec[0];
- }
- }
+ if(emptyflag) {
+ std::vector< Node > nvec;
+ retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec );
+ } else {
+ if(!preNode.isNull()) {
+ node_vec.push_back( NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, preNode ) );
+ }
+ if(node_vec.size() > 1) {
+ retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, node_vec);
+ } else {
+ retNode = node_vec[0];
+ }
+ }
Trace("strings-prerewrite") << "Strings::prerewriteConcatRegExp end " << retNode << std::endl;
return retNode;
}
Node TheoryStringsRewriter::prerewriteOrRegExp(TNode node) {
- Assert( node.getKind() == kind::REGEXP_UNION );
+ Assert( node.getKind() == kind::REGEXP_UNION );
Trace("strings-prerewrite") << "Strings::prerewriteOrRegExp start " << node << std::endl;
Node retNode = node;
std::vector<Node> node_vec;
- bool flag = false;
+ bool flag = false;
for(unsigned i=0; i<node.getNumChildren(); ++i) {
- if(node[i].getKind() == kind::REGEXP_UNION) {
- Node tmpNode = prerewriteOrRegExp( node[i] );
- for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) {
- node_vec.push_back( tmpNode[j] );
- }
- flag = true;
- } else if(node[i].getKind() == kind::REGEXP_EMPTY) {
- flag = true;
- } else {
- node_vec.push_back( node[i] );
- }
- }
- if(flag) {
- std::vector< Node > nvec;
- retNode = node_vec.size() == 0 ? NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec ) :
- node_vec.size() == 1 ? node_vec[0] : NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, node_vec);
- }
- Trace("strings-prerewrite") << "Strings::prerewriteOrRegExp end " << retNode << std::endl;
+ if(node[i].getKind() == kind::REGEXP_UNION) {
+ Node tmpNode = prerewriteOrRegExp( node[i] );
+ for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) {
+ node_vec.push_back( tmpNode[j] );
+ }
+ flag = true;
+ } else if(node[i].getKind() == kind::REGEXP_EMPTY) {
+ flag = true;
+ } else {
+ node_vec.push_back( node[i] );
+ }
+ }
+ if(flag) {
+ std::vector< Node > nvec;
+ retNode = node_vec.size() == 0 ? NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec ) :
+ node_vec.size() == 1 ? node_vec[0] : NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, node_vec);
+ }
+ Trace("strings-prerewrite") << "Strings::prerewriteOrRegExp end " << retNode << std::endl;
return retNode;
}
bool TheoryStringsRewriter::checkConstRegExp( TNode t ) {
- if( t.getKind() != kind::STRING_TO_REGEXP ) {
- for( unsigned i = 0; i<t.getNumChildren(); ++i ) {
- if( !checkConstRegExp(t[i]) ) return false;
- }
- return true;
- } else {
- if( t[0].getKind() == kind::CONST_STRING ) {
- return true;
- } else {
- return false;
- }
- }
+ if( t.getKind() != kind::STRING_TO_REGEXP ) {
+ for( unsigned i = 0; i<t.getNumChildren(); ++i ) {
+ if( !checkConstRegExp(t[i]) ) return false;
+ }
+ return true;
+ } else {
+ if( t[0].getKind() == kind::CONST_STRING ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned int index_start, TNode r ) {
- Assert( index_start <= s.size() );
- int k = r.getKind();
- switch( k ) {
- case kind::STRING_TO_REGEXP: {
- CVC4::String s2 = s.substr( index_start, s.size() - index_start );
- if(r[0].getKind() == kind::CONST_STRING) {
- return ( s2 == r[0].getConst<String>() );
- } else {
- Assert( false, "RegExp contains variables" );
- }
- }
- case kind::REGEXP_CONCAT: {
- if( s.size() != index_start ) {
- std::vector<int> vec_k( r.getNumChildren(), -1 );
- int start = 0;
- int left = (int) s.size();
- int i=0;
- while( i<(int) r.getNumChildren() ) {
- bool flag = true;
- if( i == (int) r.getNumChildren() - 1 ) {
- if( testConstStringInRegExp( s, index_start + start, r[i] ) ) {
- return true;
- }
- } else if( i == -1 ) {
- return false;
- } else {
- for(vec_k[i] = vec_k[i] + 1; vec_k[i] <= left; ++vec_k[i]) {
- CVC4::String t = s.substr(index_start + start, vec_k[i]);
- if( testConstStringInRegExp( t, 0, r[i] ) ) {
- start += vec_k[i]; left -= vec_k[i]; flag = false;
- ++i; vec_k[i] = -1;
- break;
- }
- }
- }
+ Assert( index_start <= s.size() );
+ int k = r.getKind();
+ switch( k ) {
+ case kind::STRING_TO_REGEXP: {
+ CVC4::String s2 = s.substr( index_start, s.size() - index_start );
+ if(r[0].getKind() == kind::CONST_STRING) {
+ return ( s2 == r[0].getConst<String>() );
+ } else {
+ Assert( false, "RegExp contains variables" );
+ }
+ }
+ case kind::REGEXP_CONCAT: {
+ if( s.size() != index_start ) {
+ std::vector<int> vec_k( r.getNumChildren(), -1 );
+ int start = 0;
+ int left = (int) s.size();
+ int i=0;
+ while( i<(int) r.getNumChildren() ) {
+ bool flag = true;
+ if( i == (int) r.getNumChildren() - 1 ) {
+ if( testConstStringInRegExp( s, index_start + start, r[i] ) ) {
+ return true;
+ }
+ } else if( i == -1 ) {
+ return false;
+ } else {
+ for(vec_k[i] = vec_k[i] + 1; vec_k[i] <= left; ++vec_k[i]) {
+ CVC4::String t = s.substr(index_start + start, vec_k[i]);
+ if( testConstStringInRegExp( t, 0, r[i] ) ) {
+ start += vec_k[i]; left -= vec_k[i]; flag = false;
+ ++i; vec_k[i] = -1;
+ break;
+ }
+ }
+ }
- if(flag) {
- --i;
- if(i >= 0) {
- start -= vec_k[i]; left += vec_k[i];
- }
- }
- }
- return false;
- } else {
- return true;
- }
- }
- case kind::REGEXP_UNION: {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(testConstStringInRegExp( s, index_start, r[i] )) return true;
- }
- return false;
- }
- case kind::REGEXP_INTER: {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(!testConstStringInRegExp( s, index_start, r[i] )) return false;
- }
- return true;
- }
- case kind::REGEXP_STAR: {
- if( s.size() != index_start ) {
- for(unsigned k=s.size() - index_start; k>0; --k) {
- CVC4::String t = s.substr(index_start, k);
- if( testConstStringInRegExp( t, 0, r[0] ) ) {
- if( index_start + k == s.size() || testConstStringInRegExp( s, index_start + k, r ) ) {
- return true;
- }
- }
- }
- return false;
- } else {
- return true;
- }
- }
- case kind::REGEXP_EMPTY: {
- return false;
- }
- case kind::REGEXP_SIGMA: {
- if(s.size() == 1) {
- return true;
- } else {
- return false;
- }
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << r << " in testConstStringInRegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- return false;
- }
- }
+ if(flag) {
+ --i;
+ if(i >= 0) {
+ start -= vec_k[i]; left += vec_k[i];
+ }
+ }
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+ case kind::REGEXP_UNION: {
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(testConstStringInRegExp( s, index_start, r[i] )) return true;
+ }
+ return false;
+ }
+ case kind::REGEXP_INTER: {
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(!testConstStringInRegExp( s, index_start, r[i] )) return false;
+ }
+ return true;
+ }
+ case kind::REGEXP_STAR: {
+ if( s.size() != index_start ) {
+ for(unsigned k=s.size() - index_start; k>0; --k) {
+ CVC4::String t = s.substr(index_start, k);
+ if( testConstStringInRegExp( t, 0, r[0] ) ) {
+ if( index_start + k == s.size() || testConstStringInRegExp( s, index_start + k, r ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+ case kind::REGEXP_EMPTY: {
+ return false;
+ }
+ case kind::REGEXP_SIGMA: {
+ if(s.size() == 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ default: {
+ Trace("strings-error") << "Unsupported term: " << r << " in testConstStringInRegExp." << std::endl;
+ Assert( false, "Unsupported Term" );
+ return false;
+ }
+ }
}
Node TheoryStringsRewriter::rewriteMembership(TNode node) {
- Node retNode = node;
- Node x = node[0];
+ Node retNode = node;
+ Node x = node[0];
- if(node[0].getKind() == kind::STRING_CONCAT) {
- x = rewriteConcatString(node[0]);
- }
+ if(node[0].getKind() == kind::STRING_CONCAT) {
+ x = rewriteConcatString(node[0]);
+ }
- if(node[1].getKind() == kind::REGEXP_EMPTY) {
- retNode = NodeManager::currentNM()->mkConst( false );
- } else if( x.getKind() == kind::CONST_STRING && checkConstRegExp(node[1]) ) {
- //test whether x in node[1]
- CVC4::String s = x.getConst<String>();
- retNode = NodeManager::currentNM()->mkConst( testConstStringInRegExp( s, 0, node[1] ) );
- } else if(node[1].getKind() == kind::REGEXP_SIGMA) {
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- retNode = one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x));
- } else if(node[1].getKind() == kind::REGEXP_STAR && node[1][0].getKind() == kind::REGEXP_SIGMA) {
- retNode = NodeManager::currentNM()->mkConst( true );
- } else if( x != node[0] ) {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, x, node[1] );
- }
+ if(node[1].getKind() == kind::REGEXP_EMPTY) {
+ retNode = NodeManager::currentNM()->mkConst( false );
+ } else if( x.getKind() == kind::CONST_STRING && checkConstRegExp(node[1]) ) {
+ //test whether x in node[1]
+ CVC4::String s = x.getConst<String>();
+ retNode = NodeManager::currentNM()->mkConst( testConstStringInRegExp( s, 0, node[1] ) );
+ } else if(node[1].getKind() == kind::REGEXP_SIGMA) {
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
+ retNode = one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x));
+ } else if(node[1].getKind() == kind::REGEXP_STAR && node[1][0].getKind() == kind::REGEXP_SIGMA) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ } else if( x != node[0] ) {
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, x, node[1] );
+ }
return retNode;
}
RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
- Trace("strings-postrewrite") << "Strings::postRewrite start " << node << std::endl;
- Node retNode = node;
- Node orig = retNode;
+ Trace("strings-postrewrite") << "Strings::postRewrite start " << node << std::endl;
+ Node retNode = node;
+ Node orig = retNode;
if(node.getKind() == kind::STRING_CONCAT) {
retNode = rewriteConcatString(node);
}
}
} else if(node.getKind() == kind::STRING_SUBSTR_TOTAL) {
- Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
- if(node[2] == zero) {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
- } else if( node[1].isConst() && node[2].isConst() ) {
- if(node[1].getConst<Rational>().sgn()>=0 && node[2].getConst<Rational>().sgn()>=0) {
- int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
- int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
- if( node[0].isConst() ) {
- if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
- retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
- } else {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
- }
- } else if(node[0].getKind() == kind::STRING_CONCAT && node[0][0].isConst()) {
- if( node[0][0].getConst<String>().size() >= (unsigned) (i + j) ) {
- retNode = NodeManager::currentNM()->mkConst( node[0][0].getConst<String>().substr(i, j) );
- }
- }
- } else {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
- }
- }
- } else if(node.getKind() == kind::STRING_STRCTN) {
- if( node[0] == node[1] ) {
- retNode = NodeManager::currentNM()->mkConst( true );
- } else if( node[0].isConst() && node[1].isConst() ) {
- CVC4::String s = node[0].getConst<String>();
- CVC4::String t = node[1].getConst<String>();
- if( s.find(t) != std::string::npos ) {
- retNode = NodeManager::currentNM()->mkConst( true );
- } else {
- retNode = NodeManager::currentNM()->mkConst( false );
- }
- }
- } else if(node.getKind() == kind::STRING_STRIDOF) {
- if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
- CVC4::String s = node[0].getConst<String>();
- CVC4::String t = node[1].getConst<String>();
- int i = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
- std::size_t ret = s.find(t, i);
- if( ret != std::string::npos ) {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational((int) ret) );
- } else {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
- }
- }
- } else if(node.getKind() == kind::STRING_STRREPL) {
- if(node[1] != node[2]) {
- if(node[0].isConst() && node[1].isConst()) {
- CVC4::String s = node[0].getConst<String>();
- CVC4::String t = node[1].getConst<String>();
- std::size_t p = s.find(t);
- if( p != std::string::npos ) {
- if(node[2].isConst()) {
- CVC4::String r = node[2].getConst<String>();
- CVC4::String ret = s.replace(t, r);
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::String(ret) );
- } else {
- CVC4::String s1 = s.substr(0, (int)p);
- CVC4::String s3 = s.substr((int)p + (int)t.size());
- Node ns1 = NodeManager::currentNM()->mkConst( ::CVC4::String(s1) );
- Node ns3 = NodeManager::currentNM()->mkConst( ::CVC4::String(s3) );
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, ns1, node[2], ns3 );
- }
- } else {
- retNode = node[0];
- }
- }
- } else {
- retNode = node[0];
- }
- } else if(node.getKind() == kind::STRING_PREFIX) {
- if(node[0].isConst() && node[1].isConst()) {
- CVC4::String s = node[1].getConst<String>();
- CVC4::String t = node[0].getConst<String>();
- retNode = NodeManager::currentNM()->mkConst( false );
- if(s.size() >= t.size()) {
- if(t == s.substr(0, t.size())) {
- retNode = NodeManager::currentNM()->mkConst( true );
- }
- }
- } else {
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[0]);
- Node lent = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[1]);
- retNode = NodeManager::currentNM()->mkNode(kind::AND,
- NodeManager::currentNM()->mkNode(kind::GEQ, lent, lens),
- node[0].eqNode(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, node[1],
- NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) ), lens)));
- }
- } else if(node.getKind() == kind::STRING_SUFFIX) {
- if(node[0].isConst() && node[1].isConst()) {
- CVC4::String s = node[1].getConst<String>();
- CVC4::String t = node[0].getConst<String>();
- retNode = NodeManager::currentNM()->mkConst( false );
- if(s.size() >= t.size()) {
- if(t == s.substr(s.size() - t.size(), t.size())) {
- retNode = NodeManager::currentNM()->mkConst( true );
- }
- }
- } else {
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[0]);
- Node lent = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[1]);
- retNode = NodeManager::currentNM()->mkNode(kind::AND,
- NodeManager::currentNM()->mkNode(kind::GEQ, lent, lens),
- node[0].eqNode(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, node[1],
- NodeManager::currentNM()->mkNode(kind::MINUS, lent, lens), lens)));
- }
- } else if(node.getKind() == kind::STRING_ITOS || node.getKind() == kind::STRING_U16TOS || node.getKind() == kind::STRING_U32TOS) {
- if(node[0].isConst()) {
- bool flag = false;
- std::string stmp = node[0].getConst<Rational>().getNumerator().toString();
- if(node.getKind() == kind::STRING_U16TOS) {
- CVC4::Rational r1(UINT16_MAX);
- CVC4::Rational r2 = node[0].getConst<Rational>();
- if(r2>r1) {
- flag = true;
- }
- } else if(node.getKind() == kind::STRING_U32TOS) {
- CVC4::Rational r1(UINT32_MAX);
- CVC4::Rational r2 = node[0].getConst<Rational>();
- if(r2>r1) {
- flag = true;
- }
- }
- //std::string stmp = static_cast<std::ostringstream*>( &(std::ostringstream() << node[0]) )->str();
- if(flag || stmp[0] == '-') {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
- } else {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::String(stmp) );
- }
- }
- } else if(node.getKind() == kind::STRING_STOI || node.getKind() == kind::STRING_STOU16 || node.getKind() == kind::STRING_STOU32) {
- if(node[0].isConst()) {
- CVC4::String s = node[0].getConst<String>();
- if(s.isNumber()) {
- std::string stmp = s.toString();
- //if(stmp[0] == '0' && stmp.size() != 1) {
- //TODO: leading zeros
- //retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
- //} else {
- bool flag = false;
- CVC4::Rational r2(stmp.c_str());
- if(node.getKind() == kind::STRING_U16TOS) {
- CVC4::Rational r1(UINT16_MAX);
- if(r2>r1) {
- flag = true;
- }
- } else if(node.getKind() == kind::STRING_U32TOS) {
- CVC4::Rational r1(UINT32_MAX);
- if(r2>r1) {
- flag = true;
- }
- }
- if(flag) {
- retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
- } else {
- retNode = NodeManager::currentNM()->mkConst( r2 );
- }
- //}
- } else {
- retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
- }
- } else if(node[0].getKind() == kind::STRING_CONCAT) {
- for(unsigned i=0; i<node[0].getNumChildren(); ++i) {
- if(node[0][i].isConst()) {
- CVC4::String t = node[0][i].getConst<String>();
- if(!t.isNumber()) {
- retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
- break;
- }
- }
- }
- }
- } else if(node.getKind() == kind::STRING_IN_REGEXP) {
- retNode = rewriteMembership(node);
- }
+ Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
+ if(node[2] == zero) {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
+ } else if( node[1].isConst() && node[2].isConst() ) {
+ if(node[1].getConst<Rational>().sgn()>=0 && node[2].getConst<Rational>().sgn()>=0) {
+ int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ if( node[0].isConst() ) {
+ if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
+ retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
+ }
+ } else if(node[0].getKind() == kind::STRING_CONCAT && node[0][0].isConst()) {
+ if( node[0][0].getConst<String>().size() >= (unsigned) (i + j) ) {
+ retNode = NodeManager::currentNM()->mkConst( node[0][0].getConst<String>().substr(i, j) );
+ }
+ }
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STRCTN) {
+ if( node[0] == node[1] ) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ } else if( node[0].isConst() && node[1].isConst() ) {
+ CVC4::String s = node[0].getConst<String>();
+ CVC4::String t = node[1].getConst<String>();
+ if( s.find(t) != std::string::npos ) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( false );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STRIDOF) {
+ if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
+ CVC4::String s = node[0].getConst<String>();
+ CVC4::String t = node[1].getConst<String>();
+ int i = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ std::size_t ret = s.find(t, i);
+ if( ret != std::string::npos ) {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational((int) ret) );
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STRREPL) {
+ if(node[1] != node[2]) {
+ if(node[0].isConst() && node[1].isConst()) {
+ CVC4::String s = node[0].getConst<String>();
+ CVC4::String t = node[1].getConst<String>();
+ std::size_t p = s.find(t);
+ if( p != std::string::npos ) {
+ if(node[2].isConst()) {
+ CVC4::String r = node[2].getConst<String>();
+ CVC4::String ret = s.replace(t, r);
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::String(ret) );
+ } else {
+ CVC4::String s1 = s.substr(0, (int)p);
+ CVC4::String s3 = s.substr((int)p + (int)t.size());
+ Node ns1 = NodeManager::currentNM()->mkConst( ::CVC4::String(s1) );
+ Node ns3 = NodeManager::currentNM()->mkConst( ::CVC4::String(s3) );
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, ns1, node[2], ns3 );
+ }
+ } else {
+ retNode = node[0];
+ }
+ }
+ } else {
+ retNode = node[0];
+ }
+ } else if(node.getKind() == kind::STRING_PREFIX) {
+ if(node[0].isConst() && node[1].isConst()) {
+ CVC4::String s = node[1].getConst<String>();
+ CVC4::String t = node[0].getConst<String>();
+ retNode = NodeManager::currentNM()->mkConst( false );
+ if(s.size() >= t.size()) {
+ if(t == s.substr(0, t.size())) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ }
+ }
+ } else {
+ Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[0]);
+ Node lent = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[1]);
+ retNode = NodeManager::currentNM()->mkNode(kind::AND,
+ NodeManager::currentNM()->mkNode(kind::GEQ, lent, lens),
+ node[0].eqNode(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, node[1],
+ NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) ), lens)));
+ }
+ } else if(node.getKind() == kind::STRING_SUFFIX) {
+ if(node[0].isConst() && node[1].isConst()) {
+ CVC4::String s = node[1].getConst<String>();
+ CVC4::String t = node[0].getConst<String>();
+ retNode = NodeManager::currentNM()->mkConst( false );
+ if(s.size() >= t.size()) {
+ if(t == s.substr(s.size() - t.size(), t.size())) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ }
+ }
+ } else {
+ Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[0]);
+ Node lent = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, node[1]);
+ retNode = NodeManager::currentNM()->mkNode(kind::AND,
+ NodeManager::currentNM()->mkNode(kind::GEQ, lent, lens),
+ node[0].eqNode(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, node[1],
+ NodeManager::currentNM()->mkNode(kind::MINUS, lent, lens), lens)));
+ }
+ } else if(node.getKind() == kind::STRING_ITOS || node.getKind() == kind::STRING_U16TOS || node.getKind() == kind::STRING_U32TOS) {
+ if(node[0].isConst()) {
+ bool flag = false;
+ std::string stmp = node[0].getConst<Rational>().getNumerator().toString();
+ if(node.getKind() == kind::STRING_U16TOS) {
+ CVC4::Rational r1(UINT16_MAX);
+ CVC4::Rational r2 = node[0].getConst<Rational>();
+ if(r2>r1) {
+ flag = true;
+ }
+ } else if(node.getKind() == kind::STRING_U32TOS) {
+ CVC4::Rational r1(UINT32_MAX);
+ CVC4::Rational r2 = node[0].getConst<Rational>();
+ if(r2>r1) {
+ flag = true;
+ }
+ }
+ //std::string stmp = static_cast<std::ostringstream*>( &(std::ostringstream() << node[0]) )->str();
+ if(flag || stmp[0] == '-') {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::String(stmp) );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STOI || node.getKind() == kind::STRING_STOU16 || node.getKind() == kind::STRING_STOU32) {
+ if(node[0].isConst()) {
+ CVC4::String s = node[0].getConst<String>();
+ if(s.isNumber()) {
+ std::string stmp = s.toString();
+ //if(stmp[0] == '0' && stmp.size() != 1) {
+ //TODO: leading zeros
+ //retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
+ //} else {
+ bool flag = false;
+ CVC4::Rational r2(stmp.c_str());
+ if(node.getKind() == kind::STRING_U16TOS) {
+ CVC4::Rational r1(UINT16_MAX);
+ if(r2>r1) {
+ flag = true;
+ }
+ } else if(node.getKind() == kind::STRING_U32TOS) {
+ CVC4::Rational r1(UINT32_MAX);
+ if(r2>r1) {
+ flag = true;
+ }
+ }
+ if(flag) {
+ retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( r2 );
+ }
+ //}
+ } else {
+ retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
+ }
+ } else if(node[0].getKind() == kind::STRING_CONCAT) {
+ for(unsigned i=0; i<node[0].getNumChildren(); ++i) {
+ if(node[0][i].isConst()) {
+ CVC4::String t = node[0][i].getConst<String>();
+ if(!t.isNumber()) {
+ retNode = NodeManager::currentNM()->mkConst(::CVC4::Rational(-1));
+ break;
+ }
+ }
+ }
+ }
+ } else if(node.getKind() == kind::STRING_IN_REGEXP) {
+ retNode = rewriteMembership(node);
+ }
Trace("strings-postrewrite") << "Strings::postRewrite returning " << retNode << std::endl;
return RewriteResponse(orig==retNode ? REWRITE_DONE : REWRITE_AGAIN_FULL, retNode);
RewriteResponse TheoryStringsRewriter::preRewrite(TNode node) {
Node retNode = node;
- Node orig = retNode;
+ Node orig = retNode;
Trace("strings-prerewrite") << "Strings::preRewrite start " << node << std::endl;
if(node.getKind() == kind::STRING_CONCAT) {
} else if(node.getKind() == kind::REGEXP_CONCAT) {
retNode = prerewriteConcatRegExp(node);
} else if(node.getKind() == kind::REGEXP_UNION) {
- retNode = prerewriteOrRegExp(node);
- } else if(node.getKind() == kind::REGEXP_STAR) {
- if(node[0].getKind() == kind::REGEXP_STAR) {
- retNode = node[0];
- }
- } else if(node.getKind() == kind::REGEXP_PLUS) {
- retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, node[0],
+ retNode = prerewriteOrRegExp(node);
+ } else if(node.getKind() == kind::REGEXP_STAR) {
+ if(node[0].getKind() == kind::REGEXP_STAR) {
+ retNode = node[0];
+ }
+ } else if(node.getKind() == kind::REGEXP_PLUS) {
+ retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, node[0],
NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, node[0]));
- } else if(node.getKind() == kind::REGEXP_OPT) {
- retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_UNION,
- NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String("") ) ),
- node[0]);
- } else if(node.getKind() == kind::REGEXP_RANGE) {
- std::vector< Node > vec_nodes;
- char c = node[0].getConst<String>().getFirstChar();
- char end = node[1].getConst<String>().getFirstChar();
- for(; c<=end; ++c) {
- Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) );
- vec_nodes.push_back( n );
- }
- if(vec_nodes.size() == 1) {
- retNode = vec_nodes[0];
- } else {
- retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes );
- }
- } else if(node.getKind() == kind::REGEXP_LOOP) {
- Node r = node[0];
- if(r.getKind() == kind::REGEXP_STAR) {
- retNode = r;
- } else {
- unsigned l = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<l; i++) {
- vec_nodes.push_back(r);
- }
- if(node.getNumChildren() == 3) {
- Node n = vec_nodes.size()==0 ? NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(CVC4::String("")))
- : vec_nodes.size()==1 ? r : prerewriteConcatRegExp(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes));
- unsigned u = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
- if(u <= l) {
- retNode = n;
- } else {
- std::vector< Node > vec2;
- vec2.push_back(n);
- for(unsigned j=l; j<u; j++) {
- vec_nodes.push_back(r);
- n = vec_nodes.size()==1? r : prerewriteConcatRegExp(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes));
- vec2.push_back(n);
- }
- retNode = prerewriteOrRegExp(NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec2));
- }
- } else {
- Node rest = NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, r);
- retNode = vec_nodes.size()==0? rest : prerewriteConcatRegExp( vec_nodes.size()==1?
- NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, rest)
- :NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
- NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes), rest) );
- }
- }
- Trace("strings-lp") << "Strings::lp " << node << " => " << retNode << std::endl;
- }
+ } else if(node.getKind() == kind::REGEXP_OPT) {
+ retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_UNION,
+ NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String("") ) ),
+ node[0]);
+ } else if(node.getKind() == kind::REGEXP_RANGE) {
+ std::vector< Node > vec_nodes;
+ char c = node[0].getConst<String>().getFirstChar();
+ char end = node[1].getConst<String>().getFirstChar();
+ for(; c<=end; ++c) {
+ Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) );
+ vec_nodes.push_back( n );
+ }
+ if(vec_nodes.size() == 1) {
+ retNode = vec_nodes[0];
+ } else {
+ retNode = NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes );
+ }
+ } else if(node.getKind() == kind::REGEXP_LOOP) {
+ Node r = node[0];
+ if(r.getKind() == kind::REGEXP_STAR) {
+ retNode = r;
+ } else {
+ unsigned l = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<l; i++) {
+ vec_nodes.push_back(r);
+ }
+ if(node.getNumChildren() == 3) {
+ Node n = vec_nodes.size()==0 ? NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(CVC4::String("")))
+ : vec_nodes.size()==1 ? r : prerewriteConcatRegExp(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes));
+ unsigned u = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ if(u <= l) {
+ retNode = n;
+ } else {
+ std::vector< Node > vec2;
+ vec2.push_back(n);
+ for(unsigned j=l; j<u; j++) {
+ vec_nodes.push_back(r);
+ n = vec_nodes.size()==1? r : prerewriteConcatRegExp(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes));
+ vec2.push_back(n);
+ }
+ retNode = prerewriteOrRegExp(NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec2));
+ }
+ } else {
+ Node rest = NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, r);
+ retNode = vec_nodes.size()==0? rest : prerewriteConcatRegExp( vec_nodes.size()==1?
+ NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, rest)
+ :NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
+ NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes), rest) );
+ }
+ }
+ Trace("strings-lp") << "Strings::lp " << node << " => " << retNode << std::endl;
+ }
Trace("strings-prerewrite") << "Strings::preRewrite returning " << retNode << std::endl;
return RewriteResponse(orig==retNode ? REWRITE_DONE : REWRITE_AGAIN_FULL, retNode);
namespace strings {
class StringEnumerator : public TypeEnumeratorBase<StringEnumerator> {
- std::vector< unsigned > d_data;
- unsigned d_cardinality;
- Node d_curr;
- void mkCurr() {
- //make constant from d_data
- d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
- }
+ std::vector< unsigned > d_data;
+ unsigned d_cardinality;
+ Node d_curr;
+ void mkCurr() {
+ //make constant from d_data
+ d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
+ }
public:
StringEnumerator(TypeNode type) throw(AssertionException) :
return d_curr;
}
StringEnumerator& operator++() throw() {
- bool changed = false;
- do{
- for(unsigned i=0; i<d_data.size(); ++i) {
- if( d_data[i] + 1 < d_cardinality ) {
- ++d_data[i]; changed = true;
- break;
- } else {
- d_data[i] = 0;
- }
- }
-
- if(!changed) {
- d_data.push_back( 0 );
- }
- }while(!changed);
-
- mkCurr();
+ bool changed = false;
+ do{
+ for(unsigned i=0; i<d_data.size(); ++i) {
+ if( d_data[i] + 1 < d_cardinality ) {
+ ++d_data[i]; changed = true;
+ break;
+ } else {
+ d_data[i] = 0;
+ }
+ }
+
+ if(!changed) {
+ d_data.push_back( 0 );
+ }
+ }while(!changed);
+
+ mkCurr();
return *this;
}
class StringEnumeratorLength {
private:
- unsigned d_cardinality;
- std::vector< unsigned > d_data;
- Node d_curr;
- void mkCurr() {
- //make constant from d_data
- d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
- }
+ unsigned d_cardinality;
+ std::vector< unsigned > d_data;
+ Node d_curr;
+ void mkCurr() {
+ //make constant from d_data
+ d_curr = NodeManager::currentNM()->mkConst( ::CVC4::String( d_data ) );
+ }
public:
StringEnumeratorLength(unsigned length, unsigned card = 256) : d_cardinality(card) {
for( unsigned i=0; i<length; i++ ){
d_data.push_back( 0 );
- }
- mkCurr();
+ }
+ mkCurr();
}
Node operator*() throw() {
d_data[i] = 0;
}
}
-
+
if(!changed) {
d_curr = Node::null();
}else{
d_str.clear();\r
unsigned i=0;\r
while(i < s.size()) {\r
- if(s[i] == '\\') {\r
- i++;\r
- if(i < s.size()) {\r
- switch(s[i]) {\r
- case 'n': {d_str.push_back( convertCharToUnsignedInt('\n') );i++;} break;\r
- case 't': {d_str.push_back( convertCharToUnsignedInt('\t') );i++;} break;\r
- case 'v': {d_str.push_back( convertCharToUnsignedInt('\v') );i++;} break;\r
- case 'b': {d_str.push_back( convertCharToUnsignedInt('\b') );i++;} break;\r
- case 'r': {d_str.push_back( convertCharToUnsignedInt('\r') );i++;} break;\r
- case 'f': {d_str.push_back( convertCharToUnsignedInt('\f') );i++;} break;\r
- case 'a': {d_str.push_back( convertCharToUnsignedInt('\a') );i++;} break;\r
- case '\\': {d_str.push_back( convertCharToUnsignedInt('\\') );i++;} break;\r
- case 'x': {\r
- if(i + 2 < s.size()) {\r
- if((isdigit(s[i+1]) || (s[i+1] >= 'a' && s[i+1] >= 'f') || (s[i+1] >= 'A' && s[i+1] >= 'F')) &&\r
- (isdigit(s[i+2]) || (s[i+2] >= 'a' && s[i+2] >= 'f') || (s[i+2] >= 'A' && s[i+2] >= 'F'))) {\r
- d_str.push_back( convertCharToUnsignedInt( hexToDec(s[i+1]) * 16 + hexToDec(s[i+2]) ) );\r
- i += 3;\r
- } else {\r
- throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );\r
- }\r
- } else {\r
- throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );\r
- }\r
- }\r
- break;\r
- default: {\r
- if(isdigit(s[i])) {\r
- int num = (int)s[i] - (int)'0';\r
- bool flag = num < 4;\r
- if(i+1 < s.size() && num < 8 && isdigit(s[i+1]) && s[i+1] < '8') {\r
- num = num * 8 + (int)s[i+1] - (int)'0';\r
- if(flag && i+2 < s.size() && isdigit(s[i+2]) && s[i+2] < '8') {\r
- num = num * 8 + (int)s[i+2] - (int)'0';\r
- d_str.push_back( convertCharToUnsignedInt((char)num) );\r
- i += 3;\r
- } else {\r
- d_str.push_back( convertCharToUnsignedInt((char)num) );\r
- i += 2;\r
- }\r
- } else {\r
- d_str.push_back( convertCharToUnsignedInt((char)num) );\r
- i++;\r
- }\r
- } else {\r
- d_str.push_back( convertCharToUnsignedInt(s[i]) );\r
- i++;\r
- }\r
- }\r
- }\r
- } else {\r
- throw CVC4::Exception( "should be handled by lexer: \"" + s + "\"" );\r
- //d_str.push_back( convertCharToUnsignedInt('\\') );\r
- }\r
- } else {\r
- d_str.push_back( convertCharToUnsignedInt(s[i]) );\r
- i++;\r
- }\r
+ if(s[i] == '\\') {\r
+ i++;\r
+ if(i < s.size()) {\r
+ switch(s[i]) {\r
+ case 'n': {d_str.push_back( convertCharToUnsignedInt('\n') );i++;} break;\r
+ case 't': {d_str.push_back( convertCharToUnsignedInt('\t') );i++;} break;\r
+ case 'v': {d_str.push_back( convertCharToUnsignedInt('\v') );i++;} break;\r
+ case 'b': {d_str.push_back( convertCharToUnsignedInt('\b') );i++;} break;\r
+ case 'r': {d_str.push_back( convertCharToUnsignedInt('\r') );i++;} break;\r
+ case 'f': {d_str.push_back( convertCharToUnsignedInt('\f') );i++;} break;\r
+ case 'a': {d_str.push_back( convertCharToUnsignedInt('\a') );i++;} break;\r
+ case '\\': {d_str.push_back( convertCharToUnsignedInt('\\') );i++;} break;\r
+ case 'x': {\r
+ if(i + 2 < s.size()) {\r
+ if((isdigit(s[i+1]) || (s[i+1] >= 'a' && s[i+1] >= 'f') || (s[i+1] >= 'A' && s[i+1] >= 'F')) &&\r
+ (isdigit(s[i+2]) || (s[i+2] >= 'a' && s[i+2] >= 'f') || (s[i+2] >= 'A' && s[i+2] >= 'F'))) {\r
+ d_str.push_back( convertCharToUnsignedInt( hexToDec(s[i+1]) * 16 + hexToDec(s[i+2]) ) );\r
+ i += 3;\r
+ } else {\r
+ throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );\r
+ }\r
+ } else {\r
+ throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );\r
+ }\r
+ }\r
+ break;\r
+ default: {\r
+ if(isdigit(s[i])) {\r
+ int num = (int)s[i] - (int)'0';\r
+ bool flag = num < 4;\r
+ if(i+1 < s.size() && num < 8 && isdigit(s[i+1]) && s[i+1] < '8') {\r
+ num = num * 8 + (int)s[i+1] - (int)'0';\r
+ if(flag && i+2 < s.size() && isdigit(s[i+2]) && s[i+2] < '8') {\r
+ num = num * 8 + (int)s[i+2] - (int)'0';\r
+ d_str.push_back( convertCharToUnsignedInt((char)num) );\r
+ i += 3;\r
+ } else {\r
+ d_str.push_back( convertCharToUnsignedInt((char)num) );\r
+ i += 2;\r
+ }\r
+ } else {\r
+ d_str.push_back( convertCharToUnsignedInt((char)num) );\r
+ i++;\r
+ }\r
+ } else {\r
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );\r
+ i++;\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ throw CVC4::Exception( "should be handled by lexer: \"" + s + "\"" );\r
+ //d_str.push_back( convertCharToUnsignedInt('\\') );\r
+ }\r
+ } else {\r
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );\r
+ i++;\r
+ }\r
}\r
}\r
\r
void String::getCharSet(std::set<unsigned int> &cset) const {\r
- for(std::vector<unsigned int>::const_iterator itr = d_str.begin();\r
- itr != d_str.end(); itr++) {\r
- cset.insert( *itr );\r
- }\r
+ for(std::vector<unsigned int>::const_iterator itr = d_str.begin();\r
+ itr != d_str.end(); itr++) {\r
+ cset.insert( *itr );\r
+ }\r
}\r
\r
bool String::overlap(String &y) const {\r
- unsigned n = d_str.size() < y.size() ? d_str.size() : y.size();\r
- for(unsigned i=1; i<n; i++) {\r
- String s = suffix(i);\r
- String p = y.prefix(i);\r
- if(s == p) {\r
- return true;\r
- }\r
- }\r
- return false;\r
+ unsigned n = d_str.size() < y.size() ? d_str.size() : y.size();\r
+ for(unsigned i=1; i<n; i++) {\r
+ String s = suffix(i);\r
+ String p = y.prefix(i);\r
+ if(s == p) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
}\r
\r
std::string String::toString() const {\r
- std::string str;\r
- for(unsigned int i=0; i<d_str.size(); ++i) {\r
- char c = convertUnsignedIntToChar( d_str[i] );\r
- if(isprint( c )) {\r
- if(c == '\\') {\r
- str += "\\\\";\r
- } else if(c == '\"') {\r
- str += "\\\"";\r
- } else {\r
- str += c;\r
- }\r
- } else {\r
- std::string s;\r
- switch(c) {\r
- case '\a': s = "\\a"; break;\r
- case '\b': s = "\\b"; break;\r
- case '\t': s = "\\t"; break;\r
- case '\r': s = "\\r"; break;\r
- case '\v': s = "\\v"; break;\r
- case '\f': s = "\\f"; break;\r
- case '\n': s = "\\n"; break;\r
- case '\e': s = "\\e"; break;\r
- default : {\r
- std::stringstream ss;\r
- ss << std::setfill ('0') << std::setw(2) << std::hex << ((int)c);\r
- std::string t = ss.str();\r
- t = t.substr(t.size()-2, 2);\r
- s = "\\x" + t;\r
- //std::string s2 = static_cast<std::ostringstream*>( &(std::ostringstream() << (int)c) )->str();\r
- }\r
- }\r
- str += s;\r
- }\r
- }\r
- return str;\r
+ std::string str;\r
+ for(unsigned int i=0; i<d_str.size(); ++i) {\r
+ char c = convertUnsignedIntToChar( d_str[i] );\r
+ if(isprint( c )) {\r
+ if(c == '\\') {\r
+ str += "\\\\";\r
+ } else if(c == '\"') {\r
+ str += "\\\"";\r
+ } else {\r
+ str += c;\r
+ }\r
+ } else {\r
+ std::string s;\r
+ switch(c) {\r
+ case '\a': s = "\\a"; break;\r
+ case '\b': s = "\\b"; break;\r
+ case '\t': s = "\\t"; break;\r
+ case '\r': s = "\\r"; break;\r
+ case '\v': s = "\\v"; break;\r
+ case '\f': s = "\\f"; break;\r
+ case '\n': s = "\\n"; break;\r
+ case '\e': s = "\\e"; break;\r
+ default : {\r
+ std::stringstream ss;\r
+ ss << std::setfill ('0') << std::setw(2) << std::hex << ((int)c);\r
+ std::string t = ss.str();\r
+ t = t.substr(t.size()-2, 2);\r
+ s = "\\x" + t;\r
+ //std::string s2 = static_cast<std::ostringstream*>( &(std::ostringstream() << (int)c) )->str();\r
+ }\r
+ }\r
+ str += s;\r
+ }\r
+ }\r
+ return str;\r
}\r
\r
std::ostream& operator <<(std::ostream& os, const String& s) {\r
//guarded
char hexToDec(char c) {
- if(isdigit(c)) {
- return c - '0';
- } else if (c >= 'a' && c >= 'f') {
- return c - 'a' + 10;
- } else {
- return c - 'A' + 10;
- }
+ if(isdigit(c)) {
+ return c - '0';
+ } else if (c >= 'a' && c >= 'f') {
+ return c - 'a' + 10;
+ } else {
+ return c - 'A' + 10;
+ }
}
void toInternal(const std::string &s);
}
bool isEmptyString() const {
- return ( d_str.size() == 0 );
+ return ( d_str.size() == 0 );
}
unsigned int operator[] (const unsigned int i) const {
- //Assert( i < d_str.size() && i >= 0);
+ //Assert( i < d_str.size() && i >= 0);
return d_str[i];
}
/*
}
bool isRepeated() const {
- if(d_str.size() > 1) {
- unsigned int f = d_str[0];
- for(unsigned i=1; i<d_str.size(); ++i) {
- if(f != d_str[i]) return false;
- }
- }
- return true;
+ if(d_str.size() > 1) {
+ unsigned int f = d_str[0];
+ for(unsigned i=1; i<d_str.size(); ++i) {
+ if(f != d_str[i]) return false;
+ }
+ }
+ return true;
}
bool tailcmp(const String &y, int &c) const {
- int id_x = d_str.size() - 1;
- int id_y = y.d_str.size() - 1;
- while(id_x>=0 && id_y>=0) {
- if(d_str[id_x] != y.d_str[id_y]) {
- c = id_x;
- return false;
- }
- --id_x; --id_y;
- }
- c = id_x == -1 ? ( - (id_y+1) ) : (id_x + 1);
- return true;
+ int id_x = d_str.size() - 1;
+ int id_y = y.d_str.size() - 1;
+ while(id_x>=0 && id_y>=0) {
+ if(d_str[id_x] != y.d_str[id_y]) {
+ c = id_x;
+ return false;
+ }
+ --id_x; --id_y;
+ }
+ c = id_x == -1 ? ( - (id_y+1) ) : (id_x + 1);
+ return true;
}
std::size_t find(const String &y, const int start = 0) const {
- if(d_str.size() < y.d_str.size() + (std::size_t) start) return std::string::npos;
- if(y.d_str.size() == 0) return (std::size_t) start;
- if(d_str.size() == 0) return std::string::npos;
- std::size_t ret = std::string::npos;
- for(int i = start; i <= (int) d_str.size() - (int) y.d_str.size(); i++) {
- if(d_str[i] == y.d_str[0]) {
- std::size_t j=0;
- for(; j<y.d_str.size(); j++) {
- if(d_str[i+j] != y.d_str[j]) break;
- }
- if(j == y.d_str.size()) {
- ret = (std::size_t) i;
- break;
- }
- }
- }
- return ret;
+ if(d_str.size() < y.d_str.size() + (std::size_t) start) return std::string::npos;
+ if(y.d_str.size() == 0) return (std::size_t) start;
+ if(d_str.size() == 0) return std::string::npos;
+ std::size_t ret = std::string::npos;
+ for(int i = start; i <= (int) d_str.size() - (int) y.d_str.size(); i++) {
+ if(d_str[i] == y.d_str[0]) {
+ std::size_t j=0;
+ for(; j<y.d_str.size(); j++) {
+ if(d_str[i+j] != y.d_str[j]) break;
+ }
+ if(j == y.d_str.size()) {
+ ret = (std::size_t) i;
+ break;
+ }
+ }
+ }
+ return ret;
}
String replace(const String &s, const String &t) const {
std::size_t ret = find(s);
if( ret != std::string::npos ) {
std::vector<unsigned int> vec;
- vec.insert(vec.begin(), d_str.begin(), d_str.begin() + ret);
+ vec.insert(vec.begin(), d_str.begin(), d_str.begin() + ret);
vec.insert(vec.end(), t.d_str.begin(), t.d_str.end());
vec.insert(vec.end(), d_str.begin() + ret + s.d_str.size(), d_str.end());
return String(vec);
}
String prefix(unsigned i) const {
- return substr(0, i);
+ return substr(0, i);
}
String suffix(unsigned i) const {
- return substr(d_str.size() - i, i);
+ return substr(d_str.size() - i, i);
}
bool overlap(String &y) const;
bool isNumber() const {
- if(d_str.size() == 0) return false;
- for(unsigned int i=0; i<d_str.size(); ++i) {
- char c = convertUnsignedIntToChar( d_str[i] );
- if(c<'0' || c>'9') {
- return false;
- }
- }
- return true;
+ if(d_str.size() == 0) return false;
+ for(unsigned int i=0; i<d_str.size(); ++i) {
+ char c = convertUnsignedIntToChar( d_str[i] );
+ if(c<'0' || c>'9') {
+ return false;
+ }
+ }
+ return true;
}
int toNumber() const {
- if(isNumber()) {
- int ret=0;
- for(unsigned int i=0; i<d_str.size(); ++i) {
- char c = convertUnsignedIntToChar( d_str[i] );
- ret = ret * 10 + (int)c - (int)'0';
- }
- return ret;
- } else {
- return -1;
- }
+ if(isNumber()) {
+ int ret=0;
+ for(unsigned int i=0; i<d_str.size(); ++i) {
+ char c = convertUnsignedIntToChar( d_str[i] );
+ ret = ret * 10 + (int)c - (int)'0';
+ }
+ return ret;
+ } else {
+ return -1;
+ }
}
void getCharSet(std::set<unsigned int> &cset) const;
};/* class String */