Fixes for strings, explanations for constant split propagations, substr under concat...
authorajreynol <andrew.j.reynolds@gmail.com>
Thu, 21 Jul 2016 15:56:09 +0000 (10:56 -0500)
committerajreynol <andrew.j.reynolds@gmail.com>
Thu, 21 Jul 2016 15:56:09 +0000 (10:56 -0500)
src/theory/strings/theory_strings.cpp
src/theory/strings/theory_strings.h
src/theory/strings/theory_strings_rewriter.cpp
test/regress/regress0/strings/Makefile.am
test/regress/regress0/strings/cmu-substr-rw.smt2 [new file with mode: 0644]
test/regress/regress0/strings/csp-prefix-exp-bug.smt2 [new file with mode: 0644]

index 77492631548d3aa7bfb3908fd443f7088fa3ef42..cdcac76041d6bc2a60d7e8ee124e400024d35cfa 100644 (file)
@@ -75,6 +75,7 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u,
       d_preproc(u),
       d_preproc_cache(u),
       d_extf_infer_cache(c),
+      d_extf_infer_cache_u(u),
       d_ee_disequalities(c),
       d_congruent(c),
       d_proxy_var(u),
@@ -937,10 +938,21 @@ void TheoryStrings::assertPendingFact(Node atom, bool polarity, Node exp) {
     d_equalityEngine.assertEquality( atom, polarity, exp );
     Trace("strings-pending-debug") << "  Finished assert equality" << std::endl;
   } else {
-    if( atom.getKind()==kind::STRING_IN_REGEXP ) {
+    d_equalityEngine.assertPredicate( atom, polarity, exp );
+    //process extf
+    if( atom.getKind()==kind::STRING_IN_REGEXP ){
       addExtendedFuncTerm( atom );
+      if( polarity && atom[1].getKind()==kind::REGEXP_RANGE ){
+        if( d_extf_infer_cache_u.find( atom )==d_extf_infer_cache_u.end() ){
+          d_extf_infer_cache_u.insert( atom );
+          //length of first argument is one
+          Node conc = d_one.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, atom[0] ) );
+          Node lem = NodeManager::currentNM()->mkNode( kind::OR, atom.negate(), conc );
+          Trace("strings-lemma") << "Strings::Lemma RE-Range-Len : " << lem << std::endl;
+          d_out->lemma( lem );
+        }
+      }
     }
-    d_equalityEngine.assertPredicate( atom, polarity, exp );
   }
   Trace("strings-pending-debug") << "  Now collect terms" << std::endl;
   //collect extended function terms in the atom
@@ -1426,16 +1438,7 @@ void TheoryStrings::checkExtfInference( Node n, Node nr, ExtfInfoTmp& in, int ef
     //d_extf_infer_cache stores whether we have made the inferences associated with a node n, 
     // this may need to be generalized if multiple inferences apply
         
-    if( nr.getKind()==kind::STRING_IN_REGEXP ){
-      if( in.d_pol==1 && nr[1].getKind()==kind::REGEXP_RANGE ){
-        if( d_extf_infer_cache.find( nr )==d_extf_infer_cache.end() ){
-          d_extf_infer_cache.insert( nr );
-          //length of first argument is one
-          Node conc = d_one.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, nr[0]) );
-          sendInference( in.d_exp, conc, "RE-Range-Len", true );
-        }
-      }
-    }else if( nr.getKind()==kind::STRING_STRCTN ){
+    if( nr.getKind()==kind::STRING_STRCTN ){
       if( ( in.d_pol==1 && nr[1].getKind()==kind::STRING_CONCAT ) || ( in.d_pol==-1 && nr[0].getKind()==kind::STRING_CONCAT ) ){
         if( d_extf_infer_cache.find( nr )==d_extf_infer_cache.end() ){
           d_extf_infer_cache.insert( nr );
@@ -2019,44 +2022,27 @@ bool TheoryStrings::normalizeEquivalenceClass( Node eqc ) {
       }
     }
     //construct the normal form
-    if( normal_forms.empty() ){
-      Trace("strings-solve-debug2") << "construct the normal form" << std::endl;
-      //FIXME: cleanup
-      eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
-      Node eqc_c = eqc;
-      //do not choose a concat here (in this case they have non-trivial explanation why they normalize to self)
-      while( eqc_c.getKind()==kind::STRING_CONCAT && !eqc_i.isFinished() ){
-        Node n = (*eqc_i);
-        if( d_congruent.find( n )==d_congruent.end() ){
-          if( n.getKind()!=kind::STRING_CONCAT ){
-            eqc_c = n;
-          }
-        }
-        ++eqc_i;
-      }
-      getConcatVec( eqc_c, d_normal_forms[eqc] );
-      d_normal_forms_base[eqc] = eqc_c;
+    Assert( !normal_forms.empty() );
+
+    int nf_index = 0;
+    std::vector< Node >::iterator itn = std::find( normal_form_src.begin(), normal_form_src.end(), eqc );
+    if( itn!=normal_form_src.end() ){
+      nf_index = itn - normal_form_src.begin();
+      Trace("strings-solve-debug2") << "take normal form " << nf_index << std::endl;
+      Assert( normal_form_src[nf_index]==eqc );
     }else{
-      int nf_index = 0;
-      std::vector< Node >::iterator itn = std::find( normal_form_src.begin(), normal_form_src.end(), eqc );
-      if( itn!=normal_form_src.end() ){
-        nf_index = itn - normal_form_src.begin();
-        Trace("strings-solve-debug2") << "take normal form " << nf_index << std::endl;
-        Assert( normal_form_src[nf_index]==eqc );
-      }else{
-        //just take the first normal form
-        Trace("strings-solve-debug2") << "take the first normal form" << std::endl;
-      }
-      d_normal_forms[eqc].insert( d_normal_forms[eqc].end(), normal_forms[nf_index].begin(), normal_forms[nf_index].end() );
-      d_normal_forms_exp[eqc].insert( d_normal_forms_exp[eqc].end(), normal_forms_exp[nf_index].begin(), normal_forms_exp[nf_index].end() );
-      Trace("strings-solve-debug2") << "take normal form ... done" << std::endl;
-      d_normal_forms_base[eqc] = normal_form_src[nf_index];
-      //track dependencies 
-      for( unsigned i=0; i<normal_forms_exp[nf_index].size(); i++ ){
-        Node exp = normal_forms_exp[nf_index][i];
-        for( unsigned r=0; r<2; r++ ){
-          d_normal_forms_exp_depend[eqc][exp][r==0] = normal_forms_exp_depend[nf_index][exp][r==0];
-        }
+      //just take the first normal form
+      Trace("strings-solve-debug2") << "take the first normal form" << std::endl;
+    }
+    d_normal_forms[eqc].insert( d_normal_forms[eqc].end(), normal_forms[nf_index].begin(), normal_forms[nf_index].end() );
+    d_normal_forms_exp[eqc].insert( d_normal_forms_exp[eqc].end(), normal_forms_exp[nf_index].begin(), normal_forms_exp[nf_index].end() );
+    Trace("strings-solve-debug2") << "take normal form ... done" << std::endl;
+    d_normal_forms_base[eqc] = normal_form_src[nf_index];
+    //track dependencies 
+    for( unsigned i=0; i<normal_forms_exp[nf_index].size(); i++ ){
+      Node exp = normal_forms_exp[nf_index][i];
+      for( unsigned r=0; r<2; r++ ){
+        d_normal_forms_exp_depend[eqc][exp][r==0] = normal_forms_exp_depend[nf_index][exp][r==0];
       }
     }
     Trace("strings-process-debug") << "Return process equivalence class " << eqc << " : returned, size = " << d_normal_forms[eqc].size() << std::endl;
@@ -2067,6 +2053,7 @@ bool TheoryStrings::normalizeEquivalenceClass( Node eqc ) {
 bool TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
                                     std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend ) {
   //constant for equivalence class
+  Node eqc_non_c = eqc;
   Trace("strings-process-debug") << "Get normal forms " << eqc << std::endl;
   eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
   while( !eqc_i.isFinished() ){
@@ -2156,12 +2143,23 @@ bool TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node >
           Node nn = nf_n.size()==0 ? d_emptyString : nf_n[0];
           Assert( areEqual( nn, eqc ) );
         }
+      }else{
+        eqc_non_c = n;
       }
     }
     ++eqc_i;
   }
 
-  if( !normal_forms.empty() ) {
+  if( normal_forms.empty() ) {
+    Trace("strings-solve-debug2") << "construct the normal form" << std::endl;
+    //do not choose a concat here use "eqc_non_c" (in this case they have non-trivial explanation why they normalize to self)
+    std::vector< Node > eqc_non_c_nf;
+    getConcatVec( eqc_non_c, eqc_non_c_nf );
+    normal_forms.push_back( eqc_non_c_nf );
+    normal_form_src.push_back( eqc_non_c );
+    normal_forms_exp.push_back( std::vector< Node >() );
+    normal_forms_exp_depend.push_back( std::map< Node, std::map< bool, int > >() );
+  }else{
     if(Trace.isOn("strings-solve")) {
       Trace("strings-solve") << "--- Normal forms for equivlance class " << eqc << " : " << std::endl;
       for( unsigned i=0; i<normal_forms.size(); i++ ) {
@@ -2229,32 +2227,33 @@ bool TheoryStrings::getNormalForms( Node &eqc, std::vector< std::vector< Node >
   return true;
 }
 
-void TheoryStrings::getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
-                                                   std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
-                                                   unsigned i, unsigned j, int index, bool isRev, std::vector< Node >& curr_exp ) {
+void TheoryStrings::getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+                                                   unsigned i, int index, bool isRev, std::vector< Node >& curr_exp ) {
   if( index==-1 || !options::stringMinPrefixExplain() ){
     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() );
   }else{
-    Trace("strings-explain-prefix") << "Get explanation for prefix " << index << " of normal forms " << i << " and " << j << ", reverse = " << isRev << std::endl;
-    for( unsigned r=0; r<2; r++ ){
-      int tindex = r==0 ? i : j;
-      for( unsigned k=0; k<normal_forms_exp[tindex].size(); k++ ){
-        Node exp = normal_forms_exp[tindex][k];
-        int dep = normal_forms_exp_depend[tindex][exp][isRev];
-        if( dep<=index ){
-          curr_exp.push_back( exp );
-          Trace("strings-explain-prefix-debug") << "  include : " << exp << std::endl;
-        }else{
-          Trace("strings-explain-prefix-debug") << "  exclude : " << exp << std::endl;
-        }
+    for( unsigned k=0; k<normal_forms_exp[i].size(); k++ ){
+      Node exp = normal_forms_exp[i][k];
+      int dep = normal_forms_exp_depend[i][exp][isRev];
+      if( dep<=index ){
+        curr_exp.push_back( exp );
+        Trace("strings-explain-prefix-debug") << "  include : " << exp << std::endl;
+      }else{
+        Trace("strings-explain-prefix-debug") << "  exclude : " << exp << std::endl;
       }
     }
-    Trace("strings-explain-prefix") << "Included " << curr_exp.size() << " / " << ( normal_forms_exp[i].size() + normal_forms_exp[j].size() ) << std::endl;
   }
-  if( normal_form_src[i]!=normal_form_src[j] ){
-    curr_exp.push_back( normal_form_src[i].eqNode( normal_form_src[j] ) );
+}
+
+void TheoryStrings::getExplanationVectorForPrefixEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+                                                     std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+                                                     unsigned i, unsigned j, int index_i, int index_j, bool isRev, std::vector< Node >& curr_exp ) {
+  Trace("strings-explain-prefix") << "Get explanation for prefix " << index_i << ", " << index_j << " of normal forms " << i << " and " << j << ", reverse = " << isRev << std::endl;
+  for( unsigned r=0; r<2; r++ ){
+    getExplanationVectorForPrefix( normal_forms_exp, normal_forms_exp_depend, r==0 ? i : j, r==0 ? index_i : index_j, isRev, curr_exp );
   }
+  Trace("strings-explain-prefix") << "Included " << curr_exp.size() << " / " << ( normal_forms_exp[i].size() + normal_forms_exp[j].size() ) << std::endl;
+  addToExplanation( normal_form_src[i], normal_form_src[j], curr_exp );
 }
 
 bool TheoryStrings::processNEqc( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
@@ -2318,7 +2317,7 @@ bool TheoryStrings::processNEqc( std::vector< std::vector< Node > > &normal_form
                   c_loop_index = loop_in_i!=-1 ? loop_in_i : loop_in_j;
                   c_index = index;
                   
-                  getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, false, c_lb_exp );
+                  getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, -1, false, c_lb_exp );
 
                   if(options::stringLB() == 0) {
                     flag_lb = true;
@@ -2341,13 +2340,15 @@ bool TheoryStrings::processNEqc( std::vector< std::vector< Node > > &normal_form
                   Assert( other_str.getKind()!=kind::STRING_CONCAT, "Other string is not CONCAT." );
                   if( !d_equalityEngine.areDisequal(other_str, d_emptyString, true) ) {
                     sendSplit( other_str, d_emptyString, "Len-Split(CST)" );
-                  } else {
-                    Assert(areDisequal(other_str, d_emptyString), "CST Split on empty Var");
-                    getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, false, antec );
+                  }else{
+                    Assert(areDisequal(other_str, d_emptyString), "CST Split on empty Var");                    
                     Node xnz = other_str.eqNode(d_emptyString).negate();
                     antec.push_back( xnz );
                     Node conc;
                     if( normal_forms[nconst_k].size() > index + 1 && normal_forms[nconst_k][index + 1].isConst() ) {
+                      int index_i = const_k==i ? index : index+1;
+                      int index_j = const_k==j ? index : index+1;
+                      getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index_i, index_j, false, antec );
                       CVC4::String stra = const_str.getConst<String>();
                       CVC4::String strb = normal_forms[nconst_k][index + 1].getConst<String>();
                       CVC4::String stra1 = stra.substr(1);
@@ -2358,22 +2359,36 @@ bool TheoryStrings::processNEqc( std::vector< std::vector< Node > > &normal_form
                       Node sk = mkSkolemCached( other_str, prea, sk_id_c_spt, "c_spt" );
                       conc = other_str.eqNode( mkConcat(prea, sk) );
                       Trace("strings-csp") << "Const Split: " << prea << " is removed from " << stra << " due to " << strb << std::endl;
+                      sendInference( antec, conc, "S-Split(CST-P)-prop", true );
                     } else {
+                      getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, false, antec );
+                      /* TODO
+                      CVC4::String stra = const_str.getConst<String>();
+                      if( stra.size()>3 ){
+                        //split string in half
+                        Node c_firstHalf =  NodeManager::currentNM()->mkConst( stra.substr(0, stra.size()/2 ) );
+                        Node sk = mkSkolemCached( other_str, c_firstHalf , sk_id_vc_bin_spt, "c_spt" );
+                        conc = NodeManager::currentNM()->mkNode( kind::OR, other_str.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, c_firstHalf, sk ) ),
+                                                                           NodeManager::currentNM()->mkNode( kind::AND,
+                                                                             sk.eqNode( d_emptyString ).negate(),
+                                                                             c_firstHalf.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, other_str, sk ) )  ));
+                        Trace("strings-csp") << "Const Split: " << c_firstHalf << " is removed from " << const_str << " (binary) " << std::endl;
+                        sendInference( antec, conc, "S-Split(CST-P)-binary", true );
+                      }else{
+                      */
                       // normal v/c split
                       Node firstChar = const_str.getConst<String>().size() == 1 ? const_str :
                         NodeManager::currentNM()->mkConst( const_str.getConst<String>().substr(0, 1) );
                       Node sk = mkSkolemCached( other_str, firstChar, sk_id_vc_spt, "c_spt" );
                       conc = other_str.eqNode( mkConcat(firstChar, sk) );
-                      Trace("strings-csp") << "Const Split: " << firstChar << " is removed from " << const_str << " (normal) " << std::endl;
+                      Trace("strings-csp") << "Const Split: " << firstChar << " is removed from " << const_str << " (serial) " << std::endl;
+                      sendInference( antec, conc, "S-Split(CST-P)", true );
                     }
-
-                    conc = Rewriter::rewrite( conc );
-                    sendInference( antec, conc, "S-Split(CST-P)", true );
                   }
                   return true;
                 } else {
                   std::vector< Node > antec_new_lits;
-                  getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, false, antec );
+                  getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, false, antec );
 
                   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 ) ){
@@ -2472,7 +2487,7 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
         unsigned index_k = index;
         //Node eq_exp = mkAnd( curr_exp );
         std::vector< Node > curr_exp;
-        getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, isRev, curr_exp );
+        getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, -1, isRev, curr_exp );
         while(!d_conflict && index_k<normal_forms[k].size()) {
           //can infer that this string must be empty
           Node eq = normal_forms[k][index_k].eqNode( d_emptyString );
@@ -2501,7 +2516,7 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
           //eq = Rewriter::rewrite( eq );
           Node length_eq = length_term_i.eqNode( length_term_j );
           //temp_exp.insert(temp_exp.end(), curr_exp.begin(), curr_exp.end() );
-          getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, isRev, temp_exp );
+          getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, isRev, temp_exp );
           temp_exp.push_back(length_eq);
           sendInference( temp_exp, eq, "N_Unify" );
           return true;
@@ -2511,7 +2526,7 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
           Node conc;
           std::vector< Node > antec;
           //antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
-          getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, isRev, antec );
+          getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, -1, -1, isRev, antec );
           std::vector< Node > eqn;
           for( unsigned r=0; r<2; r++ ) {
             int index_k = index;
@@ -2562,7 +2577,7 @@ bool TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
             std::vector< Node > antec;
             //curr_exp is conflict
             //antec.insert(antec.end(), curr_exp.begin(), curr_exp.end() );
-            getExplanationVectorForPrefix( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, isRev, antec );
+            getExplanationVectorForPrefixEq( normal_forms, normal_form_src, normal_forms_exp, normal_forms_exp_depend, i, j, index, index, isRev, antec );
             sendInference( antec, d_false, "N_Const", true );
             return true;
           }
@@ -3448,9 +3463,10 @@ void TheoryStrings::checkLengthsEqc() {
           ant.insert( ant.end(), d_normal_forms_exp[d_strings_eqc[i]].begin(), d_normal_forms_exp[d_strings_eqc[i]].end() );
           ant.push_back( d_normal_forms_base[d_strings_eqc[i]].eqNode( lt ) );
           Node lc = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, nf );
-          lc = Rewriter::rewrite( lc );
-          Node eq = llt.eqNode( lc );
-          if( llt!=lc ){
+          Node lcr = Rewriter::rewrite( lc );
+          Trace("strings-process-debug") << "Rewrote length " << lc << " to " << lcr << std::endl;
+          Node eq = llt.eqNode( lcr );
+          if( llt!=lcr ){
             ei->d_normalized_length.set( eq );
             sendInference( ant, eq, "LEN-NORM", true );
           }
@@ -4293,7 +4309,7 @@ void TheoryStrings::checkMemberships() {
             antec = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::AND, antec, mkExplain(rnfexp)) );
             Node conc = nvec.size()==1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);
             conc = Rewriter::rewrite(conc);
-            sendLemma( antec, conc, "REGEXP" );
+            sendLemma( antec, conc, "REGEXP_Unfold" );
             addedLemma = true;
             if(changed) {
               cprocessed.push_back( assertion );
@@ -4301,7 +4317,7 @@ void TheoryStrings::checkMemberships() {
               processed.push_back( assertion );
             }
             //d_regexp_ucached[assertion] = true;
-          } else {
+          }else{
             Trace("strings-regexp") << "Unroll/simplify membership of non-atomic term " << xr << " = ";
             for( unsigned j=0; j<d_normal_forms[xr].size(); j++ ){
               Trace("strings-regexp") << d_normal_forms[xr][j] << " ";
index e9d93a488dff6371e49cb4005758d74312fafd22..b8959f003d8554179ac489715ea38cbe6ce8da1a 100644 (file)
@@ -180,6 +180,7 @@ private:
   NodeBoolMap d_preproc_cache;
   // extended functions inferences cache
   NodeSet d_extf_infer_cache;
+  NodeSet d_extf_infer_cache_u;
   std::vector< Node > d_empty_vec;
   //
   NodeList d_ee_disequalities;
@@ -321,10 +322,11 @@ private:
   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 );
   void checkDeqNF();
-  
-  void getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
-                                      std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
-                                      unsigned i, unsigned j, int index, bool isRev, std::vector< Node >& curr_exp );
+  void getExplanationVectorForPrefix( std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+                                      unsigned i, int index, bool isRev, std::vector< Node >& curr_exp );
+  void getExplanationVectorForPrefixEq( std::vector< std::vector< Node > > &normal_forms, std::vector< Node > &normal_form_src,
+                                        std::vector< std::vector< Node > > &normal_forms_exp, std::vector< std::map< Node, std::map< bool, int > > >& normal_forms_exp_depend,
+                                        unsigned i, unsigned j, int index_i, int index_j, bool isRev, std::vector< Node >& curr_exp );
 
   //check membership constraints
   Node mkRegExpAntec(Node atom, Node ant);
@@ -401,6 +403,7 @@ protected:
   enum {
     sk_id_c_spt,
     sk_id_vc_spt,
+    sk_id_vc_bin_spt,
     sk_id_v_spt,
     sk_id_ctn_pre,
     sk_id_ctn_post,
index bb03d8d0f5fcbbc0f1f0a987f8ff60d7f4790e9f..77caf82374ca64314d142d58050ab5d21e4c1b8c 100644 (file)
@@ -1032,16 +1032,16 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
       Node tmpNode = rewriteConcatString(node[0]);
       if(tmpNode.isConst()) {
         retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode.getConst<String>().size() ) );
-      } else if(tmpNode.getKind() == kind::STRING_SUBSTR) {
+      //} else if(tmpNode.getKind() == kind::STRING_SUBSTR) {
         //retNode = tmpNode[2];
-      } else {
+      } else if( tmpNode.getKind()==kind::STRING_CONCAT ){
         // it has to be string concat
         std::vector<Node> node_vec;
         for(unsigned int i=0; i<tmpNode.getNumChildren(); ++i) {
           if(tmpNode[i].isConst()) {
             node_vec.push_back( NodeManager::currentNM()->mkConst( ::CVC4::Rational( tmpNode[i].getConst<String>().size() ) ) );
-          } else if(tmpNode[i].getKind() == kind::STRING_SUBSTR) {
-            node_vec.push_back( tmpNode[i][2] );
+          //} else if(tmpNode[i].getKind() == kind::STRING_SUBSTR) {
+          //  node_vec.push_back( tmpNode[i][2] );
           } else {
             node_vec.push_back( NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, tmpNode[i]) );
           }
index b09377bf7449d1748e11b2145b79bba9a530167f..9d7e9e13e031acb949ef18a78b2471f826ea5ee5 100644 (file)
@@ -82,7 +82,9 @@ TESTS = \
   cmu-disagree-0707-dd.smt2 \
   cmu-5042-0707-2.smt2 \
   cmu-dis-0707-3.smt2 \
-  nf-ff-contains-abs.smt2  
+  nf-ff-contains-abs.smt2  \
+  csp-prefix-exp-bug.smt2 \
+  cmu-substr-rw.smt2  
 
 FAILING_TESTS =
 
diff --git a/test/regress/regress0/strings/cmu-substr-rw.smt2 b/test/regress/regress0/strings/cmu-substr-rw.smt2
new file mode 100644 (file)
index 0000000..20bf979
--- /dev/null
@@ -0,0 +1,12 @@
+(set-logic ALL_SUPPORTED)
+(set-info :status sat)
+(set-option :strings-exp true)
+;(set-option :produce-models true)
+;(set-option :rewrite-divk true)
+
+(declare-fun uri () String)
+
+(assert (and (and (and (and (and (and (and (and (and (and (and (and (not (not (= (ite (= (str.len (str.substr (str.substr uri (+ (str.indexof uri "%" 0) 1) (- (str.len uri) (+ (str.indexof uri "%" 0) 1))) 0 (- 2 0))) 2) 1 0) 0))) (not (not (= (ite (str.contains (str.substr uri (+ (str.indexof uri "%" 0) 1) (- (str.len uri) (+ (str.indexof uri "%" 0) 1))) "%") 1 0) 0)))) (not (not (= (ite (= (str.len (str.substr uri (+ (str.indexof uri "%" 0) 1) (- (str.len uri) (+ (str.indexof uri "%" 0) 1)))) 0) 1 0) 0)))) (not (= (ite (str.contains uri "%") 1 0) 0))) (not (not (= (ite (= (str.len uri) 0) 1 0) 0)))) (>= (+ (str.indexof uri "%" 0) 1) 0)) (>= (- (str.len uri) (+ (str.indexof uri "%" 0) 1)) 0)) (>= 0 0)) (>= (- 2 0) 0)) (>= (+ (str.indexof uri "%" 0) 1) 0)) (>= (- (str.len uri) (+ (str.indexof uri "%" 0) 1)) 0)) (>= (+ (str.indexof uri "%" 0) 1) 0)) (>= (- (str.len uri) (+ (str.indexof uri "%" 0) 1)) 0)))
+
+(check-sat)
+
diff --git a/test/regress/regress0/strings/csp-prefix-exp-bug.smt2 b/test/regress/regress0/strings/csp-prefix-exp-bug.smt2
new file mode 100644 (file)
index 0000000..c2fb417
--- /dev/null
@@ -0,0 +1,10 @@
+(set-logic QF_S)
+(set-info :status sat)
+
+(declare-fun x () String)
+(declare-fun y () String)
+(declare-fun z () String)
+
+(assert (= (str.len x) 1))
+(assert (= (str.++ x y "b" z) "aaaba"))
+(check-sat)