From ea6a5a6dc37139837af6751674b8f294c038d00c Mon Sep 17 00:00:00 2001 From: Tianyi Liang Date: Tue, 29 Apr 2014 16:54:26 -0500 Subject: [PATCH] fix a typo: --string-exp => --strings-exp; fix a signed int warning in antlr --- src/parser/antlr_input.cpp | 8 +- src/theory/strings/regexp_operation.cpp | 2852 +++++++------ src/theory/strings/regexp_operation.h | 90 +- src/theory/strings/theory_strings.cpp | 3622 ++++++++--------- src/theory/strings/theory_strings.h | 476 +-- .../strings/theory_strings_preprocess.cpp | 956 ++--- .../strings/theory_strings_preprocess.h | 20 +- .../strings/theory_strings_rewriter.cpp | 812 ++-- src/theory/strings/type_enumerator.h | 68 +- src/util/regexp.cpp | 212 +- 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 vec_nodes; - for(unsigned i=0; imkNode(kind::AND, vec_nodes); - } - } - break; - } - case kind::REGEXP_UNION: { - bool flag = false; - std::vector< Node > vec_nodes; - for(unsigned i=0; imkNode(kind::OR, vec_nodes); - } - } - break; - } - case kind::REGEXP_INTER: { - bool flag = false; - std::vector< Node > vec_nodes; - for(unsigned i=0; imkNode(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; imkNode(kind::AND, vec_nodes); + } + } + break; + } + case kind::REGEXP_UNION: { + bool flag = false; + std::vector< Node > vec_nodes; + for(unsigned i=0; imkNode(kind::OR, vec_nodes); + } + } + break; + } + case kind::REGEXP_INTER: { + bool flag = false; + std::vector< Node > vec_nodes; + for(unsigned i=0; imkNode(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; imkNode(kind::REGEXP_CONCAT, vec_nodes); - ret = 1; - } else { - ret = 2; - } - } else { - tmp = tmp[0]; - std::vector< Node > vec_nodes; - for(unsigned i=1; imkNode(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 vec_nodes2; - if(dc != d_emptySingleton) { - vec_nodes2.push_back( dc ); - } - for(unsigned j=i+1; jmkNode( 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; imkNode( 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; imkNode( 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; imkNode(kind::REGEXP_CONCAT, vec_nodes); + ret = 1; + } else { + ret = 2; + } + } else { + tmp = tmp[0]; + std::vector< Node > vec_nodes; + for(unsigned i=1; imkNode(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 vec_nodes2; + if(dc != d_emptySingleton) { + vec_nodes2.push_back( dc ); + } + for(unsigned j=i+1; jmkNode( 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; imkNode( 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; imkNode( 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 vec_nodes2; - if(dc != rees) { - vec_nodes2.push_back( dc ); - } - for(unsigned j=i+1; jmkNode( 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; imkNode( 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; imkNode( 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 vec_nodes2; + if(dc != rees) { + vec_nodes2.push_back( dc ); + } + for(unsigned j=i+1; jmkNode( 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; imkNode( 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; imkNode( 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().size(); + return true; + } else { + return false; + } + } + break; + case kind::REGEXP_CONCAT: + { + for(unsigned i=0; i &pcset, SetNodes &pvset ) { - std::map< Node, std::pair< std::set, 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 cset; - SetNodes vset; - int k = r.getKind(); - switch( k ) { - case kind::REGEXP_EMPTY: { - break; - } - case kind::REGEXP_SIGMA: { - for(unsigned i=0; i(); - 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, SetNodes > p(cset, vset); - d_fset_cache[r] = p; + std::map< Node, std::pair< std::set, 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 cset; + SetNodes vset; + int k = r.getKind(); + switch( k ) { + case kind::REGEXP_EMPTY: { + break; + } + case kind::REGEXP_SIGMA: { + for(unsigned i=0; i(); + 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, SetNodes > p(cset, vset); + d_fset_cache[r] = p; - Trace("regexp-fset") << "FSET( " << mkString(r) << " ) = { "; - for(std::set::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::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(); - } - } else { - return false; - } - } - vec_chars.push_back( '\0' ); - return true; - } - break; - case kind::REGEXP_UNION: - { - bool flag = false; - for(unsigned i=0; i vt2; - for(unsigned i=0; i 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(); + } + } else { + return false; + } + } + vec_chars.push_back( '\0' ); + return true; + } + break; + case kind::REGEXP_UNION: + { + bool flag = false; + for(unsigned i=0; i vt2; + for(unsigned i=0; i 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 ) { - 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; imkNode(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; imkNode(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; imkNode(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; imkNode(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; imkNode(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; imkNode(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; imkSkolem( "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; imkNode(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; imkNode(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; imkSkolem( "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; imkNode(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; imkNode(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 &pcset, SetNodes &pvset ) { - std::map< Node, std::pair< std::set, 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 cset; - SetNodes vset; - int k = r.getKind(); - switch( k ) { - case kind::REGEXP_EMPTY: { - break; - } - case kind::REGEXP_SIGMA: { - for(unsigned i=0; i(); - s.getCharSet( cset ); - } else if(st.getKind() == kind::VARIABLE) { - vset.insert( st ); - } else { - for(unsigned i=0; i(); - s.getCharSet( cset ); - } else { - vset.insert( st[i] ); - } - } - } - break; - } - case kind::REGEXP_CONCAT: { - for(unsigned i=0; i, SetNodes > p(cset, vset); - d_cset_cache[r] = p; + std::map< Node, std::pair< std::set, 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 cset; + SetNodes vset; + int k = r.getKind(); + switch( k ) { + case kind::REGEXP_EMPTY: { + break; + } + case kind::REGEXP_SIGMA: { + for(unsigned i=0; i(); + s.getCharSet( cset ); + } else if(st.getKind() == kind::VARIABLE) { + vset.insert( st ); + } else { + for(unsigned i=0; i(); + s.getCharSet( cset ); + } else { + vset.insert( st[i] ); + } + } + } + break; + } + case kind::REGEXP_CONCAT: { + for(unsigned i=0; i, SetNodes > p(cset, vset); + d_cset_cache[r] = p; - Trace("regexp-cset") << "CSET( " << mkString(r) << " ) = { "; - for(std::set::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::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::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::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 cset; - SetNodes vset; - firstChars(r, cset, vset); - std::vector< Node > vec_nodes; - for(unsigned i=0; imkNode(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 cset; + SetNodes vset; + firstChars(r, cset, vset); + std::vector< Node > vec_nodes; + for(unsigned i=0; imkNode(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; imkNode(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 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; jmkNode(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 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 tset; - splitRegExp(r[0], tset); - PairNodes tmp1(d_emptySingleton, d_emptySingleton); - pset.push_back(tmp1); - for(unsigned i=0; imkNode(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; imkNode(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; imkNode(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 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; jmkNode(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 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 tset; + splitRegExp(r[0], tset); + PairNodes tmp1(d_emptySingleton, d_emptySingleton); + pset.push_back(tmp1); + for(unsigned i=0; imkNode(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; imkNode(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().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().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 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, std::set > > d_cset_cache; - std::map< Node, std::pair< std::set, std::set > > 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 &pcset, SetNodes &pvset ); - Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ); - void firstChars( Node r, std::set &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, std::set > > d_cset_cache; + std::map< Node, std::pair< std::set, std::set > > 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 &pcset, SetNodes &pvset ); + Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ); + void firstChars( Node r, std::set &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(); - CVC4::String bs = bc.getConst(); - 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(); + CVC4::String bs = bc.getConst(); + 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& assumptions){ } Debug("strings-explain-debug") << "Explanation for " << literal << " was " << std::endl; for( unsigned i=ps; iassertEqualityEngine( &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; i0 ) 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().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().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 pure_eq; - Trace("strings-model") << "The equivalence classes "; - for( unsigned j=0; j 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; i0 ) 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().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().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 pure_eq; + Trace("strings-model") << "The equivalence classes "; + for( unsigned j=0; jd_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().getNumerator().toUnsignedInt()); - for( unsigned j=0; jassertEquality( 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; i0 ) 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; jassertEquality( 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; igetValue(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().getNumerator().toUnsignedInt()); + for( unsigned j=0; jassertEquality( 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; i0 ) 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; jassertEquality( 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; igetValue(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; ilemma( 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; ilemma( 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 nf_n; - std::vector 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 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; rmkNode( kind::EQUAL, n[i], nr ) ); - } - if( !nresult ) { - //Trace("strings-process-debug") << "....Caused already asserted - for( unsigned j=i+1; j1 ) { - 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 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 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 nf_n; + std::vector 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 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; rmkNode( kind::EQUAL, n[i], nr ) ); + } + if( !nresult ) { + //Trace("strings-process-debug") << "....Caused already asserted + for( unsigned j=i+1; j1 ) { + 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 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 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(); - CVC4::String s2 = itr2->getConst(); - *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(); + CVC4::String s2 = itr2->getConst(); + *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 &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().tailcmp( r.getConst(), c ) ) { - if(c >= 0) { - s_zy = NodeManager::currentNM()->mkConst( s_zy.getConst().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().isRepeated() - ) { - Node rep_c = NodeManager::currentNM()->mkConst( s_zy.getConst().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().tailcmp( r.getConst(), c ) ) { + if(c >= 0) { + s_zy = NodeManager::currentNM()->mkConst( s_zy.getConst().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().isRepeated() + ) { + Node rep_c = NodeManager::currentNM()->mkConst( s_zy.getConst().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 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(); - CVC4::String strb = normal_forms[nconst_k][nconst_index_k + 1].getConst(); - 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().size() == 1 ? const_str : - NodeManager::currentNM()->mkConst( const_str.getConst().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 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(); + CVC4::String strb = normal_forms[nconst_k][nconst_index_k + 1].getConst(); + 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().size() == 1 ? const_str : + NodeManager::currentNM()->mkConst( const_str.getConst().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 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().size() <= other_str.getConst().size() ? const_str.getConst().size() : other_str.getConst().size(); - bool isSameFix = isRev ? const_str.getConst().rstrncmp(other_str.getConst(), len_short): const_str.getConst().strncmp(other_str.getConst(), len_short); - if( isSameFix ) { - //same prefix/suffix - //k is the index of the string that is shorter - int k = const_str.getConst().size()().size() ? i : j; - int index_k = const_str.getConst().size()().size() ? index_i : index_j; - int l = const_str.getConst().size()().size() ? j : i; - int index_l = const_str.getConst().size()().size() ? index_j : index_i; - if(isRev) { - int new_len = normal_forms[l][index_l].getConst().size() - len_short; - Node remainderStr = NodeManager::currentNM()->mkConst( normal_forms[l][index_l].getConst().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().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 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().size() <= other_str.getConst().size() ? const_str.getConst().size() : other_str.getConst().size(); + bool isSameFix = isRev ? const_str.getConst().rstrncmp(other_str.getConst(), len_short): const_str.getConst().strncmp(other_str.getConst(), len_short); + if( isSameFix ) { + //same prefix/suffix + //k is the index of the string that is shorter + int k = const_str.getConst().size()().size() ? i : j; + int index_k = const_str.getConst().size()().size() ? index_i : index_j; + int l = const_str.getConst().size()().size() ? j : i; + int index_l = const_str.getConst().size()().size() ? index_j : index_i; + if(isRev) { + int new_len = normal_forms[l][index_l].getConst().size() - len_short; + Node remainderStr = NodeManager::currentNM()->mkConst( normal_forms[l][index_l].getConst().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().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 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 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() ) { - 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_kmkNode( 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().size() < j.getConst().size() ? i.getConst().size() : j.getConst().size(); - bool isSameFix = isRev ? i.getConst().rstrncmp(j.getConst(), len_short): i.getConst().strncmp(j.getConst(), len_short); - if( isSameFix ) { - //same prefix/suffix - //k is the index of the string that is shorter - Node nk = i.getConst().size() < j.getConst().size() ? i : j; - Node nl = i.getConst().size() < j.getConst().size() ? j : i; - Node remainderStr; - if(isRev) { - int new_len = nl.getConst().size() - len_short; - remainderStr = NodeManager::currentNM()->mkConst( nl.getConst().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().substr(len_short) ); - Trace("strings-solve-debug-test") << "Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl; - } - if( i.getConst().size() < j.getConst().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() ) { + 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_kmkNode( 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().size() < j.getConst().size() ? i.getConst().size() : j.getConst().size(); + bool isSameFix = isRev ? i.getConst().rstrncmp(j.getConst(), len_short): i.getConst().strncmp(j.getConst(), len_short); + if( isSameFix ) { + //same prefix/suffix + //k is the index of the string that is shorter + Node nk = i.getConst().size() < j.getConst().size() ? i : j; + Node nl = i.getConst().size() < j.getConst().size() ? j : i; + Node remainderStr; + if(isRev) { + int new_len = nl.getConst().size() - len_short; + remainderStr = NodeManager::currentNM()->mkConst( nl.getConst().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().substr(len_short) ); + Trace("strings-solve-debug-test") << "Break normal form of " << nl << " into " << nk << ", " << remainderStr << std::endl; + } + if( i.getConst().size() < j.getConst().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; ilemma(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; i1 && 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 eqcs; + getEquivalenceClasses( eqcs ); + std::vector< std::vector< Node > > cols; + std::vector< Node > lts; + separateByLength( eqcs, cols, lts ); + for( unsigned i=0; i1 && 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 nodes; - getEquivalenceClasses( nodes ); - for( unsigned i=0; i1 ) { - 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; i1 ) { + 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; id_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; id_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& 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; i0 ) Trace(c) << " ++ "; - Trace(c) << n[i]; - } + for( unsigned i=0; i0 ) 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; iend(); ++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 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; iend(); ++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; imkBoundVar(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, 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; imkSkolem( "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; imkSkolem( "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; imkNode( 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; imkNode( 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().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; + co.push_back(0); + for(unsigned int k=0; k().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 vec_nodes; - for(unsigned int i=1; imkNode( 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 vec_nodes; + for(unsigned int i=1; imkNode( 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(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(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 &nf_exp) { - Node ret = x; - if(x.getKind() == kind::STRING_CONCAT) { - std::vector< Node > vec_nodes; - for(unsigned i=0; i vec_nodes; + for(unsigned i=0; i &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 vec_nodes; - for(unsigned i=0; imkNode(kind::REGEXP_UNION, vec_nodes) ); - break; - } - case kind::REGEXP_INTER: { - std::vector< Node > vec_nodes; - for(unsigned i=0; imkNode(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 vec_nodes; + for(unsigned i=0; imkNode(kind::REGEXP_UNION, vec_nodes) ); + break; + } + case kind::REGEXP_INTER: { + std::vector< Node > vec_nodes; + for(unsigned i=0; imkNode(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 NodeList; - typedef context::CDHashMap NodeListMap; - typedef context::CDHashMap NodeBoolMap; - typedef context::CDHashMap NodeIntMap; - typedef context::CDHashMap NodeNodeMap; - typedef context::CDHashSet NodeSet; + typedef context::CDChunkList NodeList; + typedef context::CDHashMap NodeListMap; + typedef context::CDHashMap NodeBoolMap; + typedef context::CDHashMap NodeIntMap; + typedef context::CDHashMap NodeNodeMap; + typedef context::CDHashSet 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& 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& 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 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 &nf_exp); - Node getNormalSymRegExp(Node r, std::vector &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 &nf_exp); + Node getNormalSymRegExp(Node r, std::vector &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; imkNode(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 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; imkConst(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; imkNode(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 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; imkConst(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().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().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::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().getNumerator().toUnsignedInt(); - if(len > 1) { - Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) ); - std::vector< Node > vec; - for(int i=0; imkConst( ::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().getNumerator().toUnsignedInt(); + if(len > 1) { + Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) ); + std::vector< Node > vec; + for(int i=0; imkConst( ::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; imkNode( 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; imkNode( 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) { @@ -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; imkNode( 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; imkNode( 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) { - 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 d_cache; - //Constants - Node d_zero; + // NOTE: this class is NOT context-dependent + std::hash_map 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; imkConst( preNode.getConst().concat( tmpNode[0].getConst() ) ); @@ -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().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_vec; - bool flag = false; + bool flag = false; for(unsigned i=0; i 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 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() ); - } else { - Assert( false, "RegExp contains variables" ); - } - } - case kind::REGEXP_CONCAT: { - if( s.size() != index_start ) { - std::vector 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() ); + } else { + Assert( false, "RegExp contains variables" ); + } + } + case kind::REGEXP_CONCAT: { + if( s.size() != index_start ) { + std::vector 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; i0; --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; i0; --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(); - 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(); + 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().sgn()>=0 && node[2].getConst().sgn()>=0) { - int i = node[1].getConst().getNumerator().toUnsignedInt(); - int j = node[2].getConst().getNumerator().toUnsignedInt(); - if( node[0].isConst() ) { - if( node[0].getConst().size() >= (unsigned) (i + j) ) { - retNode = NodeManager::currentNM()->mkConst( node[0].getConst().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().size() >= (unsigned) (i + j) ) { - retNode = NodeManager::currentNM()->mkConst( node[0][0].getConst().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(); - CVC4::String t = node[1].getConst(); - 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(); - CVC4::String t = node[1].getConst(); - int i = node[2].getConst().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(); - CVC4::String t = node[1].getConst(); - std::size_t p = s.find(t); - if( p != std::string::npos ) { - if(node[2].isConst()) { - CVC4::String r = node[2].getConst(); - 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(); - CVC4::String t = node[0].getConst(); - 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(); - CVC4::String t = node[0].getConst(); - 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().getNumerator().toString(); - if(node.getKind() == kind::STRING_U16TOS) { - CVC4::Rational r1(UINT16_MAX); - CVC4::Rational r2 = node[0].getConst(); - if(r2>r1) { - flag = true; - } - } else if(node.getKind() == kind::STRING_U32TOS) { - CVC4::Rational r1(UINT32_MAX); - CVC4::Rational r2 = node[0].getConst(); - if(r2>r1) { - flag = true; - } - } - //std::string stmp = static_cast( &(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(); - 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(); - 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().sgn()>=0 && node[2].getConst().sgn()>=0) { + int i = node[1].getConst().getNumerator().toUnsignedInt(); + int j = node[2].getConst().getNumerator().toUnsignedInt(); + if( node[0].isConst() ) { + if( node[0].getConst().size() >= (unsigned) (i + j) ) { + retNode = NodeManager::currentNM()->mkConst( node[0].getConst().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().size() >= (unsigned) (i + j) ) { + retNode = NodeManager::currentNM()->mkConst( node[0][0].getConst().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(); + CVC4::String t = node[1].getConst(); + 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(); + CVC4::String t = node[1].getConst(); + int i = node[2].getConst().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(); + CVC4::String t = node[1].getConst(); + std::size_t p = s.find(t); + if( p != std::string::npos ) { + if(node[2].isConst()) { + CVC4::String r = node[2].getConst(); + 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(); + CVC4::String t = node[0].getConst(); + 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(); + CVC4::String t = node[0].getConst(); + 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().getNumerator().toString(); + if(node.getKind() == kind::STRING_U16TOS) { + CVC4::Rational r1(UINT16_MAX); + CVC4::Rational r2 = node[0].getConst(); + if(r2>r1) { + flag = true; + } + } else if(node.getKind() == kind::STRING_U32TOS) { + CVC4::Rational r1(UINT32_MAX); + CVC4::Rational r2 = node[0].getConst(); + if(r2>r1) { + flag = true; + } + } + //std::string stmp = static_cast( &(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(); + 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(); + 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().getFirstChar(); - char end = node[1].getConst().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().getNumerator().toUnsignedInt(); - std::vector< Node > vec_nodes; - for(unsigned i=0; imkNode(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().getNumerator().toUnsignedInt(); - if(u <= l) { - retNode = n; - } else { - std::vector< Node > vec2; - vec2.push_back(n); - for(unsigned j=l; jmkNode(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().getFirstChar(); + char end = node[1].getConst().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().getNumerator().toUnsignedInt(); + std::vector< Node > vec_nodes; + for(unsigned i=0; imkNode(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().getNumerator().toUnsignedInt(); + if(u <= l) { + retNode = n; + } else { + std::vector< Node > vec2; + vec2.push_back(n); + for(unsigned j=l; jmkNode(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 { - 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; - 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= '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 &cset) const { - for(std::vector::const_iterator itr = d_str.begin(); - itr != d_str.end(); itr++) { - cset.insert( *itr ); - } + for(std::vector::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( &(std::ostringstream() << (int)c) )->str(); - } - } - str += s; - } - } - return str; + std::string str; + for(unsigned int i=0; i( &(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 1) { + unsigned int f = d_str[0]; + for(unsigned i=1; i=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 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'9') { - return false; - } - } - return true; + if(d_str.size() == 0) return false; + for(unsigned int i=0; i'9') { + return false; + } + } + return true; } int toNumber() const { - if(isNumber()) { - int ret=0; - for(unsigned int i=0; i &cset) const; };/* class String */ -- 2.30.2