Do not split on cardinality for string equivalence classes with non-constant lengths...
authorajreynol <andrew.j.reynolds@gmail.com>
Wed, 10 May 2017 15:35:38 +0000 (10:35 -0500)
committerajreynol <andrew.j.reynolds@gmail.com>
Wed, 10 May 2017 15:35:38 +0000 (10:35 -0500)
src/theory/strings/theory_strings.cpp
test/regress/regress0/strings/Makefile.am
test/regress/regress0/strings/bug799-min.smt2 [new file with mode: 0644]

index 42e43b5432e3582756e1a1c3aefd6ab644aca6b3..6526b68cf984843085249ea84010e063f311f8b3 100644 (file)
@@ -2212,7 +2212,7 @@ void TheoryStrings::getNormalForms( Node &eqc, std::vector< 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;
+      Trace("strings-solve") << "--- Normal forms for equivalance class " << eqc << " : " << std::endl;
       for( unsigned i=0; i<normal_forms.size(); i++ ) {
         Trace("strings-solve") << "#" << i << " (from " << normal_form_src[i] << ") : ";
         for( unsigned j=0; j<normal_forms[i].size(); j++ ) {
@@ -3725,9 +3725,32 @@ void TheoryStrings::checkCardinality() {
         card_need++;
       }
       Trace("strings-card") << "Need length " << card_need << " for this number of strings (where alphabet size is " << d_card_size << ")." << std::endl;
-      Node cmp = NodeManager::currentNM()->mkNode( kind::GEQ, lr, NodeManager::currentNM()->mkConst( Rational( card_need ) ) );
-      cmp = Rewriter::rewrite( cmp );
-      if( cmp!=d_true ){
+      //check if we need to split
+      bool needsSplit = true;
+      if( lr.isConst() ){
+        // if constant, compare
+        Node cmp = NodeManager::currentNM()->mkNode( kind::GEQ, lr, NodeManager::currentNM()->mkConst( Rational( card_need ) ) );
+        cmp = Rewriter::rewrite( cmp );
+        needsSplit = cmp!=d_true;
+      }else{
+        // find the minimimum constant that we are unknown to be disequal from, or otherwise stop if we increment such that cardinality does not apply
+        unsigned r=0; 
+        bool success = true;
+        while( r<card_need && success ){
+          Node rr = NodeManager::currentNM()->mkConst<Rational>( Rational(r) );
+          if( areDisequal( rr, lr ) ){
+            r++;
+          }else{
+            success = false;
+          }
+        }
+        if( r>0 ){
+          Trace("strings-card") << "Symbolic length " << lr << " must be at least " << r << " due to constant disequalities." << std::endl;
+        }
+        needsSplit = r<card_need;
+      }
+
+      if( needsSplit ){
         unsigned int int_k = (unsigned int)card_need;
         for( std::vector< Node >::iterator itr1 = cols[i].begin();
             itr1 != cols[i].end(); ++itr1) {
index 41c500170cd18e868cd338a6c7d02dfc1698646b..5c89c847265a97a94b4fabced35db8a976679aac 100644 (file)
@@ -87,7 +87,8 @@ TESTS = \
   strings-index-empty.smt2 \
   bug768.smt2 \
   username_checker_min.smt2 \
-  repl-empty-sem.smt2
+  repl-empty-sem.smt2 \
+  bug799-min.smt2
 
 FAILING_TESTS =
 
diff --git a/test/regress/regress0/strings/bug799-min.smt2 b/test/regress/regress0/strings/bug799-min.smt2
new file mode 100644 (file)
index 0000000..06acffc
--- /dev/null
@@ -0,0 +1,18 @@
+; COMMAND-LINE: --incremental --strings-exp
+; EXPECT: sat
+(set-logic ALL)
+(set-info :status sat)
+
+(declare-fun u () String)
+(declare-fun s () String)
+
+(assert (= (str.len u) 9))
+(assert (= (str.at u 1) s))
+(assert (= (str.at u 2) "4"))
+(assert (= (str.at u 7) "5"))
+(assert (= (str.at u 8) "6"))
+
+(push 1)
+(assert (str.in.re s (re.range "0" "3")))
+
+(check-sat)