diff options
-rw-r--r-- | src/parser/antlr_input.cpp | 8 | ||||
-rw-r--r-- | src/theory/strings/regexp_operation.cpp | 2852 | ||||
-rw-r--r-- | src/theory/strings/regexp_operation.h | 90 | ||||
-rw-r--r-- | src/theory/strings/theory_strings.cpp | 3622 | ||||
-rw-r--r-- | src/theory/strings/theory_strings.h | 476 | ||||
-rw-r--r-- | src/theory/strings/theory_strings_preprocess.cpp | 956 | ||||
-rw-r--r-- | src/theory/strings/theory_strings_preprocess.h | 20 | ||||
-rw-r--r-- | src/theory/strings/theory_strings_rewriter.cpp | 812 | ||||
-rw-r--r-- | src/theory/strings/type_enumerator.h | 68 | ||||
-rw-r--r-- | src/util/regexp.cpp | 212 | ||||
-rw-r--r-- | src/util/regexp.h | 130 |
11 files changed, 4618 insertions, 4628 deletions
diff --git a/src/parser/antlr_input.cpp b/src/parser/antlr_input.cpp index 88b43eb0e..127365b78 100644 --- a/src/parser/antlr_input.cpp +++ b/src/parser/antlr_input.cpp @@ -372,8 +372,8 @@ std::string parseErrorHelper(const char* lineStart, int charPositionInLine, cons // 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]) ) ) { @@ -396,8 +396,8 @@ std::string parseErrorHelper(const char* lineStart, int charPositionInLine, cons } 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]) ) ) { diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp index 5c664ba34..fef6cec96 100644 --- a/src/theory/strings/regexp_operation.cpp +++ b/src/theory/strings/regexp_operation.cpp @@ -1,25 +1,15 @@ /********************* */
-/*! \file regexp_operation.cpp -
- ** \verbatim -
- ** Original author: Tianyi Liang -
- ** Major contributors: none -
- ** Minor contributors (to current version): none -
- ** This file is part of the CVC4 project. -
- ** Copyright (c) 2009-2013 New York University and The University of Iowa -
- ** See the file COPYING in the top-level source directory for licensing -
- ** information.\endverbatim -
- ** -
+/*! \file regexp_operation.cpp
+ ** \verbatim
+ ** Original author: Tianyi Liang
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
** \brief Symbolic Regular Expresion Operations
**
** Symbolic Regular Expresion Operations
@@ -36,14 +26,14 @@ RegExpOpr::RegExpOpr() { d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
- d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
- d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
- std::vector< Node > nvec;
+ d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
+ d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
+ d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
+ std::vector< Node > nvec;
d_emptyRegexp = NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec );
- d_sigma = NodeManager::currentNM()->mkNode( kind::REGEXP_SIGMA, nvec );
- d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );
- d_card = 256;
+ d_sigma = NodeManager::currentNM()->mkNode( kind::REGEXP_SIGMA, nvec );
+ d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );
+ d_card = 256;
}
int RegExpOpr::gcd ( int a, int b ) {
@@ -55,1470 +45,1470 @@ int RegExpOpr::gcd ( int a, int b ) { }
bool RegExpOpr::checkConstRegExp( Node r ) {
- Trace("strings-regexp-cstre") << "RegExp-CheckConstRegExp starts with " << mkString( r ) << std::endl;
- bool ret = true;
- if( d_cstre_cache.find( r ) != d_cstre_cache.end() ) {
- ret = d_cstre_cache[r];
- } else {
- if(r.getKind() == kind::STRING_TO_REGEXP) {
- Node tmp = Rewriter::rewrite( r[0] );
- ret = tmp.isConst();
- } else {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(!checkConstRegExp(r[i])) {
- ret = false; break;
- }
- }
- }
- d_cstre_cache[r] = ret;
- }
- return ret;
+ Trace("strings-regexp-cstre") << "RegExp-CheckConstRegExp starts with " << mkString( r ) << std::endl;
+ bool ret = true;
+ if( d_cstre_cache.find( r ) != d_cstre_cache.end() ) {
+ ret = d_cstre_cache[r];
+ } else {
+ if(r.getKind() == kind::STRING_TO_REGEXP) {
+ Node tmp = Rewriter::rewrite( r[0] );
+ ret = tmp.isConst();
+ } else {
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(!checkConstRegExp(r[i])) {
+ ret = false; break;
+ }
+ }
+ }
+ d_cstre_cache[r] = ret;
+ }
+ return ret;
}
// 0-unknown, 1-yes, 2-no
int RegExpOpr::delta( Node r, Node &exp ) {
- Trace("regexp-delta") << "RegExp-Delta starts with " << mkString( r ) << std::endl;
- int ret = 0;
- if( d_delta_cache.find( r ) != d_delta_cache.end() ) {
- ret = d_delta_cache[r].first;
- exp = d_delta_cache[r].second;
- } else {
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- ret = 2;
- break;
- }
- case kind::REGEXP_SIGMA: {
- ret = 2;
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node tmp = Rewriter::rewrite(r[0]);
- if(tmp.isConst()) {
- if(tmp == d_emptyString) {
- ret = 1;
- } else {
- ret = 2;
- }
- } else {
- ret = 0;
- if(tmp.getKind() == kind::STRING_CONCAT) {
- for(unsigned i=0; i<tmp.getNumChildren(); i++) {
- if(tmp[i].isConst()) {
- ret = 2; break;
- }
- }
+ Trace("regexp-delta") << "RegExp-Delta starts with " << mkString( r ) << std::endl;
+ int ret = 0;
+ if( d_delta_cache.find( r ) != d_delta_cache.end() ) {
+ ret = d_delta_cache[r].first;
+ exp = d_delta_cache[r].second;
+ } else {
+ int k = r.getKind();
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ ret = 2;
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ ret = 2;
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ Node tmp = Rewriter::rewrite(r[0]);
+ if(tmp.isConst()) {
+ if(tmp == d_emptyString) {
+ ret = 1;
+ } else {
+ ret = 2;
+ }
+ } else {
+ ret = 0;
+ if(tmp.getKind() == kind::STRING_CONCAT) {
+ for(unsigned i=0; i<tmp.getNumChildren(); i++) {
+ if(tmp[i].isConst()) {
+ ret = 2; break;
+ }
+ }
- }
- if(ret == 0) {
- exp = r[0].eqNode(d_emptyString);
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 2) {
- ret = 2;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
- }
- if(ret != 2) {
- if(!flag) {
- ret = 1;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- }
- }
- break;
- }
- case kind::REGEXP_UNION: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 1) {
- ret = 1;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
- }
- if(ret != 1) {
- if(!flag) {
- ret = 2;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::OR, vec_nodes);
- }
- }
- break;
- }
- case kind::REGEXP_INTER: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 2) {
- ret = 2;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
- }
- if(ret != 2) {
- if(!flag) {
- ret = 1;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- }
- }
- break;
- }
- case kind::REGEXP_STAR: {
- ret = 1;
- break;
- }
- case kind::REGEXP_PLUS: {
- ret = delta( r[0], exp );
- break;
- }
- case kind::REGEXP_OPT: {
- ret = 1;
- break;
- }
- case kind::REGEXP_RANGE: {
- ret = 2;
- break;
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;
- Assert( false );
- //return Node::null();
- }
- }
- if(!exp.isNull()) {
- exp = Rewriter::rewrite(exp);
- }
- std::pair< int, Node > p(ret, exp);
- d_delta_cache[r] = p;
- }
- Trace("regexp-delta") << "RegExp-Delta returns : " << ret << std::endl;
- return ret;
+ }
+ if(ret == 0) {
+ exp = r[0].eqNode(d_emptyString);
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ bool flag = false;
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node exp2;
+ int tmp = delta( r[i], exp2 );
+ if(tmp == 2) {
+ ret = 2;
+ break;
+ } else if(tmp == 0) {
+ vec_nodes.push_back( exp2 );
+ flag = true;
+ }
+ }
+ if(ret != 2) {
+ if(!flag) {
+ ret = 1;
+ } else {
+ exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ bool flag = false;
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node exp2;
+ int tmp = delta( r[i], exp2 );
+ if(tmp == 1) {
+ ret = 1;
+ break;
+ } else if(tmp == 0) {
+ vec_nodes.push_back( exp2 );
+ flag = true;
+ }
+ }
+ if(ret != 1) {
+ if(!flag) {
+ ret = 2;
+ } else {
+ exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::OR, vec_nodes);
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ bool flag = false;
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node exp2;
+ int tmp = delta( r[i], exp2 );
+ if(tmp == 2) {
+ ret = 2;
+ break;
+ } else if(tmp == 0) {
+ vec_nodes.push_back( exp2 );
+ flag = true;
+ }
+ }
+ if(ret != 2) {
+ if(!flag) {
+ ret = 1;
+ } else {
+ exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ ret = 1;
+ break;
+ }
+ case kind::REGEXP_PLUS: {
+ ret = delta( r[0], exp );
+ break;
+ }
+ case kind::REGEXP_OPT: {
+ ret = 1;
+ break;
+ }
+ case kind::REGEXP_RANGE: {
+ ret = 2;
+ break;
+ }
+ default: {
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;
+ Assert( false );
+ //return Node::null();
+ }
+ }
+ if(!exp.isNull()) {
+ exp = Rewriter::rewrite(exp);
+ }
+ std::pair< int, Node > p(ret, exp);
+ d_delta_cache[r] = p;
+ }
+ Trace("regexp-delta") << "RegExp-Delta returns : " << ret << std::endl;
+ return ret;
}
// 0-unknown, 1-yes, 2-no
int RegExpOpr::derivativeS( Node r, CVC4::String c, Node &retNode ) {
- Assert( c.size() < 2 );
- Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;
-
- int ret = 1;
- retNode = d_emptyRegexp;
-
- PairNodeStr dv = std::make_pair( r, c );
- if( d_deriv_cache.find( dv ) != d_deriv_cache.end() ) {
- retNode = d_deriv_cache[dv].first;
- ret = d_deriv_cache[dv].second;
- } else if( c.isEmptyString() ) {
- Node expNode;
- ret = delta( r, expNode );
- if(ret == 0) {
- retNode = NodeManager::currentNM()->mkNode(kind::ITE, expNode, r, d_emptyRegexp);
- } else if(ret == 1) {
- retNode = r;
- }
- std::pair< Node, int > p(retNode, ret);
- d_deriv_cache[dv] = p;
- } else {
- switch( r.getKind() ) {
- case kind::REGEXP_EMPTY: {
- ret = 2;
- break;
- }
- case kind::REGEXP_SIGMA: {
- retNode = d_emptySingleton;
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node tmp = Rewriter::rewrite(r[0]);
- if(tmp.isConst()) {
- if(tmp == d_emptyString) {
- ret = 2;
- } else {
- if(tmp.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
- tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );
- } else {
- ret = 2;
- }
- }
- } else {
- ret = 0;
- Node rest;
- if(tmp.getKind() == kind::STRING_CONCAT) {
- Node t2 = tmp[0];
- if(t2.isConst()) {
- if(t2.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
- Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
- tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );
- std::vector< Node > vec_nodes;
- vec_nodes.push_back(n);
- for(unsigned i=1; i<tmp.getNumChildren(); i++) {
- vec_nodes.push_back(tmp[i]);
- }
- retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);
- ret = 1;
- } else {
- ret = 2;
- }
- } else {
- tmp = tmp[0];
- std::vector< Node > vec_nodes;
- for(unsigned i=1; i<tmp.getNumChildren(); i++) {
- vec_nodes.push_back(tmp[i]);
- }
- rest = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);
- }
- }
- if(ret == 0) {
- Node sk = NodeManager::currentNM()->mkSkolem( "rsp", NodeManager::currentNM()->stringType(), "Split RegExp" );
- retNode = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, sk);
- if(!rest.isNull()) {
- retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, retNode, rest));
- }
- Node exp = tmp.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,
- NodeManager::currentNM()->mkConst(c), sk));
- retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, exp, retNode, d_emptyRegexp));
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- std::vector< Node > vec_nodes;
- std::vector< Node > delta_nodes;
- Node dnode = d_true;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc;
- Node exp2;
- int rt = derivativeS(r[i], c, dc);
- if(rt != 2) {
- if(rt == 0) {
- ret = 0;
- }
- std::vector< Node > vec_nodes2;
- if(dc != d_emptySingleton) {
- vec_nodes2.push_back( dc );
- }
- for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
- if(r[j] != d_emptySingleton) {
- vec_nodes2.push_back( r[j] );
- }
- }
- Node tmp = vec_nodes2.size()==0 ? d_emptySingleton :
- vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );
- if(dnode != d_true) {
- tmp = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, dnode, tmp, d_emptyRegexp));
- ret = 0;
- }
- if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
- vec_nodes.push_back( tmp );
- }
- }
- Node exp3;
- int rt2 = delta( r[i], exp3 );
- if( rt2 == 0 ) {
- dnode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, dnode, exp3));
- } else if( rt2 == 2 ) {
- break;
- }
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- if(retNode == d_emptyRegexp) {
- ret = 2;
- }
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc;
- int rt = derivativeS(r[i], c, dc);
- if(rt == 0) {
- ret = 0;
- }
- if(rt != 2) {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- if(retNode == d_emptyRegexp) {
- ret = 2;
- }
- break;
- }
- case kind::REGEXP_INTER: {
- bool flag = true;
- bool flag_sg = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc;
- int rt = derivativeS(r[i], c, dc);
- if(rt == 0) {
- ret = 0;
- } else if(rt == 2) {
- flag = false;
- break;
- }
- if(dc == d_sigma_star) {
- flag_sg = true;
- } else {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- }
- if(flag) {
- if(vec_nodes.size() == 0 && flag_sg) {
- retNode = d_sigma_star;
- } else {
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );
- if(retNode == d_emptyRegexp) {
- ret = 2;
- }
- }
- } else {
- retNode = d_emptyRegexp;
- ret = 2;
- }
- break;
- }
- case kind::REGEXP_STAR: {
- Node dc;
- ret = derivativeS(r[0], c, dc);
- retNode = dc==d_emptyRegexp ? dc : (dc==d_emptySingleton ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r ));
- break;
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- if(retNode != d_emptyRegexp) {
- retNode = Rewriter::rewrite( retNode );
- }
- std::pair< Node, int > p(retNode, ret);
- d_deriv_cache[dv] = p;
- }
+ Assert( c.size() < 2 );
+ Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;
+
+ int ret = 1;
+ retNode = d_emptyRegexp;
- Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;
- return ret;
+ PairNodeStr dv = std::make_pair( r, c );
+ if( d_deriv_cache.find( dv ) != d_deriv_cache.end() ) {
+ retNode = d_deriv_cache[dv].first;
+ ret = d_deriv_cache[dv].second;
+ } else if( c.isEmptyString() ) {
+ Node expNode;
+ ret = delta( r, expNode );
+ if(ret == 0) {
+ retNode = NodeManager::currentNM()->mkNode(kind::ITE, expNode, r, d_emptyRegexp);
+ } else if(ret == 1) {
+ retNode = r;
+ }
+ std::pair< Node, int > p(retNode, ret);
+ d_deriv_cache[dv] = p;
+ } else {
+ switch( r.getKind() ) {
+ case kind::REGEXP_EMPTY: {
+ ret = 2;
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ retNode = d_emptySingleton;
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ Node tmp = Rewriter::rewrite(r[0]);
+ if(tmp.isConst()) {
+ if(tmp == d_emptyString) {
+ ret = 2;
+ } else {
+ if(tmp.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
+ tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );
+ } else {
+ ret = 2;
+ }
+ }
+ } else {
+ ret = 0;
+ Node rest;
+ if(tmp.getKind() == kind::STRING_CONCAT) {
+ Node t2 = tmp[0];
+ if(t2.isConst()) {
+ if(t2.getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
+ Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
+ tmp.getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( tmp.getConst< CVC4::String >().substr(1) ) );
+ std::vector< Node > vec_nodes;
+ vec_nodes.push_back(n);
+ for(unsigned i=1; i<tmp.getNumChildren(); i++) {
+ vec_nodes.push_back(tmp[i]);
+ }
+ retNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);
+ ret = 1;
+ } else {
+ ret = 2;
+ }
+ } else {
+ tmp = tmp[0];
+ std::vector< Node > vec_nodes;
+ for(unsigned i=1; i<tmp.getNumChildren(); i++) {
+ vec_nodes.push_back(tmp[i]);
+ }
+ rest = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes);
+ }
+ }
+ if(ret == 0) {
+ Node sk = NodeManager::currentNM()->mkSkolem( "rsp", NodeManager::currentNM()->stringType(), "Split RegExp" );
+ retNode = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, sk);
+ if(!rest.isNull()) {
+ retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, retNode, rest));
+ }
+ Node exp = tmp.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT,
+ NodeManager::currentNM()->mkConst(c), sk));
+ retNode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, exp, retNode, d_emptyRegexp));
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ std::vector< Node > vec_nodes;
+ std::vector< Node > delta_nodes;
+ Node dnode = d_true;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node dc;
+ Node exp2;
+ int rt = derivativeS(r[i], c, dc);
+ if(rt != 2) {
+ if(rt == 0) {
+ ret = 0;
+ }
+ std::vector< Node > vec_nodes2;
+ if(dc != d_emptySingleton) {
+ vec_nodes2.push_back( dc );
+ }
+ for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
+ if(r[j] != d_emptySingleton) {
+ vec_nodes2.push_back( r[j] );
+ }
+ }
+ Node tmp = vec_nodes2.size()==0 ? d_emptySingleton :
+ vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );
+ if(dnode != d_true) {
+ tmp = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::ITE, dnode, tmp, d_emptyRegexp));
+ ret = 0;
+ }
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
+ vec_nodes.push_back( tmp );
+ }
+ }
+ Node exp3;
+ int rt2 = delta( r[i], exp3 );
+ if( rt2 == 0 ) {
+ dnode = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND, dnode, exp3));
+ } else if( rt2 == 2 ) {
+ break;
+ }
+ }
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
+ if(retNode == d_emptyRegexp) {
+ ret = 2;
+ }
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node dc;
+ int rt = derivativeS(r[i], c, dc);
+ if(rt == 0) {
+ ret = 0;
+ }
+ if(rt != 2) {
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
+ vec_nodes.push_back( dc );
+ }
+ }
+ Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;
+ }
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
+ if(retNode == d_emptyRegexp) {
+ ret = 2;
+ }
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ bool flag = true;
+ bool flag_sg = false;
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node dc;
+ int rt = derivativeS(r[i], c, dc);
+ if(rt == 0) {
+ ret = 0;
+ } else if(rt == 2) {
+ flag = false;
+ break;
+ }
+ if(dc == d_sigma_star) {
+ flag_sg = true;
+ } else {
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
+ vec_nodes.push_back( dc );
+ }
+ }
+ }
+ if(flag) {
+ if(vec_nodes.size() == 0 && flag_sg) {
+ retNode = d_sigma_star;
+ } else {
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );
+ if(retNode == d_emptyRegexp) {
+ ret = 2;
+ }
+ }
+ } else {
+ retNode = d_emptyRegexp;
+ ret = 2;
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ Node dc;
+ ret = derivativeS(r[0], c, dc);
+ retNode = dc==d_emptyRegexp ? dc : (dc==d_emptySingleton ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r ));
+ break;
+ }
+ default: {
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;
+ Assert( false, "Unsupported Term" );
+ }
+ }
+ if(retNode != d_emptyRegexp) {
+ retNode = Rewriter::rewrite( retNode );
+ }
+ std::pair< Node, int > p(retNode, ret);
+ d_deriv_cache[dv] = p;
+ }
+
+ Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;
+ return ret;
}
Node RegExpOpr::derivativeSingle( Node r, CVC4::String c ) {
- Assert( c.size() < 2 );
- Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;
- Node retNode = d_emptyRegexp;
- PairNodeStr dv = std::make_pair( r, c );
- if( d_dv_cache.find( dv ) != d_dv_cache.end() ) {
- retNode = d_dv_cache[dv];
- } else if( c.isEmptyString() ){
- Node exp;
- int tmp = delta( r, exp );
- if(tmp == 0) {
- // TODO variable
- retNode = d_emptyRegexp;
- } else if(tmp == 1) {
- retNode = r;
- } else {
- retNode = d_emptyRegexp;
- }
- } else {
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- retNode = d_emptyRegexp;
- break;
- }
- case kind::REGEXP_SIGMA: {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
- break;
- }
- case kind::STRING_TO_REGEXP: {
- if(r[0].isConst()) {
- if(r[0] == d_emptyString) {
- retNode = d_emptyRegexp;
- } else {
- if(r[0].getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
- retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
- r[0].getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( r[0].getConst< CVC4::String >().substr(1) ) );
- } else {
- retNode = d_emptyRegexp;
- }
- }
- } else {
- // TODO variable
- retNode = d_emptyRegexp;
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- Node rees = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc = derivativeSingle(r[i], c);
- if(dc != d_emptyRegexp) {
- std::vector< Node > vec_nodes2;
- if(dc != rees) {
- vec_nodes2.push_back( dc );
- }
- for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
- if(r[j] != rees) {
- vec_nodes2.push_back( r[j] );
- }
- }
- Node tmp = vec_nodes2.size()==0 ? rees :
- vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );
- if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
- vec_nodes.push_back( tmp );
- }
- }
- Node exp;
- if( delta( r[i], exp ) != 1 ) {
- break;
- }
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc = derivativeSingle(r[i], c);
- if(dc != d_emptyRegexp) {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;
- }
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
- break;
- }
- case kind::REGEXP_INTER: {
- bool flag = true;
- bool flag_sg = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node dc = derivativeSingle(r[i], c);
- if(dc != d_emptyRegexp) {
- if(dc == d_sigma_star) {
- flag_sg = true;
- } else {
- if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
- vec_nodes.push_back( dc );
- }
- }
- } else {
- flag = false;
- break;
- }
- }
- if(flag) {
- if(vec_nodes.size() == 0 && flag_sg) {
- retNode = d_sigma_star;
- } else {
- retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
- ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );
- }
- } else {
- retNode = d_emptyRegexp;
- }
- break;
- }
- case kind::REGEXP_STAR: {
- Node dc = derivativeSingle(r[0], c);
- if(dc != d_emptyRegexp) {
- retNode = dc==NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ) ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r );
- } else {
- retNode = d_emptyRegexp;
- }
- break;
- }
- default: {
- //TODO: special sym: sigma, none, all
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- //return Node::null();
- }
- }
- if(retNode != d_emptyRegexp) {
- retNode = Rewriter::rewrite( retNode );
- }
- d_dv_cache[dv] = retNode;
- }
- Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;
- return retNode;
+ Assert( c.size() < 2 );
+ Trace("regexp-deriv") << "RegExp-deriv starts with R{ " << mkString( r ) << " }, c=" << c << std::endl;
+ Node retNode = d_emptyRegexp;
+ PairNodeStr dv = std::make_pair( r, c );
+ if( d_dv_cache.find( dv ) != d_dv_cache.end() ) {
+ retNode = d_dv_cache[dv];
+ } else if( c.isEmptyString() ){
+ Node exp;
+ int tmp = delta( r, exp );
+ if(tmp == 0) {
+ // TODO variable
+ retNode = d_emptyRegexp;
+ } else if(tmp == 1) {
+ retNode = r;
+ } else {
+ retNode = d_emptyRegexp;
+ }
+ } else {
+ int k = r.getKind();
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ retNode = d_emptyRegexp;
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ if(r[0].isConst()) {
+ if(r[0] == d_emptyString) {
+ retNode = d_emptyRegexp;
+ } else {
+ if(r[0].getConst< CVC4::String >().getFirstChar() == c.getFirstChar()) {
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP,
+ r[0].getConst< CVC4::String >().size() == 1 ? d_emptyString : NodeManager::currentNM()->mkConst( r[0].getConst< CVC4::String >().substr(1) ) );
+ } else {
+ retNode = d_emptyRegexp;
+ }
+ }
+ } else {
+ // TODO variable
+ retNode = d_emptyRegexp;
+ }
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ Node rees = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node dc = derivativeSingle(r[i], c);
+ if(dc != d_emptyRegexp) {
+ std::vector< Node > vec_nodes2;
+ if(dc != rees) {
+ vec_nodes2.push_back( dc );
+ }
+ for(unsigned j=i+1; j<r.getNumChildren(); ++j) {
+ if(r[j] != rees) {
+ vec_nodes2.push_back( r[j] );
+ }
+ }
+ Node tmp = vec_nodes2.size()==0 ? rees :
+ vec_nodes2.size()==1 ? vec_nodes2[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, vec_nodes2 );
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), tmp) == vec_nodes.end()) {
+ vec_nodes.push_back( tmp );
+ }
+ }
+ Node exp;
+ if( delta( r[i], exp ) != 1 ) {
+ break;
+ }
+ }
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node dc = derivativeSingle(r[i], c);
+ if(dc != d_emptyRegexp) {
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
+ vec_nodes.push_back( dc );
+ }
+ }
+ Trace("regexp-deriv") << "RegExp-deriv OR R[" << i << "]{ " << mkString(r[i]) << " returns " << mkString(dc) << std::endl;
+ }
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes ) );
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ bool flag = true;
+ bool flag_sg = false;
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ Node dc = derivativeSingle(r[i], c);
+ if(dc != d_emptyRegexp) {
+ if(dc == d_sigma_star) {
+ flag_sg = true;
+ } else {
+ if(std::find(vec_nodes.begin(), vec_nodes.end(), dc) == vec_nodes.end()) {
+ vec_nodes.push_back( dc );
+ }
+ }
+ } else {
+ flag = false;
+ break;
+ }
+ }
+ if(flag) {
+ if(vec_nodes.size() == 0 && flag_sg) {
+ retNode = d_sigma_star;
+ } else {
+ retNode = vec_nodes.size() == 0 ? d_emptyRegexp :
+ ( vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode( kind::REGEXP_INTER, vec_nodes ) );
+ }
+ } else {
+ retNode = d_emptyRegexp;
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ Node dc = derivativeSingle(r[0], c);
+ if(dc != d_emptyRegexp) {
+ retNode = dc==NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString ) ? r : NodeManager::currentNM()->mkNode( kind::REGEXP_CONCAT, dc, r );
+ } else {
+ retNode = d_emptyRegexp;
+ }
+ break;
+ }
+ default: {
+ //TODO: special sym: sigma, none, all
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in derivative of RegExp." << std::endl;
+ Assert( false, "Unsupported Term" );
+ //return Node::null();
+ }
+ }
+ if(retNode != d_emptyRegexp) {
+ retNode = Rewriter::rewrite( retNode );
+ }
+ d_dv_cache[dv] = retNode;
+ }
+ Trace("regexp-deriv") << "RegExp-deriv returns : " << mkString( retNode ) << std::endl;
+ return retNode;
}
//TODO:
bool RegExpOpr::guessLength( Node r, int &co ) {
- int k = r.getKind();
- switch( k ) {
- case kind::STRING_TO_REGEXP:
- {
- if(r[0].isConst()) {
- co += r[0].getConst< CVC4::String >().size();
- return true;
- } else {
- return false;
- }
- }
- break;
- case kind::REGEXP_CONCAT:
- {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(!guessLength( r[i], co)) {
- return false;
- }
- }
- return true;
- }
- break;
- case kind::REGEXP_UNION:
- {
- int g_co;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- int cop = 0;
- if(!guessLength( r[i], cop)) {
- return false;
- }
- if(i == 0) {
- g_co = cop;
- } else {
- g_co = gcd(g_co, cop);
- }
- }
- return true;
- }
- break;
- case kind::REGEXP_INTER:
- {
- int g_co;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- int cop = 0;
- if(!guessLength( r[i], cop)) {
- return false;
- }
- if(i == 0) {
- g_co = cop;
- } else {
- g_co = gcd(g_co, cop);
- }
- }
- return true;
- }
- break;
- case kind::REGEXP_STAR:
- {
- co = 0;
- return true;
- }
- break;
- default:
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in membership of RegExp." << std::endl;
- return false;
- }
+ int k = r.getKind();
+ switch( k ) {
+ case kind::STRING_TO_REGEXP:
+ {
+ if(r[0].isConst()) {
+ co += r[0].getConst< CVC4::String >().size();
+ return true;
+ } else {
+ return false;
+ }
+ }
+ break;
+ case kind::REGEXP_CONCAT:
+ {
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(!guessLength( r[i], co)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ break;
+ case kind::REGEXP_UNION:
+ {
+ int g_co;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ int cop = 0;
+ if(!guessLength( r[i], cop)) {
+ return false;
+ }
+ if(i == 0) {
+ g_co = cop;
+ } else {
+ g_co = gcd(g_co, cop);
+ }
+ }
+ return true;
+ }
+ break;
+ case kind::REGEXP_INTER:
+ {
+ int g_co;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ int cop = 0;
+ if(!guessLength( r[i], cop)) {
+ return false;
+ }
+ if(i == 0) {
+ g_co = cop;
+ } else {
+ g_co = gcd(g_co, cop);
+ }
+ }
+ return true;
+ }
+ break;
+ case kind::REGEXP_STAR:
+ {
+ co = 0;
+ return true;
+ }
+ break;
+ default:
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in membership of RegExp." << std::endl;
+ return false;
+ }
}
void RegExpOpr::firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) {
- std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_fset_cache.find(r);
- if(itr != d_fset_cache.end()) {
- pcset.insert((itr->second).first.begin(), (itr->second).first.end());
- pvset.insert((itr->second).second.begin(), (itr->second).second.end());
- } else {
- std::set<unsigned> cset;
- SetNodes vset;
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- break;
- }
- case kind::REGEXP_SIGMA: {
- for(unsigned i=0; i<d_card; i++) {
- cset.insert(i);
- }
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node st = Rewriter::rewrite(r[0]);
- if(st.isConst()) {
- CVC4::String s = st.getConst< CVC4::String >();
- if(s.size() != 0) {
- cset.insert(s[0]);
- }
- } else if(st.getKind() == kind::VARIABLE) {
- vset.insert( st );
- } else {
- if(st[0].isConst()) {
- CVC4::String s = st[0].getConst< CVC4::String >();
- cset.insert(s[0]);
- } else {
- vset.insert( st[0] );
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- firstChars(r[i], cset, vset);
- Node n = r[i];
- Node exp;
- int r = delta( n, exp );
- if(r != 1) {
- break;
- }
- }
- break;
- }
- case kind::REGEXP_UNION: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- firstChars(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_INTER: {
- //TODO: Overapproximation for now
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- firstChars(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- firstChars(r[0], cset, vset);
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- pcset.insert(cset.begin(), cset.end());
- pvset.insert(vset.begin(), vset.end());
- std::pair< std::set<unsigned>, SetNodes > p(cset, vset);
- d_fset_cache[r] = p;
+ std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_fset_cache.find(r);
+ if(itr != d_fset_cache.end()) {
+ pcset.insert((itr->second).first.begin(), (itr->second).first.end());
+ pvset.insert((itr->second).second.begin(), (itr->second).second.end());
+ } else {
+ std::set<unsigned> cset;
+ SetNodes vset;
+ int k = r.getKind();
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ for(unsigned i=0; i<d_card; i++) {
+ cset.insert(i);
+ }
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ Node st = Rewriter::rewrite(r[0]);
+ if(st.isConst()) {
+ CVC4::String s = st.getConst< CVC4::String >();
+ if(s.size() != 0) {
+ cset.insert(s[0]);
+ }
+ } else if(st.getKind() == kind::VARIABLE) {
+ vset.insert( st );
+ } else {
+ if(st[0].isConst()) {
+ CVC4::String s = st[0].getConst< CVC4::String >();
+ cset.insert(s[0]);
+ } else {
+ vset.insert( st[0] );
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ for(unsigned i=0; i<r.getNumChildren(); i++) {
+ firstChars(r[i], cset, vset);
+ Node n = r[i];
+ Node exp;
+ int r = delta( n, exp );
+ if(r != 1) {
+ break;
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ for(unsigned i=0; i<r.getNumChildren(); i++) {
+ firstChars(r[i], cset, vset);
+ }
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ //TODO: Overapproximation for now
+ for(unsigned i=0; i<r.getNumChildren(); i++) {
+ firstChars(r[i], cset, vset);
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ firstChars(r[0], cset, vset);
+ break;
+ }
+ default: {
+ Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;
+ Assert( false, "Unsupported Term" );
+ }
+ }
+ pcset.insert(cset.begin(), cset.end());
+ pvset.insert(vset.begin(), vset.end());
+ std::pair< std::set<unsigned>, SetNodes > p(cset, vset);
+ d_fset_cache[r] = p;
- Trace("regexp-fset") << "FSET( " << mkString(r) << " ) = { ";
- for(std::set<unsigned>::const_iterator itr = cset.begin();
- itr != cset.end(); itr++) {
- Trace("regexp-fset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";
- }
- Trace("regexp-fset") << " }" << std::endl;
- }
+ Trace("regexp-fset") << "FSET( " << mkString(r) << " ) = { ";
+ for(std::set<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ Trace("regexp-fset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";
+ }
+ Trace("regexp-fset") << " }" << std::endl;
+ }
}
bool RegExpOpr::follow( Node r, CVC4::String c, std::vector< char > &vec_chars ) {
- int k = r.getKind();
- switch( k ) {
- case kind::STRING_TO_REGEXP:
- {
- if(r[0].isConst()) {
- if(r[0] != d_emptyString) {
- char t1 = r[0].getConst< CVC4::String >().getFirstChar();
- if(c.isEmptyString()) {
- vec_chars.push_back( t1 );
- return true;
- } else {
- char t2 = c.getFirstChar();
- if(t1 != t2) {
- return false;
- } else {
- if(c.size() >= 2) {
- vec_chars.push_back( c.substr(1,1).getFirstChar() );
- } else {
- vec_chars.push_back( '\0' );
- }
- return true;
- }
- }
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- break;
- case kind::REGEXP_CONCAT:
- {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if( follow(r[i], c, vec_chars) ) {
- if(vec_chars[vec_chars.size() - 1] == '\0') {
- vec_chars.pop_back();
- c = d_emptyString.getConst< CVC4::String >();
- }
- } else {
- return false;
- }
- }
- vec_chars.push_back( '\0' );
- return true;
- }
- break;
- case kind::REGEXP_UNION:
- {
- bool flag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if( follow(r[i], c, vec_chars) ) {
- flag=true;
- }
- }
- return flag;
- }
- break;
- case kind::REGEXP_INTER:
- {
- std::vector< char > vt2;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- std::vector< char > v_tmp;
- if( !follow(r[i], c, v_tmp) ) {
- return false;
- }
- std::vector< char > vt3(vt2);
- vt2.clear();
- std::set_intersection( vt3.begin(), vt3.end(), v_tmp.begin(), v_tmp.end(), vt2.begin() );
- if(vt2.size() == 0) {
- return false;
- }
- }
- vec_chars.insert( vec_chars.end(), vt2.begin(), vt2.end() );
- return true;
- }
- break;
- case kind::REGEXP_STAR:
- {
- if(follow(r[0], c, vec_chars)) {
- if(vec_chars[vec_chars.size() - 1] == '\0') {
- if(c.isEmptyString()) {
- return true;
- } else {
- vec_chars.pop_back();
- c = d_emptyString.getConst< CVC4::String >();
- return follow(r[0], c, vec_chars);
- }
- } else {
- return true;
- }
- } else {
- vec_chars.push_back( '\0' );
- return true;
- }
- }
- break;
- default: {
- Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;
- //AlwaysAssert( false );
- //return Node::null();
- return false;
- }
- }
+ int k = r.getKind();
+ switch( k ) {
+ case kind::STRING_TO_REGEXP:
+ {
+ if(r[0].isConst()) {
+ if(r[0] != d_emptyString) {
+ char t1 = r[0].getConst< CVC4::String >().getFirstChar();
+ if(c.isEmptyString()) {
+ vec_chars.push_back( t1 );
+ return true;
+ } else {
+ char t2 = c.getFirstChar();
+ if(t1 != t2) {
+ return false;
+ } else {
+ if(c.size() >= 2) {
+ vec_chars.push_back( c.substr(1,1).getFirstChar() );
+ } else {
+ vec_chars.push_back( '\0' );
+ }
+ return true;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ break;
+ case kind::REGEXP_CONCAT:
+ {
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if( follow(r[i], c, vec_chars) ) {
+ if(vec_chars[vec_chars.size() - 1] == '\0') {
+ vec_chars.pop_back();
+ c = d_emptyString.getConst< CVC4::String >();
+ }
+ } else {
+ return false;
+ }
+ }
+ vec_chars.push_back( '\0' );
+ return true;
+ }
+ break;
+ case kind::REGEXP_UNION:
+ {
+ bool flag = false;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if( follow(r[i], c, vec_chars) ) {
+ flag=true;
+ }
+ }
+ return flag;
+ }
+ break;
+ case kind::REGEXP_INTER:
+ {
+ std::vector< char > vt2;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ std::vector< char > v_tmp;
+ if( !follow(r[i], c, v_tmp) ) {
+ return false;
+ }
+ std::vector< char > vt3(vt2);
+ vt2.clear();
+ std::set_intersection( vt3.begin(), vt3.end(), v_tmp.begin(), v_tmp.end(), vt2.begin() );
+ if(vt2.size() == 0) {
+ return false;
+ }
+ }
+ vec_chars.insert( vec_chars.end(), vt2.begin(), vt2.end() );
+ return true;
+ }
+ break;
+ case kind::REGEXP_STAR:
+ {
+ if(follow(r[0], c, vec_chars)) {
+ if(vec_chars[vec_chars.size() - 1] == '\0') {
+ if(c.isEmptyString()) {
+ return true;
+ } else {
+ vec_chars.pop_back();
+ c = d_emptyString.getConst< CVC4::String >();
+ return follow(r[0], c, vec_chars);
+ }
+ } else {
+ return true;
+ }
+ } else {
+ vec_chars.push_back( '\0' );
+ return true;
+ }
+ }
+ break;
+ default: {
+ Trace("strings-error") << "Unsupported term: " << mkString( r ) << " in delta of RegExp." << std::endl;
+ //AlwaysAssert( false );
+ //return Node::null();
+ return false;
+ }
+ }
}
Node RegExpOpr::mkAllExceptOne( char exp_c ) {
- std::vector< Node > vec_nodes;
- for(char c=d_char_start; c<=d_char_end; ++c) {
- if(c != exp_c ) {
- Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) );
- vec_nodes.push_back( n );
- }
- }
- return NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes );
+ std::vector< Node > vec_nodes;
+ for(char c=d_char_start; c<=d_char_end; ++c) {
+ if(c != exp_c ) {
+ Node n = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst( ::CVC4::String( c ) ) );
+ vec_nodes.push_back( n );
+ }
+ }
+ return NodeManager::currentNM()->mkNode( kind::REGEXP_UNION, vec_nodes );
}
//simplify
void RegExpOpr::simplify(Node t, std::vector< Node > &new_nodes, bool polarity) {
- Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl;
- Assert(t.getKind() == kind::STRING_IN_REGEXP);
- Node str = Rewriter::rewrite(t[0]);
- Node re = Rewriter::rewrite(t[1]);
- if(polarity) {
- simplifyPRegExp( str, re, new_nodes );
- } else {
- simplifyNRegExp( str, re, new_nodes );
- }
- Trace("strings-regexp-simpl") << "RegExp-Simpl returns (" << new_nodes.size() << "):\n";
- for(unsigned i=0; i<new_nodes.size(); i++) {
- Trace("strings-regexp-simpl") << "\t" << new_nodes[i] << std::endl;
- }
+ Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl;
+ Assert(t.getKind() == kind::STRING_IN_REGEXP);
+ Node str = Rewriter::rewrite(t[0]);
+ Node re = Rewriter::rewrite(t[1]);
+ if(polarity) {
+ simplifyPRegExp( str, re, new_nodes );
+ } else {
+ simplifyNRegExp( str, re, new_nodes );
+ }
+ Trace("strings-regexp-simpl") << "RegExp-Simpl returns (" << new_nodes.size() << "):\n";
+ for(unsigned i=0; i<new_nodes.size(); i++) {
+ Trace("strings-regexp-simpl") << "\t" << new_nodes[i] << std::endl;
+ }
}
void RegExpOpr::simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {
- std::pair < Node, Node > p(s, r);
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_neg_cache.find(p);
- if(itr != d_simpl_neg_cache.end()) {
- new_nodes.push_back( itr->second );
- } else {
- int k = r.getKind();
- Node conc;
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- conc = d_true;
- break;
- }
- case kind::REGEXP_SIGMA: {
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)).negate();
- break;
- }
- case kind::STRING_TO_REGEXP: {
- conc = s.eqNode(r[0]).negate();
- break;
- }
- case kind::REGEXP_CONCAT: {
- //TODO: rewrite empty
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_zero),
- NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s), b1 ) );
- Node s1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1));
- Node s2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1)));
- Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();
- if(r[0].getKind() == kind::STRING_TO_REGEXP) {
- s1r1 = s1.eqNode(r[0][0]).negate();
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- s1r1 = d_true;
- }
- Node r2 = r[1];
- if(r.getNumChildren() > 2) {
- std::vector< Node > nvec;
- for(unsigned i=1; i<r.getNumChildren(); i++) {
- nvec.push_back( r[i] );
- }
- r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, nvec);
- }
- r2 = Rewriter::rewrite(r2);
- Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r2).negate();
- if(r2.getKind() == kind::STRING_TO_REGEXP) {
- s2r2 = s2.eqNode(r2[0]).negate();
- } else if(r2.getKind() == kind::REGEXP_EMPTY) {
- s2r2 = d_true;
- }
+ std::pair < Node, Node > p(s, r);
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_neg_cache.find(p);
+ if(itr != d_simpl_neg_cache.end()) {
+ new_nodes.push_back( itr->second );
+ } else {
+ int k = r.getKind();
+ Node conc;
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ conc = d_true;
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)).negate();
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ conc = s.eqNode(r[0]).negate();
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ //TODO: rewrite empty
+ Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
+ Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
+ Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
+ Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_zero),
+ NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s), b1 ) );
+ Node s1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1));
+ Node s2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1)));
+ Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();
+ if(r[0].getKind() == kind::STRING_TO_REGEXP) {
+ s1r1 = s1.eqNode(r[0][0]).negate();
+ } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
+ s1r1 = d_true;
+ }
+ Node r2 = r[1];
+ if(r.getNumChildren() > 2) {
+ std::vector< Node > nvec;
+ for(unsigned i=1; i<r.getNumChildren(); i++) {
+ nvec.push_back( r[i] );
+ }
+ r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, nvec);
+ }
+ r2 = Rewriter::rewrite(r2);
+ Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r2).negate();
+ if(r2.getKind() == kind::STRING_TO_REGEXP) {
+ s2r2 = s2.eqNode(r2[0]).negate();
+ } else if(r2.getKind() == kind::REGEXP_EMPTY) {
+ s2r2 = d_true;
+ }
+
+ conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);
+ conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);
+ conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ std::vector< Node > c_and;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {
+ c_and.push_back( r[i][0].eqNode(s).negate() );
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
+ continue;
+ } else {
+ c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
+ }
+ }
+ conc = c_and.size() == 0 ? d_true :
+ c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ bool emptyflag = false;
+ std::vector< Node > c_or;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {
+ c_or.push_back( r[i][0].eqNode(s).negate() );
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
+ emptyflag = true;
+ break;
+ } else {
+ c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
+ }
+ }
+ if(emptyflag) {
+ conc = d_true;
+ } else {
+ conc = c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ if(s == d_emptyString) {
+ conc = d_false;
+ } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
+ conc = s.eqNode(d_emptyString).negate();
+ } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
+ conc = d_false;
+ } else {
+ Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
+ Node sne = s.eqNode(d_emptyString).negate();
+ Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
+ Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
+ Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_one),
+ NodeManager::currentNM()->mkNode( kind::GEQ, lens, b1 ) );
+ //internal
+ Node s1 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1);
+ Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1));
+ Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();
+ Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r).negate();
- conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);
- conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);
- conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > c_and;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_and.push_back( r[i][0].eqNode(s).negate() );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- continue;
- } else {
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
- }
- }
- conc = c_and.size() == 0 ? d_true :
- c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
- break;
- }
- case kind::REGEXP_INTER: {
- bool emptyflag = false;
- std::vector< Node > c_or;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_or.push_back( r[i][0].eqNode(s).negate() );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
- }
- }
- if(emptyflag) {
- conc = d_true;
- } else {
- conc = c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- if(s == d_emptyString) {
- conc = d_false;
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- conc = s.eqNode(d_emptyString).negate();
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
- conc = d_false;
- } else {
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
- Node sne = s.eqNode(d_emptyString).negate();
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_one),
- NodeManager::currentNM()->mkNode( kind::GEQ, lens, b1 ) );
- //internal
- Node s1 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, d_zero, b1);
- Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1));
- Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();
- Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r).negate();
-
- conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);
- conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);
- conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);
- conc = NodeManager::currentNM()->mkNode(kind::AND, sne, conc);
- }
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyNRegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- conc = Rewriter::rewrite( conc );
- new_nodes.push_back( conc );
- d_simpl_neg_cache[p] = conc;
- }
+ conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);
+ conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);
+ conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);
+ conc = NodeManager::currentNM()->mkNode(kind::AND, sne, conc);
+ }
+ break;
+ }
+ default: {
+ Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyNRegExp." << std::endl;
+ Assert( false, "Unsupported Term" );
+ }
+ }
+ conc = Rewriter::rewrite( conc );
+ new_nodes.push_back( conc );
+ d_simpl_neg_cache[p] = conc;
+ }
}
void RegExpOpr::simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {
- std::pair < Node, Node > p(s, r);
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_cache.find(p);
- if(itr != d_simpl_cache.end()) {
- new_nodes.push_back( itr->second );
- } else {
- int k = r.getKind();
- Node conc;
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- conc = d_false;
- break;
- }
- case kind::REGEXP_SIGMA: {
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));
- break;
- }
- case kind::STRING_TO_REGEXP: {
- conc = s.eqNode(r[0]);
- break;
- }
- case kind::REGEXP_CONCAT: {
- std::vector< Node > nvec;
- std::vector< Node > cc;
- bool emptyflag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- cc.push_back( r[i][0] );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- Node sk = NodeManager::currentNM()->mkSkolem( "rc", s.getType(), "created for regular expression concat" );
- Node lem = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk, r[i]);
- nvec.push_back(lem);
- cc.push_back(sk);
- }
- }
- if(emptyflag) {
- conc = d_false;
- } else {
- Node lem = s.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc) );
- nvec.push_back(lem);
- conc = nvec.size() == 1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);
- }
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > c_or;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_or.push_back( r[i][0].eqNode(s) );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- continue;
- } else {
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
- }
- }
- conc = c_or.size() == 0 ? d_false :
- c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
- break;
- }
- case kind::REGEXP_INTER: {
- std::vector< Node > c_and;
- bool emptyflag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_and.push_back( r[i][0].eqNode(s) );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
- }
- }
- if(emptyflag) {
- conc = d_false;
- } else {
- conc = c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- if(s == d_emptyString) {
- conc = d_true;
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- conc = s.eqNode(d_emptyString);
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
- conc = d_true;
- } else {
- Node se = s.eqNode(d_emptyString);
- Node sinr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[0]);
- Node sk1 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );
- Node s1nz = sk1.eqNode(d_emptyString).negate();
- Node s2nz = sk2.eqNode(d_emptyString).negate();
- Node s1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);
- Node s2inrs = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2, r);
- Node s12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2));
+ std::pair < Node, Node > p(s, r);
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_cache.find(p);
+ if(itr != d_simpl_cache.end()) {
+ new_nodes.push_back( itr->second );
+ } else {
+ int k = r.getKind();
+ Node conc;
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ conc = d_false;
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ conc = s.eqNode(r[0]);
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ std::vector< Node > nvec;
+ std::vector< Node > cc;
+ bool emptyflag = false;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {
+ cc.push_back( r[i][0] );
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
+ emptyflag = true;
+ break;
+ } else {
+ Node sk = NodeManager::currentNM()->mkSkolem( "rc", s.getType(), "created for regular expression concat" );
+ Node lem = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk, r[i]);
+ nvec.push_back(lem);
+ cc.push_back(sk);
+ }
+ }
+ if(emptyflag) {
+ conc = d_false;
+ } else {
+ Node lem = s.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc) );
+ nvec.push_back(lem);
+ conc = nvec.size() == 1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);
+ }
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ std::vector< Node > c_or;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {
+ c_or.push_back( r[i][0].eqNode(s) );
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
+ continue;
+ } else {
+ c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
+ }
+ }
+ conc = c_or.size() == 0 ? d_false :
+ c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ std::vector< Node > c_and;
+ bool emptyflag = false;
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(r[i].getKind() == kind::STRING_TO_REGEXP) {
+ c_and.push_back( r[i][0].eqNode(s) );
+ } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
+ emptyflag = true;
+ break;
+ } else {
+ c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
+ }
+ }
+ if(emptyflag) {
+ conc = d_false;
+ } else {
+ conc = c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ if(s == d_emptyString) {
+ conc = d_true;
+ } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
+ conc = s.eqNode(d_emptyString);
+ } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
+ conc = d_true;
+ } else {
+ Node se = s.eqNode(d_emptyString);
+ Node sinr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[0]);
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "rs", s.getType(), "created for regular expression star" );
+ Node s1nz = sk1.eqNode(d_emptyString).negate();
+ Node s2nz = sk2.eqNode(d_emptyString).negate();
+ Node s1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);
+ Node s2inrs = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2, r);
+ Node s12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2));
- conc = NodeManager::currentNM()->mkNode(kind::AND, s12, s1nz, s2nz, s1inr, s2inrs);
- conc = NodeManager::currentNM()->mkNode(kind::OR, se, sinr, conc);
- }
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyPRegExp." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- conc = Rewriter::rewrite( conc );
- new_nodes.push_back( conc );
- d_simpl_cache[p] = conc;
- }
+ conc = NodeManager::currentNM()->mkNode(kind::AND, s12, s1nz, s2nz, s1inr, s2inrs);
+ conc = NodeManager::currentNM()->mkNode(kind::OR, se, sinr, conc);
+ }
+ break;
+ }
+ default: {
+ Trace("strings-regexp") << "Unsupported term: " << r << " in simplifyPRegExp." << std::endl;
+ Assert( false, "Unsupported Term" );
+ }
+ }
+ conc = Rewriter::rewrite( conc );
+ new_nodes.push_back( conc );
+ d_simpl_cache[p] = conc;
+ }
}
void RegExpOpr::getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset ) {
- std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_cset_cache.find(r);
- if(itr != d_cset_cache.end()) {
- pcset.insert((itr->second).first.begin(), (itr->second).first.end());
- pvset.insert((itr->second).second.begin(), (itr->second).second.end());
- } else {
- std::set<unsigned> cset;
- SetNodes vset;
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- break;
- }
- case kind::REGEXP_SIGMA: {
- for(unsigned i=0; i<d_card; i++) {
- cset.insert(i);
- }
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node st = Rewriter::rewrite(r[0]);
- if(st.isConst()) {
- CVC4::String s = st.getConst< CVC4::String >();
- s.getCharSet( cset );
- } else if(st.getKind() == kind::VARIABLE) {
- vset.insert( st );
- } else {
- for(unsigned i=0; i<st.getNumChildren(); i++) {
- if(st[i].isConst()) {
- CVC4::String s = st[i].getConst< CVC4::String >();
- s.getCharSet( cset );
- } else {
- vset.insert( st[i] );
- }
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- getCharSet(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_UNION: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- getCharSet(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_INTER: {
- //TODO: Overapproximation for now
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- getCharSet(r[i], cset, vset);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- getCharSet(r[0], cset, vset);
- break;
- }
- default: {
- Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;
- Assert( false, "Unsupported Term" );
- }
- }
- pcset.insert(cset.begin(), cset.end());
- pvset.insert(vset.begin(), vset.end());
- std::pair< std::set<unsigned>, SetNodes > p(cset, vset);
- d_cset_cache[r] = p;
+ std::map< Node, std::pair< std::set<unsigned>, SetNodes > >::const_iterator itr = d_cset_cache.find(r);
+ if(itr != d_cset_cache.end()) {
+ pcset.insert((itr->second).first.begin(), (itr->second).first.end());
+ pvset.insert((itr->second).second.begin(), (itr->second).second.end());
+ } else {
+ std::set<unsigned> cset;
+ SetNodes vset;
+ int k = r.getKind();
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ for(unsigned i=0; i<d_card; i++) {
+ cset.insert(i);
+ }
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ Node st = Rewriter::rewrite(r[0]);
+ if(st.isConst()) {
+ CVC4::String s = st.getConst< CVC4::String >();
+ s.getCharSet( cset );
+ } else if(st.getKind() == kind::VARIABLE) {
+ vset.insert( st );
+ } else {
+ for(unsigned i=0; i<st.getNumChildren(); i++) {
+ if(st[i].isConst()) {
+ CVC4::String s = st[i].getConst< CVC4::String >();
+ s.getCharSet( cset );
+ } else {
+ vset.insert( st[i] );
+ }
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ for(unsigned i=0; i<r.getNumChildren(); i++) {
+ getCharSet(r[i], cset, vset);
+ }
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ for(unsigned i=0; i<r.getNumChildren(); i++) {
+ getCharSet(r[i], cset, vset);
+ }
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ //TODO: Overapproximation for now
+ for(unsigned i=0; i<r.getNumChildren(); i++) {
+ getCharSet(r[i], cset, vset);
+ }
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ getCharSet(r[0], cset, vset);
+ break;
+ }
+ default: {
+ Trace("strings-regexp") << "Unsupported term: " << r << " in getCharSet." << std::endl;
+ Assert( false, "Unsupported Term" );
+ }
+ }
+ pcset.insert(cset.begin(), cset.end());
+ pvset.insert(vset.begin(), vset.end());
+ std::pair< std::set<unsigned>, SetNodes > p(cset, vset);
+ d_cset_cache[r] = p;
- Trace("regexp-cset") << "CSET( " << mkString(r) << " ) = { ";
- for(std::set<unsigned>::const_iterator itr = cset.begin();
- itr != cset.end(); itr++) {
- Trace("regexp-cset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";
- }
- Trace("regexp-cset") << " }" << std::endl;
- }
+ Trace("regexp-cset") << "CSET( " << mkString(r) << " ) = { ";
+ for(std::set<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ Trace("regexp-cset") << CVC4::String::convertUnsignedIntToChar(*itr) << ",";
+ }
+ Trace("regexp-cset") << " }" << std::endl;
+ }
}
Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ) {
- if(spflag) {
- //TODO: var
- return Node::null();
- }
- std::pair < Node, Node > p(r1, r2);
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p);
- Node rNode;
- if(itr != d_inter_cache.end()) {
- rNode = itr->second;
- } else {
- if(r1 == r2) {
- rNode = r1;
- } else if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {
- rNode = d_emptyRegexp;
- } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {
- Node exp;
- int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);
- if(r == 0) {
- //TODO: variable
- spflag = true;
- } else if(r == 1) {
- rNode = d_emptySingleton;
- } else {
- rNode = d_emptyRegexp;
- }
- } else {
- std::set< unsigned > cset, cset2;
- std::set< Node > vset, vset2;
- getCharSet(r1, cset, vset);
- getCharSet(r2, cset2, vset2);
- if(vset.empty() && vset2.empty()) {
- cset.clear();
- firstChars(r1, cset, vset);
- std::vector< Node > vec_nodes;
- for(std::set<unsigned>::const_iterator itr = cset.begin();
- itr != cset.end(); itr++) {
- CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
- std::pair< Node, Node > p(r1, r2);
- if(cache[ *itr ].find(p) == cache[ *itr ].end()) {
- Node r1l = derivativeSingle(r1, c);
- Node r2l = derivativeSingle(r2, c);
- std::map< unsigned, std::set< PairNodes > > cache2(cache);
- PairNodes p(r1l, r2l);
- cache2[ *itr ].insert( p );
- Node rt = intersectInternal(r1l, r2l, cache2, spflag);
- if(spflag) {
- //TODO:
- return Node::null();
- }
- rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
- NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) );
- vec_nodes.push_back(rt);
- }
- }
- rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] :
- NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
- rNode = Rewriter::rewrite( rNode );
- } else {
- //TODO: non-empty var set
- spflag = true;
- }
- }
- d_inter_cache[p] = rNode;
- }
- Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
- return rNode;
+ if(spflag) {
+ //TODO: var
+ return Node::null();
+ }
+ std::pair < Node, Node > p(r1, r2);
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p);
+ Node rNode;
+ if(itr != d_inter_cache.end()) {
+ rNode = itr->second;
+ } else {
+ if(r1 == r2) {
+ rNode = r1;
+ } else if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {
+ rNode = d_emptyRegexp;
+ } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {
+ Node exp;
+ int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);
+ if(r == 0) {
+ //TODO: variable
+ spflag = true;
+ } else if(r == 1) {
+ rNode = d_emptySingleton;
+ } else {
+ rNode = d_emptyRegexp;
+ }
+ } else {
+ std::set< unsigned > cset, cset2;
+ std::set< Node > vset, vset2;
+ getCharSet(r1, cset, vset);
+ getCharSet(r2, cset2, vset2);
+ if(vset.empty() && vset2.empty()) {
+ cset.clear();
+ firstChars(r1, cset, vset);
+ std::vector< Node > vec_nodes;
+ for(std::set<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
+ std::pair< Node, Node > p(r1, r2);
+ if(cache[ *itr ].find(p) == cache[ *itr ].end()) {
+ Node r1l = derivativeSingle(r1, c);
+ Node r2l = derivativeSingle(r2, c);
+ std::map< unsigned, std::set< PairNodes > > cache2(cache);
+ PairNodes p(r1l, r2l);
+ cache2[ *itr ].insert( p );
+ Node rt = intersectInternal(r1l, r2l, cache2, spflag);
+ if(spflag) {
+ //TODO:
+ return Node::null();
+ }
+ rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
+ NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) );
+ vec_nodes.push_back(rt);
+ }
+ }
+ rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
+ rNode = Rewriter::rewrite( rNode );
+ } else {
+ //TODO: non-empty var set
+ spflag = true;
+ }
+ }
+ d_inter_cache[p] = rNode;
+ }
+ Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
+ return rNode;
}
Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) {
- std::map< unsigned, std::set< PairNodes > > cache;
- return intersectInternal(r1, r2, cache, spflag);
+ std::map< unsigned, std::set< PairNodes > > cache;
+ return intersectInternal(r1, r2, cache, spflag);
}
Node RegExpOpr::complement(Node r, int &ret) {
- Node rNode;
- ret = 1;
- if(d_compl_cache.find(r) != d_compl_cache.end()) {
- rNode = d_compl_cache[r].first;
- ret = d_compl_cache[r].second;
- } else {
- if(r == d_emptyRegexp) {
- rNode = d_sigma_star;
- } else if(r == d_emptySingleton) {
- rNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, d_sigma, d_sigma_star);
- } else if(!checkConstRegExp(r)) {
- //TODO: var to be extended
- ret = 0;
- } else {
- std::set<unsigned> cset;
- SetNodes vset;
- firstChars(r, cset, vset);
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<d_card; i++) {
- CVC4::String c = CVC4::String::convertUnsignedIntToChar(i);
- Node n = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c));
- Node r2;
- if(cset.find(i) == cset.end()) {
- r2 = d_sigma_star;
- } else {
- int rt;
- derivativeS(r, c, r2);
- if(r2 == r) {
- r2 = d_emptyRegexp;
- } else {
- r2 = complement(r2, rt);
- }
- }
- n = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, n, r2));
- vec_nodes.push_back(n);
- }
- rNode = vec_nodes.size()==0? d_emptyRegexp : vec_nodes.size()==1? vec_nodes[0] :
- NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
- }
- rNode = Rewriter::rewrite(rNode);
- std::pair< Node, int > p(rNode, ret);
- d_compl_cache[r] = p;
- }
- Trace("regexp-compl") << "COMPL( " << mkString(r) << " ) = " << mkString(rNode) << ", ret=" << ret << std::endl;
- return rNode;
+ Node rNode;
+ ret = 1;
+ if(d_compl_cache.find(r) != d_compl_cache.end()) {
+ rNode = d_compl_cache[r].first;
+ ret = d_compl_cache[r].second;
+ } else {
+ if(r == d_emptyRegexp) {
+ rNode = d_sigma_star;
+ } else if(r == d_emptySingleton) {
+ rNode = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, d_sigma, d_sigma_star);
+ } else if(!checkConstRegExp(r)) {
+ //TODO: var to be extended
+ ret = 0;
+ } else {
+ std::set<unsigned> cset;
+ SetNodes vset;
+ firstChars(r, cset, vset);
+ std::vector< Node > vec_nodes;
+ for(unsigned i=0; i<d_card; i++) {
+ CVC4::String c = CVC4::String::convertUnsignedIntToChar(i);
+ Node n = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c));
+ Node r2;
+ if(cset.find(i) == cset.end()) {
+ r2 = d_sigma_star;
+ } else {
+ int rt;
+ derivativeS(r, c, r2);
+ if(r2 == r) {
+ r2 = d_emptyRegexp;
+ } else {
+ r2 = complement(r2, rt);
+ }
+ }
+ n = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, n, r2));
+ vec_nodes.push_back(n);
+ }
+ rNode = vec_nodes.size()==0? d_emptyRegexp : vec_nodes.size()==1? vec_nodes[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
+ }
+ rNode = Rewriter::rewrite(rNode);
+ std::pair< Node, int > p(rNode, ret);
+ d_compl_cache[r] = p;
+ }
+ Trace("regexp-compl") << "COMPL( " << mkString(r) << " ) = " << mkString(rNode) << ", ret=" << ret << std::endl;
+ return rNode;
}
void RegExpOpr::splitRegExp(Node r, std::vector< PairNodes > &pset) {
- Assert(checkConstRegExp(r));
- if(d_split_cache.find(r) != d_split_cache.end()) {
- pset = d_split_cache[r];
- } else {
- switch( r.getKind() ) {
- case kind::REGEXP_EMPTY: {
- break;
- }
- case kind::REGEXP_OPT: {
- PairNodes tmp(d_emptySingleton, d_emptySingleton);
- pset.push_back(tmp);
- }
- case kind::REGEXP_RANGE:
- case kind::REGEXP_SIGMA: {
- PairNodes tmp1(d_emptySingleton, r);
- PairNodes tmp2(r, d_emptySingleton);
- pset.push_back(tmp1);
- pset.push_back(tmp2);
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Assert(r[0].isConst());
- CVC4::String s = r[0].getConst< CVC4::String >();
- PairNodes tmp1(d_emptySingleton, r);
- pset.push_back(tmp1);
- for(unsigned i=1; i<s.size(); i++) {
- CVC4::String s1 = s.substr(0, i);
- CVC4::String s2 = s.substr(i);
- Node n1 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s1));
- Node n2 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s2));
- PairNodes tmp3(n1, n2);
- pset.push_back(tmp3);
- }
- PairNodes tmp2(r, d_emptySingleton);
- pset.push_back(tmp2);
- break;
- }
- case kind::REGEXP_CONCAT: {
- for(unsigned i=0; i<r.getNumChildren(); i++) {
- std::vector< PairNodes > tset;
- splitRegExp(r[i], tset);
- std::vector< Node > hvec;
- std::vector< Node > tvec;
- for(unsigned j=0; j<=i; j++) {
- hvec.push_back(r[j]);
- }
- for(unsigned j=i; j<r.getNumChildren(); j++) {
- tvec.push_back(r[j]);
- }
- for(unsigned j=0; j<tset.size(); j++) {
- hvec[i] = tset[j].first;
- tvec[0] = tset[j].second;
- Node r1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, hvec) );
- Node r2 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tvec) );
- PairNodes tmp2(r1, r2);
- pset.push_back(tmp2);
- }
- }
- break;
- }
- case kind::REGEXP_UNION: {
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- std::vector< PairNodes > tset;
- splitRegExp(r[i], tset);
- pset.insert(pset.end(), tset.begin(), tset.end());
- }
- break;
- }
- case kind::REGEXP_INTER: {
- bool spflag = false;
- Node tmp = r[0];
- for(unsigned i=1; i<r.getNumChildren(); i++) {
- tmp = intersect(tmp, r[i], spflag);
- }
- splitRegExp(tmp, pset);
- break;
- }
- case kind::REGEXP_STAR: {
- std::vector< PairNodes > tset;
- splitRegExp(r[0], tset);
- PairNodes tmp1(d_emptySingleton, d_emptySingleton);
- pset.push_back(tmp1);
- for(unsigned i=0; i<tset.size(); i++) {
- Node r1 = tset[i].first==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);
- Node r2 = tset[i].second==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);
- PairNodes tmp2(r1, r2);
- pset.push_back(tmp2);
- }
- break;
- }
- case kind::REGEXP_PLUS: {
- std::vector< PairNodes > tset;
- splitRegExp(r[0], tset);
- for(unsigned i=0; i<tset.size(); i++) {
- Node r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);
- Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);
- PairNodes tmp2(r1, r2);
- pset.push_back(tmp2);
- }
- break;
- }
- default: {
- Trace("strings-error") << "Unsupported term: " << r << " in splitRegExp." << std::endl;
- Assert( false );
- //return Node::null();
- }
- }
- d_split_cache[r] = pset;
- }
+ Assert(checkConstRegExp(r));
+ if(d_split_cache.find(r) != d_split_cache.end()) {
+ pset = d_split_cache[r];
+ } else {
+ switch( r.getKind() ) {
+ case kind::REGEXP_EMPTY: {
+ break;
+ }
+ case kind::REGEXP_OPT: {
+ PairNodes tmp(d_emptySingleton, d_emptySingleton);
+ pset.push_back(tmp);
+ }
+ case kind::REGEXP_RANGE:
+ case kind::REGEXP_SIGMA: {
+ PairNodes tmp1(d_emptySingleton, r);
+ PairNodes tmp2(r, d_emptySingleton);
+ pset.push_back(tmp1);
+ pset.push_back(tmp2);
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ Assert(r[0].isConst());
+ CVC4::String s = r[0].getConst< CVC4::String >();
+ PairNodes tmp1(d_emptySingleton, r);
+ pset.push_back(tmp1);
+ for(unsigned i=1; i<s.size(); i++) {
+ CVC4::String s1 = s.substr(0, i);
+ CVC4::String s2 = s.substr(i);
+ Node n1 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s1));
+ Node n2 = NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(s2));
+ PairNodes tmp3(n1, n2);
+ pset.push_back(tmp3);
+ }
+ PairNodes tmp2(r, d_emptySingleton);
+ pset.push_back(tmp2);
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ for(unsigned i=0; i<r.getNumChildren(); i++) {
+ std::vector< PairNodes > tset;
+ splitRegExp(r[i], tset);
+ std::vector< Node > hvec;
+ std::vector< Node > tvec;
+ for(unsigned j=0; j<=i; j++) {
+ hvec.push_back(r[j]);
+ }
+ for(unsigned j=i; j<r.getNumChildren(); j++) {
+ tvec.push_back(r[j]);
+ }
+ for(unsigned j=0; j<tset.size(); j++) {
+ hvec[i] = tset[j].first;
+ tvec[0] = tset[j].second;
+ Node r1 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, hvec) );
+ Node r2 = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tvec) );
+ PairNodes tmp2(r1, r2);
+ pset.push_back(tmp2);
+ }
+ }
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ std::vector< PairNodes > tset;
+ splitRegExp(r[i], tset);
+ pset.insert(pset.end(), tset.begin(), tset.end());
+ }
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ bool spflag = false;
+ Node tmp = r[0];
+ for(unsigned i=1; i<r.getNumChildren(); i++) {
+ tmp = intersect(tmp, r[i], spflag);
+ }
+ splitRegExp(tmp, pset);
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ std::vector< PairNodes > tset;
+ splitRegExp(r[0], tset);
+ PairNodes tmp1(d_emptySingleton, d_emptySingleton);
+ pset.push_back(tmp1);
+ for(unsigned i=0; i<tset.size(); i++) {
+ Node r1 = tset[i].first==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);
+ Node r2 = tset[i].second==d_emptySingleton ? r : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);
+ PairNodes tmp2(r1, r2);
+ pset.push_back(tmp2);
+ }
+ break;
+ }
+ case kind::REGEXP_PLUS: {
+ std::vector< PairNodes > tset;
+ splitRegExp(r[0], tset);
+ for(unsigned i=0; i<tset.size(); i++) {
+ Node r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, r, tset[i].first);
+ Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, tset[i].second, r);
+ PairNodes tmp2(r1, r2);
+ pset.push_back(tmp2);
+ }
+ break;
+ }
+ default: {
+ Trace("strings-error") << "Unsupported term: " << r << " in splitRegExp." << std::endl;
+ Assert( false );
+ //return Node::null();
+ }
+ }
+ d_split_cache[r] = pset;
+ }
}
//printing
std::string RegExpOpr::niceChar( Node r ) {
- if(r.isConst()) {
- std::string s = r.getConst<CVC4::String>().toString() ;
- return s == "" ? "{E}" : ( s == " " ? "{ }" : s.size()>1? "("+s+")" : s );
- } else {
- std::string ss = "$" + r.toString();
- return ss;
- }
+ if(r.isConst()) {
+ std::string s = r.getConst<CVC4::String>().toString() ;
+ return s == "" ? "{E}" : ( s == " " ? "{ }" : s.size()>1? "("+s+")" : s );
+ } else {
+ std::string ss = "$" + r.toString();
+ return ss;
+ }
}
std::string RegExpOpr::mkString( Node r ) {
- std::string retStr;
- if(r.isNull()) {
- retStr = "Empty";
- } else {
- int k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- retStr += "Empty";
- break;
- }
- case kind::REGEXP_SIGMA: {
- retStr += "{W}";
- break;
- }
- case kind::STRING_TO_REGEXP: {
- retStr += niceChar( r[0] );
- break;
- }
- case kind::REGEXP_CONCAT: {
- retStr += "(";
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- //if(i != 0) retStr += ".";
- retStr += mkString( r[i] );
- }
- retStr += ")";
- break;
- }
- case kind::REGEXP_UNION: {
- if(r == d_sigma) {
- retStr += "{A}";
- } else {
- retStr += "(";
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(i != 0) retStr += "|";
- retStr += mkString( r[i] );
- }
- retStr += ")";
- }
- break;
- }
- case kind::REGEXP_INTER: {
- retStr += "(";
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(i != 0) retStr += "&";
- retStr += mkString( r[i] );
- }
- retStr += ")";
- break;
- }
- case kind::REGEXP_STAR: {
- retStr += mkString( r[0] );
- retStr += "*";
- break;
- }
- case kind::REGEXP_PLUS: {
- retStr += mkString( r[0] );
- retStr += "+";
- break;
- }
- case kind::REGEXP_OPT: {
- retStr += mkString( r[0] );
- retStr += "?";
- break;
- }
- case kind::REGEXP_RANGE: {
- retStr += "[";
- retStr += niceChar( r[0] );
- retStr += "-";
- retStr += niceChar( r[1] );
- retStr += "]";
- break;
- }
- default:
- Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl;
- //Assert( false );
- //return Node::null();
- }
- }
+ std::string retStr;
+ if(r.isNull()) {
+ retStr = "Empty";
+ } else {
+ int k = r.getKind();
+ switch( k ) {
+ case kind::REGEXP_EMPTY: {
+ retStr += "Empty";
+ break;
+ }
+ case kind::REGEXP_SIGMA: {
+ retStr += "{W}";
+ break;
+ }
+ case kind::STRING_TO_REGEXP: {
+ retStr += niceChar( r[0] );
+ break;
+ }
+ case kind::REGEXP_CONCAT: {
+ retStr += "(";
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ //if(i != 0) retStr += ".";
+ retStr += mkString( r[i] );
+ }
+ retStr += ")";
+ break;
+ }
+ case kind::REGEXP_UNION: {
+ if(r == d_sigma) {
+ retStr += "{A}";
+ } else {
+ retStr += "(";
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(i != 0) retStr += "|";
+ retStr += mkString( r[i] );
+ }
+ retStr += ")";
+ }
+ break;
+ }
+ case kind::REGEXP_INTER: {
+ retStr += "(";
+ for(unsigned i=0; i<r.getNumChildren(); ++i) {
+ if(i != 0) retStr += "&";
+ retStr += mkString( r[i] );
+ }
+ retStr += ")";
+ break;
+ }
+ case kind::REGEXP_STAR: {
+ retStr += mkString( r[0] );
+ retStr += "*";
+ break;
+ }
+ case kind::REGEXP_PLUS: {
+ retStr += mkString( r[0] );
+ retStr += "+";
+ break;
+ }
+ case kind::REGEXP_OPT: {
+ retStr += mkString( r[0] );
+ retStr += "?";
+ break;
+ }
+ case kind::REGEXP_RANGE: {
+ retStr += "[";
+ retStr += niceChar( r[0] );
+ retStr += "-";
+ retStr += niceChar( r[1] );
+ retStr += "]";
+ break;
+ }
+ default:
+ Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl;
+ //Assert( false );
+ //return Node::null();
+ }
+ }
- return retStr;
+ return retStr;
}
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h index 0513eeef4..d5606627f 100644 --- a/src/theory/strings/regexp_operation.h +++ b/src/theory/strings/regexp_operation.h @@ -33,64 +33,64 @@ namespace theory { namespace strings {
class RegExpOpr {
- typedef std::pair< Node, CVC4::String > PairNodeStr;
- typedef std::set< Node > SetNodes;
- typedef std::pair< Node, Node > PairNodes;
+ typedef std::pair< Node, CVC4::String > PairNodeStr;
+ typedef std::set< Node > SetNodes;
+ typedef std::pair< Node, Node > PairNodes;
private:
- unsigned d_card;
+ unsigned d_card;
Node d_emptyString;
Node d_true;
Node d_false;
- Node d_emptySingleton;
- Node d_emptyRegexp;
- Node d_zero;
- Node d_one;
+ Node d_emptySingleton;
+ Node d_emptyRegexp;
+ Node d_zero;
+ Node d_one;
- char d_char_start;
- char d_char_end;
- Node d_sigma;
- Node d_sigma_star;
-
- std::map< PairNodes, Node > d_simpl_cache;
- std::map< PairNodes, Node > d_simpl_neg_cache;
- std::map< Node, std::pair< int, Node > > d_delta_cache;
- std::map< PairNodeStr, Node > d_dv_cache;
- std::map< PairNodeStr, std::pair< Node, int > > d_deriv_cache;
- std::map< Node, std::pair< Node, int > > d_compl_cache;
- std::map< Node, bool > d_cstre_cache;
- std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_cset_cache;
- std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_fset_cache;
- std::map< PairNodes, Node > d_inter_cache;
- std::map< Node, std::vector< PairNodes > > d_split_cache;
- //bool checkStarPlus( Node t );
- void simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes );
- void simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes );
- std::string niceChar( Node r );
- int gcd ( int a, int b );
- Node mkAllExceptOne( char c );
+ char d_char_start;
+ char d_char_end;
+ Node d_sigma;
+ Node d_sigma_star;
- void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
- Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag );
- void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
+ std::map< PairNodes, Node > d_simpl_cache;
+ std::map< PairNodes, Node > d_simpl_neg_cache;
+ std::map< Node, std::pair< int, Node > > d_delta_cache;
+ std::map< PairNodeStr, Node > d_dv_cache;
+ std::map< PairNodeStr, std::pair< Node, int > > d_deriv_cache;
+ std::map< Node, std::pair< Node, int > > d_compl_cache;
+ std::map< Node, bool > d_cstre_cache;
+ std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_cset_cache;
+ std::map< Node, std::pair< std::set<unsigned>, std::set<Node> > > d_fset_cache;
+ std::map< PairNodes, Node > d_inter_cache;
+ std::map< Node, std::vector< PairNodes > > d_split_cache;
+ //bool checkStarPlus( Node t );
+ void simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes );
+ void simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes );
+ std::string niceChar( Node r );
+ int gcd ( int a, int b );
+ Node mkAllExceptOne( char c );
- //TODO: for intersection
- bool follow( Node r, CVC4::String c, std::vector< char > &vec_chars );
+ void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
+ Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag );
+ void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
+
+ //TODO: for intersection
+ bool follow( Node r, CVC4::String c, std::vector< char > &vec_chars );
public:
- RegExpOpr();
+ RegExpOpr();
- bool checkConstRegExp( Node r );
+ bool checkConstRegExp( Node r );
void simplify(Node t, std::vector< Node > &new_nodes, bool polarity);
- int delta( Node r, Node &exp );
- int derivativeS( Node r, CVC4::String c, Node &retNode );
- Node derivativeSingle( Node r, CVC4::String c );
- bool guessLength( Node r, int &co );
- Node intersect(Node r1, Node r2, bool &spflag);
- Node complement(Node r, int &ret);
- void splitRegExp(Node r, std::vector< PairNodes > &pset);
+ int delta( Node r, Node &exp );
+ int derivativeS( Node r, CVC4::String c, Node &retNode );
+ Node derivativeSingle( Node r, CVC4::String c );
+ bool guessLength( Node r, int &co );
+ Node intersect(Node r1, Node r2, bool &spflag);
+ Node complement(Node r, int &ret);
+ void splitRegExp(Node r, std::vector< PairNodes > &pset);
- std::string mkString( Node r );
+ std::string mkString( Node r );
};
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 61d60d4cd..0c20b12cd 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -41,28 +41,28 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, Outpu 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); @@ -93,11 +93,11 @@ TheoryStrings::~TheoryStrings() { } 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 ){ @@ -115,52 +115,52 @@ bool TheoryStrings::areEqual( Node a, Node b ){ } 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) { @@ -227,7 +227,7 @@ void TheoryStrings::explain(TNode literal, std::vector<TNode>& assumptions){ } 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; } } @@ -249,8 +249,8 @@ Node TheoryStrings::explain( TNode literal ){ 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(); } @@ -260,148 +260,148 @@ void TheoryStrings::presolve() { 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; } ///////////////////////////////////////////////////////////////////////////// @@ -421,7 +421,7 @@ void TheoryStrings::preRegisterTerm(TNode n) { 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); @@ -433,7 +433,7 @@ void TheoryStrings::preRegisterTerm(TNode n) { 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; @@ -536,13 +536,13 @@ void TheoryStrings::check(Effort e) { 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; @@ -556,21 +556,21 @@ void TheoryStrings::check(Effort e) { 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(); @@ -578,28 +578,28 @@ void TheoryStrings::check(Effort e) { 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; @@ -630,16 +630,16 @@ TheoryStrings::EqcInfo * TheoryStrings::getOrMakeEqcInfo( Node eqc, bool doMake /** 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 ); } } @@ -747,14 +747,14 @@ void TheoryStrings::doPendingFacts() { } 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(); @@ -762,125 +762,125 @@ void TheoryStrings::doPendingLemmas() { 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() ) { @@ -913,57 +913,57 @@ bool TheoryStrings::getNormalForms(Node &eqc, std::vector< Node > & visited, std //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, @@ -971,492 +971,492 @@ 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; } @@ -1539,188 +1539,188 @@ bool TheoryStrings::normalizeEquivalenceClass( Node eqc, std::vector< Node > & v //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() ){ @@ -1735,12 +1735,12 @@ void TheoryStrings::addNormalFormPair( Node n1, Node n2 ) { } 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? @@ -1763,56 +1763,56 @@ bool TheoryStrings::isNormalFormPair2( Node n1, Node n2 ) { } 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 ) { @@ -1859,30 +1859,30 @@ 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() { @@ -1916,7 +1916,7 @@ 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; @@ -1951,10 +1951,10 @@ bool TheoryStrings::checkSimple() { 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) { @@ -1975,24 +1975,24 @@ bool TheoryStrings::checkNormalForms() { } } ++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; @@ -2001,12 +2001,12 @@ bool TheoryStrings::checkNormalForms() { 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 { @@ -2061,11 +2061,11 @@ bool TheoryStrings::checkNormalForms() { 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 ); @@ -2085,75 +2085,75 @@ bool TheoryStrings::checkNormalForms() { 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() { @@ -2246,46 +2246,46 @@ void TheoryStrings::getEquivalenceClasses( std::vector< Node >& eqcs ) { } 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; @@ -2318,107 +2318,107 @@ void TheoryStrings::separateByLength(std::vector< Node >& n, } 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; @@ -2602,7 +2602,7 @@ bool TheoryStrings::checkMemberships() { 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), @@ -2638,518 +2638,518 @@ bool TheoryStrings::checkMemberships() { 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 diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h index f4a17fa46..f41b534b7 100644 --- a/src/theory/strings/theory_strings.h +++ b/src/theory/strings/theory_strings.h @@ -37,104 +37,104 @@ namespace strings { */ 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 */ @@ -143,202 +143,202 @@ private: 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 */ diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp index c1f2c3a9c..54156c85d 100644 --- a/src/theory/strings/theory_strings_preprocess.cpp +++ b/src/theory/strings/theory_strings_preprocess.cpp @@ -25,116 +25,116 @@ namespace theory { 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); @@ -142,392 +142,392 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) { 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) { @@ -536,41 +536,41 @@ 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 */ diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h index 6d0af4d1b..e6910373f 100644 --- a/src/theory/strings/theory_strings_preprocess.h +++ b/src/theory/strings/theory_strings_preprocess.h @@ -29,20 +29,20 @@ namespace theory { 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 */ diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp index 97d814a81..c226afa7d 100644 --- a/src/theory/strings/theory_strings_rewriter.cpp +++ b/src/theory/strings/theory_strings_rewriter.cpp @@ -31,10 +31,10 @@ Node TheoryStringsRewriter::rewriteConcatString( TNode node ) { 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>() ) ); @@ -71,14 +71,14 @@ Node TheoryStringsRewriter::rewriteConcatString( TNode node ) { } } } - 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; } @@ -91,7 +91,7 @@ Node TheoryStringsRewriter::prerewriteConcatRegExp( TNode node ) { 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]); @@ -126,7 +126,7 @@ Node TheoryStringsRewriter::prerewriteConcatRegExp( TNode node ) { } 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(); @@ -138,189 +138,189 @@ Node TheoryStringsRewriter::prerewriteConcatRegExp( TNode node ) { 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); @@ -370,182 +370,182 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode 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); @@ -553,7 +553,7 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) { 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) { @@ -561,67 +561,67 @@ RewriteResponse TheoryStringsRewriter::preRewrite(TNode node) { } 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); diff --git a/src/theory/strings/type_enumerator.h b/src/theory/strings/type_enumerator.h index 1a101fa70..f011e4c7d 100644 --- a/src/theory/strings/type_enumerator.h +++ b/src/theory/strings/type_enumerator.h @@ -31,13 +31,13 @@ namespace theory { 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) : @@ -51,23 +51,23 @@ public: 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; } @@ -80,19 +80,19 @@ public: 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() { @@ -109,7 +109,7 @@ public: d_data[i] = 0; } } - + if(!changed) { d_curr = Node::null(); }else{ diff --git a/src/util/regexp.cpp b/src/util/regexp.cpp index 3e2fa948c..c0e2947cb 100644 --- a/src/util/regexp.cpp +++ b/src/util/regexp.cpp @@ -27,122 +27,122 @@ void String::toInternal(const std::string &s) { d_str.clear();
unsigned i=0;
while(i < s.size()) {
- if(s[i] == '\\') {
- i++;
- if(i < s.size()) {
- switch(s[i]) {
- case 'n': {d_str.push_back( convertCharToUnsignedInt('\n') );i++;} break;
- case 't': {d_str.push_back( convertCharToUnsignedInt('\t') );i++;} break;
- case 'v': {d_str.push_back( convertCharToUnsignedInt('\v') );i++;} break;
- case 'b': {d_str.push_back( convertCharToUnsignedInt('\b') );i++;} break;
- case 'r': {d_str.push_back( convertCharToUnsignedInt('\r') );i++;} break;
- case 'f': {d_str.push_back( convertCharToUnsignedInt('\f') );i++;} break;
- case 'a': {d_str.push_back( convertCharToUnsignedInt('\a') );i++;} break;
- case '\\': {d_str.push_back( convertCharToUnsignedInt('\\') );i++;} break;
- case 'x': {
- if(i + 2 < s.size()) {
- if((isdigit(s[i+1]) || (s[i+1] >= 'a' && s[i+1] >= 'f') || (s[i+1] >= 'A' && s[i+1] >= 'F')) &&
- (isdigit(s[i+2]) || (s[i+2] >= 'a' && s[i+2] >= 'f') || (s[i+2] >= 'A' && s[i+2] >= 'F'))) {
- d_str.push_back( convertCharToUnsignedInt( hexToDec(s[i+1]) * 16 + hexToDec(s[i+2]) ) );
- i += 3;
- } else {
- throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );
- }
- } else {
- throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );
- }
- }
- break;
- default: {
- if(isdigit(s[i])) {
- int num = (int)s[i] - (int)'0';
- bool flag = num < 4;
- if(i+1 < s.size() && num < 8 && isdigit(s[i+1]) && s[i+1] < '8') {
- num = num * 8 + (int)s[i+1] - (int)'0';
- if(flag && i+2 < s.size() && isdigit(s[i+2]) && s[i+2] < '8') {
- num = num * 8 + (int)s[i+2] - (int)'0';
- d_str.push_back( convertCharToUnsignedInt((char)num) );
- i += 3;
- } else {
- d_str.push_back( convertCharToUnsignedInt((char)num) );
- i += 2;
- }
- } else {
- d_str.push_back( convertCharToUnsignedInt((char)num) );
- i++;
- }
- } else {
- d_str.push_back( convertCharToUnsignedInt(s[i]) );
- i++;
- }
- }
- }
- } else {
- throw CVC4::Exception( "should be handled by lexer: \"" + s + "\"" );
- //d_str.push_back( convertCharToUnsignedInt('\\') );
- }
- } else {
- d_str.push_back( convertCharToUnsignedInt(s[i]) );
- i++;
- }
+ if(s[i] == '\\') {
+ i++;
+ if(i < s.size()) {
+ switch(s[i]) {
+ case 'n': {d_str.push_back( convertCharToUnsignedInt('\n') );i++;} break;
+ case 't': {d_str.push_back( convertCharToUnsignedInt('\t') );i++;} break;
+ case 'v': {d_str.push_back( convertCharToUnsignedInt('\v') );i++;} break;
+ case 'b': {d_str.push_back( convertCharToUnsignedInt('\b') );i++;} break;
+ case 'r': {d_str.push_back( convertCharToUnsignedInt('\r') );i++;} break;
+ case 'f': {d_str.push_back( convertCharToUnsignedInt('\f') );i++;} break;
+ case 'a': {d_str.push_back( convertCharToUnsignedInt('\a') );i++;} break;
+ case '\\': {d_str.push_back( convertCharToUnsignedInt('\\') );i++;} break;
+ case 'x': {
+ if(i + 2 < s.size()) {
+ if((isdigit(s[i+1]) || (s[i+1] >= 'a' && s[i+1] >= 'f') || (s[i+1] >= 'A' && s[i+1] >= 'F')) &&
+ (isdigit(s[i+2]) || (s[i+2] >= 'a' && s[i+2] >= 'f') || (s[i+2] >= 'A' && s[i+2] >= 'F'))) {
+ d_str.push_back( convertCharToUnsignedInt( hexToDec(s[i+1]) * 16 + hexToDec(s[i+2]) ) );
+ i += 3;
+ } else {
+ throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );
+ }
+ } else {
+ throw CVC4::Exception( "Error String Literal: \"" + s + "\"" );
+ }
+ }
+ break;
+ default: {
+ if(isdigit(s[i])) {
+ int num = (int)s[i] - (int)'0';
+ bool flag = num < 4;
+ if(i+1 < s.size() && num < 8 && isdigit(s[i+1]) && s[i+1] < '8') {
+ num = num * 8 + (int)s[i+1] - (int)'0';
+ if(flag && i+2 < s.size() && isdigit(s[i+2]) && s[i+2] < '8') {
+ num = num * 8 + (int)s[i+2] - (int)'0';
+ d_str.push_back( convertCharToUnsignedInt((char)num) );
+ i += 3;
+ } else {
+ d_str.push_back( convertCharToUnsignedInt((char)num) );
+ i += 2;
+ }
+ } else {
+ d_str.push_back( convertCharToUnsignedInt((char)num) );
+ i++;
+ }
+ } else {
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );
+ i++;
+ }
+ }
+ }
+ } else {
+ throw CVC4::Exception( "should be handled by lexer: \"" + s + "\"" );
+ //d_str.push_back( convertCharToUnsignedInt('\\') );
+ }
+ } else {
+ d_str.push_back( convertCharToUnsignedInt(s[i]) );
+ i++;
+ }
}
}
void String::getCharSet(std::set<unsigned int> &cset) const {
- for(std::vector<unsigned int>::const_iterator itr = d_str.begin();
- itr != d_str.end(); itr++) {
- cset.insert( *itr );
- }
+ for(std::vector<unsigned int>::const_iterator itr = d_str.begin();
+ itr != d_str.end(); itr++) {
+ cset.insert( *itr );
+ }
}
bool String::overlap(String &y) const {
- unsigned n = d_str.size() < y.size() ? d_str.size() : y.size();
- for(unsigned i=1; i<n; i++) {
- String s = suffix(i);
- String p = y.prefix(i);
- if(s == p) {
- return true;
- }
- }
- return false;
+ unsigned n = d_str.size() < y.size() ? d_str.size() : y.size();
+ for(unsigned i=1; i<n; i++) {
+ String s = suffix(i);
+ String p = y.prefix(i);
+ if(s == p) {
+ return true;
+ }
+ }
+ return false;
}
std::string String::toString() const {
- std::string str;
- for(unsigned int i=0; i<d_str.size(); ++i) {
- char c = convertUnsignedIntToChar( d_str[i] );
- if(isprint( c )) {
- if(c == '\\') {
- str += "\\\\";
- } else if(c == '\"') {
- str += "\\\"";
- } else {
- str += c;
- }
- } else {
- std::string s;
- switch(c) {
- case '\a': s = "\\a"; break;
- case '\b': s = "\\b"; break;
- case '\t': s = "\\t"; break;
- case '\r': s = "\\r"; break;
- case '\v': s = "\\v"; break;
- case '\f': s = "\\f"; break;
- case '\n': s = "\\n"; break;
- case '\e': s = "\\e"; break;
- default : {
- std::stringstream ss;
- ss << std::setfill ('0') << std::setw(2) << std::hex << ((int)c);
- std::string t = ss.str();
- t = t.substr(t.size()-2, 2);
- s = "\\x" + t;
- //std::string s2 = static_cast<std::ostringstream*>( &(std::ostringstream() << (int)c) )->str();
- }
- }
- str += s;
- }
- }
- return str;
+ std::string str;
+ for(unsigned int i=0; i<d_str.size(); ++i) {
+ char c = convertUnsignedIntToChar( d_str[i] );
+ if(isprint( c )) {
+ if(c == '\\') {
+ str += "\\\\";
+ } else if(c == '\"') {
+ str += "\\\"";
+ } else {
+ str += c;
+ }
+ } else {
+ std::string s;
+ switch(c) {
+ case '\a': s = "\\a"; break;
+ case '\b': s = "\\b"; break;
+ case '\t': s = "\\t"; break;
+ case '\r': s = "\\r"; break;
+ case '\v': s = "\\v"; break;
+ case '\f': s = "\\f"; break;
+ case '\n': s = "\\n"; break;
+ case '\e': s = "\\e"; break;
+ default : {
+ std::stringstream ss;
+ ss << std::setfill ('0') << std::setw(2) << std::hex << ((int)c);
+ std::string t = ss.str();
+ t = t.substr(t.size()-2, 2);
+ s = "\\x" + t;
+ //std::string s2 = static_cast<std::ostringstream*>( &(std::ostringstream() << (int)c) )->str();
+ }
+ }
+ str += s;
+ }
+ }
+ return str;
}
std::ostream& operator <<(std::ostream& os, const String& s) {
diff --git a/src/util/regexp.h b/src/util/regexp.h index 1ae01343d..b7eea929d 100644 --- a/src/util/regexp.h +++ b/src/util/regexp.h @@ -61,13 +61,13 @@ private: //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); @@ -164,11 +164,11 @@ public: } 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]; } /* @@ -185,54 +185,54 @@ public: } 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); @@ -255,34 +255,34 @@ public: } 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 */ |