mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 13:29:11 +00:00 
			
		
		
		
	
							parent
							
								
									8c5993d9a6
								
							
						
					
					
						commit
						9c3f0190f4
					
				
					 9 changed files with 272 additions and 310 deletions
				
			
		| 
						 | 
				
			
			@ -1013,9 +1013,9 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned lenA = 0, lenB = 0;
 | 
			
		||||
    bool lA = min_length(as.size(), as.c_ptr(), lenA);
 | 
			
		||||
    bool lA = min_length(as, lenA);
 | 
			
		||||
    if (lA) {
 | 
			
		||||
        min_length(bs.size(), bs.c_ptr(), lenB);
 | 
			
		||||
        min_length(bs, lenB);
 | 
			
		||||
        if (lenB > lenA) {
 | 
			
		||||
            result = m().mk_false();
 | 
			
		||||
            return BR_DONE;
 | 
			
		||||
| 
						 | 
				
			
			@ -1387,7 +1387,7 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu
 | 
			
		|||
    if (m_lhs.empty()) {
 | 
			
		||||
        unsigned len = 0;
 | 
			
		||||
        m_util.str.get_concat(b, m_lhs);
 | 
			
		||||
        min_length(m_lhs.size(), m_lhs.c_ptr(), len);
 | 
			
		||||
        min_length(m_lhs, len);
 | 
			
		||||
        if (len > 0) {
 | 
			
		||||
            result = a;
 | 
			
		||||
            return BR_DONE;
 | 
			
		||||
| 
						 | 
				
			
			@ -2191,13 +2191,12 @@ br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
 | 
			
		||||
    TRACE("seq", tout << mk_bounded_pp(l, m(), 2) << " = " << mk_bounded_pp(r, m(), 2) << "\n";);
 | 
			
		||||
    expr_ref_vector res(m());
 | 
			
		||||
    expr_ref_pair_vector new_eqs(m());
 | 
			
		||||
    bool changed = false;
 | 
			
		||||
    if (!reduce_eq(l, r, new_eqs, changed)) {
 | 
			
		||||
        result = m().mk_false();
 | 
			
		||||
        TRACE("seq", tout << result << "\n";);
 | 
			
		||||
        TRACE("seq_verbose", tout << result << "\n";);
 | 
			
		||||
        return BR_DONE;
 | 
			
		||||
    }
 | 
			
		||||
    if (!changed) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2207,24 +2206,33 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
 | 
			
		|||
        res.push_back(m().mk_eq(p.first, p.second));
 | 
			
		||||
    }
 | 
			
		||||
    result = mk_and(res);
 | 
			
		||||
    TRACE("seq", tout << result << "\n";);
 | 
			
		||||
    TRACE("seq_verbose", tout << result << "\n";);
 | 
			
		||||
    return BR_REWRITE3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) {
 | 
			
		||||
void seq_rewriter::remove_empty(expr_ref_vector& es) {
 | 
			
		||||
    unsigned j = 0;
 | 
			
		||||
    for (expr* e : es) {
 | 
			
		||||
        if (!m_util.str.is_empty(e))
 | 
			
		||||
            es[j++] = e;
 | 
			
		||||
    }
 | 
			
		||||
    es.shrink(j);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void seq_rewriter::remove_leading(unsigned n, expr_ref_vector& es) {
 | 
			
		||||
    SASSERT(n <= es.size());
 | 
			
		||||
    if (n == 0)
 | 
			
		||||
        return;
 | 
			
		||||
    for (unsigned i = n; i < es.size(); ++i) {
 | 
			
		||||
        es[i-n] = es.get(i);
 | 
			
		||||
    }
 | 
			
		||||
    es.shrink(es.size() - n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) {    
 | 
			
		||||
    expr* a, *b;    
 | 
			
		||||
    zstring s;
 | 
			
		||||
    bool lchange = false;
 | 
			
		||||
    SASSERT(new_eqs.empty());
 | 
			
		||||
    TRACE("seq_verbose", tout << ls << "\n"; tout << rs << "\n";);
 | 
			
		||||
    // solve from back
 | 
			
		||||
    zstring s, s1, s2;
 | 
			
		||||
    while (true) {
 | 
			
		||||
        while (!rs.empty() && m_util.str.is_empty(rs.back())) {
 | 
			
		||||
            rs.pop_back();
 | 
			
		||||
        }
 | 
			
		||||
        while (!ls.empty() && m_util.str.is_empty(ls.back())) {
 | 
			
		||||
            ls.pop_back();
 | 
			
		||||
        }
 | 
			
		||||
        if (ls.empty() || rs.empty()) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -2262,29 +2270,42 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
 | 
			
		|||
                rs[rs.size()-1] = s2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_util.str.is_string(l, s1) && m_util.str.is_string(r, s2)) {
 | 
			
		||||
            unsigned min_l = std::min(s1.length(), s2.length());
 | 
			
		||||
            for (unsigned i = 0; i < min_l; ++i) {
 | 
			
		||||
                if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            ls.pop_back();          
 | 
			
		||||
            rs.pop_back();
 | 
			
		||||
            if (min_l < s1.length()) {
 | 
			
		||||
                ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-min_l)));
 | 
			
		||||
            }
 | 
			
		||||
            if (min_l < s2.length()) {
 | 
			
		||||
                rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-min_l)));
 | 
			
		||||
            }        
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        change = true;
 | 
			
		||||
        lchange = true;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    // solve from front
 | 
			
		||||
bool seq_rewriter::reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) {    
 | 
			
		||||
    expr* a, *b;    
 | 
			
		||||
    zstring s, s1, s2;
 | 
			
		||||
    unsigned head1 = 0, head2 = 0;
 | 
			
		||||
    while (true) {
 | 
			
		||||
        while (head1 < ls.size() && m_util.str.is_empty(ls[head1].get())) {
 | 
			
		||||
            ++head1;
 | 
			
		||||
        }
 | 
			
		||||
        while (head2 < rs.size() && m_util.str.is_empty(rs[head2].get())) {
 | 
			
		||||
            ++head2;
 | 
			
		||||
        }
 | 
			
		||||
        if (head1 == ls.size() || head2 == rs.size()) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(head1 < ls.size() && head2 < rs.size());
 | 
			
		||||
 | 
			
		||||
        expr* l = ls[head1].get();
 | 
			
		||||
        expr* r = rs[head2].get();
 | 
			
		||||
        expr* l = ls.get(head1);
 | 
			
		||||
        expr* r = rs.get(head2);
 | 
			
		||||
        if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
 | 
			
		||||
            std::swap(l, r);
 | 
			
		||||
            ls.swap(rs);
 | 
			
		||||
| 
						 | 
				
			
			@ -2317,144 +2338,57 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
 | 
			
		|||
                rs[head2] = s2;
 | 
			
		||||
            }            
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_util.str.is_string(l, s1) &&
 | 
			
		||||
                 m_util.str.is_string(r, s2)) {
 | 
			
		||||
            TRACE("seq", tout << s1 << " - " << s2 << " " << s1.length() << " " << s2.length() << "\n";);
 | 
			
		||||
            unsigned min_l = std::min(s1.length(), s2.length());
 | 
			
		||||
            for (unsigned i = 0; i < min_l; ++i) {
 | 
			
		||||
                if (s1[i] != s2[i]) {
 | 
			
		||||
                    TRACE("seq", tout << "different at position " << i << " " << s1[i] << " " << s2[i] << "\n";);
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (min_l == s1.length()) {
 | 
			
		||||
                ++head1;            
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                ls[head1] = m_util.str.mk_string(s1.extract(min_l, s1.length()-min_l));
 | 
			
		||||
            }
 | 
			
		||||
            if (min_l == s2.length()) {
 | 
			
		||||
                ++head2;            
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                rs[head2] = m_util.str.mk_string(s2.extract(min_l, s2.length()-min_l));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        TRACE("seq_verbose", tout << ls << " == " << rs << "\n";);
 | 
			
		||||
       
 | 
			
		||||
        change = true;
 | 
			
		||||
        lchange = true;
 | 
			
		||||
    }
 | 
			
		||||
    // reduce strings
 | 
			
		||||
    zstring s1, s2;
 | 
			
		||||
    while (head1 < ls.size() && 
 | 
			
		||||
           head2 < rs.size() && 
 | 
			
		||||
           m_util.str.is_string(ls[head1].get(), s1) &&
 | 
			
		||||
           m_util.str.is_string(rs[head2].get(), s2)) {
 | 
			
		||||
        TRACE("seq", tout << s1 << " - " << s2 << " " << s1.length() << " " << s2.length() << "\n";);
 | 
			
		||||
        unsigned l = std::min(s1.length(), s2.length());
 | 
			
		||||
        for (unsigned i = 0; i < l; ++i) {
 | 
			
		||||
            if (s1[i] != s2[i]) {
 | 
			
		||||
                TRACE("seq", tout << "different at position " << i << " " << s1[i] << " " << s2[i] << "\n";);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (l == s1.length()) {
 | 
			
		||||
            ++head1;            
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            ls[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
 | 
			
		||||
        }
 | 
			
		||||
        if (l == s2.length()) {
 | 
			
		||||
            ++head2;            
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            rs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
 | 
			
		||||
        }
 | 
			
		||||
        TRACE("seq", tout << "change string\n";);
 | 
			
		||||
        change = true;
 | 
			
		||||
        lchange = true;
 | 
			
		||||
    }
 | 
			
		||||
    while (head1 < ls.size() && 
 | 
			
		||||
           head2 < rs.size() &&
 | 
			
		||||
           m_util.str.is_string(ls.back(), s1) &&
 | 
			
		||||
           m_util.str.is_string(rs.back(), s2)) {
 | 
			
		||||
        unsigned l = std::min(s1.length(), s2.length());
 | 
			
		||||
        for (unsigned i = 0; i < l; ++i) {
 | 
			
		||||
            if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ls.pop_back();          
 | 
			
		||||
        rs.pop_back();
 | 
			
		||||
        if (l < s1.length()) {
 | 
			
		||||
            ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
 | 
			
		||||
        }
 | 
			
		||||
        if (l < s2.length()) {
 | 
			
		||||
            rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
 | 
			
		||||
        }        
 | 
			
		||||
        TRACE("seq", tout << "change string back\n";);
 | 
			
		||||
        change = true;
 | 
			
		||||
        lchange = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_sat = true;
 | 
			
		||||
    unsigned szl = ls.size() - head1, szr = rs.size() - head2;
 | 
			
		||||
    expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2;
 | 
			
		||||
 | 
			
		||||
    if (solve_itos(szl, _ls, szr, _rs, new_eqs, is_sat)) {
 | 
			
		||||
        ls.reset(); rs.reset();
 | 
			
		||||
        change = true;
 | 
			
		||||
        return is_sat;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (length_constrained(szl, _ls, szr, _rs, new_eqs, is_sat)) {
 | 
			
		||||
        ls.reset(); rs.reset();
 | 
			
		||||
        change = true;
 | 
			
		||||
        return is_sat;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (szr == 0 && szl == 0) {
 | 
			
		||||
        ls.reset();
 | 
			
		||||
        rs.reset();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (szr == 0 && szl > 0) {
 | 
			
		||||
        std::swap(szr, szl);
 | 
			
		||||
        std::swap(_ls, _rs);
 | 
			
		||||
    }
 | 
			
		||||
    if (szl == 0 && szr > 0) {
 | 
			
		||||
        if (set_empty(szr, _rs, true, new_eqs)) {
 | 
			
		||||
            lchange |= szr > 1; 
 | 
			
		||||
            change  |= szr > 1;
 | 
			
		||||
            if (szr == 1 && !lchange) {
 | 
			
		||||
                new_eqs.reset();
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                ls.reset();        
 | 
			
		||||
                rs.reset();
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(szl > 0 && szr > 0);
 | 
			
		||||
 | 
			
		||||
    if (is_subsequence(szl, _ls, szr, _rs, new_eqs, is_sat)) {
 | 
			
		||||
        ls.reset(); rs.reset();
 | 
			
		||||
        change = true;
 | 
			
		||||
        return is_sat;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (lchange) {
 | 
			
		||||
        if (head1 > 0) {
 | 
			
		||||
            for (unsigned i = 0; i < szl; ++i) {
 | 
			
		||||
                ls[i] = ls[i + head1].get();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ls.shrink(szl);
 | 
			
		||||
        if (head2 > 0) {
 | 
			
		||||
            for (unsigned i = 0; i < szr; ++i) {
 | 
			
		||||
                rs[i] = rs[i + head2].get();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        rs.shrink(szr);
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(rs.empty() == ls.empty());
 | 
			
		||||
    change |= lchange;
 | 
			
		||||
    remove_leading(head1, ls);
 | 
			
		||||
    remove_leading(head2, rs);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void seq_rewriter::add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_pair_vector& eqs) {
 | 
			
		||||
    if (!ls.empty() || !rs.empty()) {
 | 
			
		||||
        sort * s = m().get_sort(ls.empty() ? rs[0] : ls[0]);
 | 
			
		||||
        eqs.push_back(m_util.str.mk_concat(ls, s), m_util.str.mk_concat(rs, s));
 | 
			
		||||
    }
 | 
			
		||||
/**
 | 
			
		||||
   \brief simplify equality ls = rs
 | 
			
		||||
   - New equalities are inserted into eqs.
 | 
			
		||||
   - Last remaining equalities that cannot be simplified further are kept in ls, rs
 | 
			
		||||
   - returns false if equality is unsatisfiable   
 | 
			
		||||
*/
 | 
			
		||||
bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change) {
 | 
			
		||||
    TRACE("seq_verbose", tout << ls << "\n"; tout << rs << "\n";);
 | 
			
		||||
    remove_empty(ls);
 | 
			
		||||
    remove_empty(rs);
 | 
			
		||||
    return 
 | 
			
		||||
        reduce_back(ls, rs, eqs, change) && 
 | 
			
		||||
        reduce_front(ls, rs, eqs, change) &&
 | 
			
		||||
        reduce_itos(ls, rs, eqs, change) &&
 | 
			
		||||
        reduce_by_length(ls, rs, eqs, change) &&
 | 
			
		||||
        reduce_subsequence(ls, rs, eqs, change); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bool& changed) {
 | 
			
		||||
    m_lhs.reset();
 | 
			
		||||
    m_rhs.reset();
 | 
			
		||||
| 
						 | 
				
			
			@ -2463,7 +2397,7 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bo
 | 
			
		|||
    bool change = false;
 | 
			
		||||
    if (reduce_eq(m_lhs, m_rhs, new_eqs, change)) {
 | 
			
		||||
        if (!change) {
 | 
			
		||||
            new_eqs.push_back(std::make_pair(l, r));
 | 
			
		||||
            new_eqs.push_back(l, r);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            add_seqs(m_lhs, m_rhs, new_eqs);
 | 
			
		||||
| 
						 | 
				
			
			@ -2477,6 +2411,14 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bo
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void seq_rewriter::add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_pair_vector& eqs) {
 | 
			
		||||
    if (!ls.empty() || !rs.empty()) {
 | 
			
		||||
        sort * s = m().get_sort(ls.empty() ? rs[0] : ls[0]);
 | 
			
		||||
        eqs.push_back(m_util.str.mk_concat(ls, s), m_util.str.mk_concat(rs, s));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) {
 | 
			
		||||
    m_lhs.reset();
 | 
			
		||||
    m_util.str.get_concat(a, m_lhs);
 | 
			
		||||
| 
						 | 
				
			
			@ -2524,18 +2466,22 @@ bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) {
 | 
			
		||||
    SASSERT(n > 0);
 | 
			
		||||
    ptr_vector<expr> bs;
 | 
			
		||||
    for (unsigned i = 0; i < n; ++i) {
 | 
			
		||||
        if (m_util.str.is_unit(as[i]) ||
 | 
			
		||||
            m_util.str.is_string(as[i])) {
 | 
			
		||||
            bs.push_back(as[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }    
 | 
			
		||||
    return m_util.str.mk_concat(bs.size(), bs.c_ptr(), m().get_sort(as[0]));    
 | 
			
		||||
expr* seq_rewriter::concat_non_empty(expr_ref_vector& es) {
 | 
			
		||||
    sort* s = m().get_sort(es.get(0));
 | 
			
		||||
    unsigned j = 0;
 | 
			
		||||
    for (expr* e : es) {
 | 
			
		||||
        if (m_util.str.is_unit(e) || m_util.str.is_string(e))
 | 
			
		||||
            es[j++] = e;
 | 
			
		||||
    }
 | 
			
		||||
    es.shrink(j);
 | 
			
		||||
    return m_util.str.mk_concat(es, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
  \brief assign the non-unit and non-string elements to the empty sequence.
 | 
			
		||||
  If all is true, then return false if there is a unit or non-empty substring.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs) {
 | 
			
		||||
    zstring s;
 | 
			
		||||
    expr* emp = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -2547,8 +2493,9 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pa
 | 
			
		|||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_util.str.is_string(es[i], s)) {
 | 
			
		||||
            if (s.length() == 0)
 | 
			
		||||
                continue;
 | 
			
		||||
            if (all) {
 | 
			
		||||
                SASSERT(s.length() > 0);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -2560,18 +2507,24 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pa
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) {
 | 
			
		||||
/***
 | 
			
		||||
    \brief extract the minimal length of the sequence.
 | 
			
		||||
    Return true if the minimal length is equal to the 
 | 
			
		||||
    maximal length (the sequence is bounded).
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) {
 | 
			
		||||
    zstring s;
 | 
			
		||||
    bool bounded = true;
 | 
			
		||||
    len = 0;
 | 
			
		||||
    for (unsigned i = 0; i < n; ++i) {
 | 
			
		||||
        if (m_util.str.is_unit(es[i])) {
 | 
			
		||||
    for (expr* e : es) {
 | 
			
		||||
        if (m_util.str.is_unit(e)) {
 | 
			
		||||
            ++len;
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_util.str.is_empty(es[i])) {
 | 
			
		||||
        else if (m_util.str.is_empty(e)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_util.str.is_string(es[i], s)) {
 | 
			
		||||
        else if (m_util.str.is_string(e, s)) {
 | 
			
		||||
            len += s.length();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
| 
						 | 
				
			
			@ -2599,28 +2552,29 @@ bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const {
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs, 
 | 
			
		||||
                              expr_ref_pair_vector& eqs, bool& is_sat) {
 | 
			
		||||
bool seq_rewriter::reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs,
 | 
			
		||||
                              expr_ref_pair_vector& eqs, bool& change) {
 | 
			
		||||
    expr* n = nullptr;
 | 
			
		||||
    is_sat = true;
 | 
			
		||||
    if (szl == 1 && m_util.str.is_itos(ls[0], n) &&
 | 
			
		||||
        solve_itos(n, szr, rs, eqs)) {
 | 
			
		||||
        return true;
 | 
			
		||||
    if (ls.size() == 1 && m_util.str.is_itos(ls.get(0), n) &&
 | 
			
		||||
        solve_itos(n, rs, eqs)) {
 | 
			
		||||
        ls.reset(); rs.reset();
 | 
			
		||||
        change = true;
 | 
			
		||||
    }
 | 
			
		||||
    if (szr == 1 && m_util.str.is_itos(rs[0], n) &&
 | 
			
		||||
        solve_itos(n, szl, ls, eqs)) {
 | 
			
		||||
        return true;
 | 
			
		||||
    else if (rs.size() == 1 && m_util.str.is_itos(rs.get(0), n) &&
 | 
			
		||||
        solve_itos(n, ls, eqs)) {
 | 
			
		||||
        ls.reset(); rs.reset();
 | 
			
		||||
        change = true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * itos(n) = <numeric string> -> n = numeric
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_pair_vector& eqs) {
 | 
			
		||||
bool seq_rewriter::solve_itos(expr* n, expr_ref_vector const& es, expr_ref_pair_vector& eqs) {
 | 
			
		||||
    zstring s;
 | 
			
		||||
    if (is_string(sz, es, s)) {
 | 
			
		||||
    if (is_string(es.size(), es.c_ptr(), s)) {
 | 
			
		||||
        std::string s1 = s.encode();
 | 
			
		||||
        rational r(s1.c_str());
 | 
			
		||||
        if (s1 == r.to_string()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2631,116 +2585,94 @@ bool seq_rewriter::solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_pa
 | 
			
		|||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr, expr* const* r, 
 | 
			
		||||
                                      expr_ref_pair_vector& eqs, bool& is_sat) {
 | 
			
		||||
    is_sat = true;
 | 
			
		||||
bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs,
 | 
			
		||||
                                    expr_ref_pair_vector& eqs, bool& change) {
 | 
			
		||||
 | 
			
		||||
    if (ls.empty() && rs.empty())
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    unsigned len1 = 0, len2 = 0;
 | 
			
		||||
    bool bounded1 = min_length(szl, l, len1);
 | 
			
		||||
    bool bounded2 = min_length(szr, r, len2);
 | 
			
		||||
    if (bounded1 && len1 < len2) {
 | 
			
		||||
        is_sat = false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (bounded2 && len2 < len1) {
 | 
			
		||||
        is_sat = false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    bool bounded1 = min_length(ls, len1);
 | 
			
		||||
    bool bounded2 = min_length(rs, len2);
 | 
			
		||||
    if (bounded1 && len1 < len2) 
 | 
			
		||||
        return false;
 | 
			
		||||
    if (bounded2 && len2 < len1) 
 | 
			
		||||
        return false;
 | 
			
		||||
    if (bounded1 && len1 == len2 && len1 > 0) {
 | 
			
		||||
        is_sat = set_empty(szr, r, false, eqs);
 | 
			
		||||
        if (is_sat) {
 | 
			
		||||
            eqs.push_back(concat_non_empty(szl, l), concat_non_empty(szr, r));
 | 
			
		||||
            //split_units(eqs);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
        change = true;
 | 
			
		||||
        if (!set_empty(rs.size(), rs.c_ptr(), false, eqs))
 | 
			
		||||
            return false;
 | 
			
		||||
        eqs.push_back(concat_non_empty(ls), concat_non_empty(rs));
 | 
			
		||||
        ls.reset(); 
 | 
			
		||||
        rs.reset();
 | 
			
		||||
    }
 | 
			
		||||
    if (bounded2 && len1 == len2 && len1 > 0) {
 | 
			
		||||
        if (is_sat) {
 | 
			
		||||
            eqs.push_back(concat_non_empty(szl, l), concat_non_empty(szr, r));
 | 
			
		||||
            //split_units(eqs);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    else if (bounded2 && len1 == len2 && len1 > 0) {
 | 
			
		||||
        change = true;
 | 
			
		||||
        if (!set_empty(ls.size(), ls.c_ptr(), false, eqs))
 | 
			
		||||
            return false;
 | 
			
		||||
        eqs.push_back(concat_non_empty(ls), concat_non_empty(rs));
 | 
			
		||||
        ls.reset(); 
 | 
			
		||||
        rs.reset();
 | 
			
		||||
    }    
 | 
			
		||||
    return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void seq_rewriter::split_units(expr_ref_pair_vector& eqs) {
 | 
			
		||||
    expr* a, *b, *a1, *b1, *a2, *b2;
 | 
			
		||||
    while (!eqs.empty()) {
 | 
			
		||||
        auto const& p = eqs.back();
 | 
			
		||||
        if (m_util.str.is_unit(p.first, a) &&
 | 
			
		||||
            m_util.str.is_unit(p.second, b)) {
 | 
			
		||||
            eqs[eqs.size()-1] = std::make_pair(a, b);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (m_util.str.is_concat(p.first, a, a2) && 
 | 
			
		||||
            m_util.str.is_unit(a, a1) && 
 | 
			
		||||
            m_util.str.is_concat(p.second, b, b2) &&
 | 
			
		||||
            m_util.str.is_unit(b, b1)) {
 | 
			
		||||
            expr_ref _pin_a(p.first, m()), _pin_b(p.second, m());
 | 
			
		||||
            eqs[eqs.size()-1] = std::make_pair(a1, b1);
 | 
			
		||||
            eqs.push_back(a2, b2);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::is_epsilon(expr* e) const {
 | 
			
		||||
    expr* e1;
 | 
			
		||||
    return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, expr* const* r, 
 | 
			
		||||
                                  expr_ref_pair_vector& eqs, bool& is_sat) {
 | 
			
		||||
    is_sat = true;
 | 
			
		||||
    if (szl == szr) return false;
 | 
			
		||||
    if (szr < szl) {
 | 
			
		||||
        std::swap(szl, szr);
 | 
			
		||||
        std::swap(l, r);
 | 
			
		||||
    }
 | 
			
		||||
bool seq_rewriter::reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change) {
 | 
			
		||||
    
 | 
			
		||||
    if (ls.size() > rs.size()) 
 | 
			
		||||
        ls.swap(rs);
 | 
			
		||||
 | 
			
		||||
    if (ls.size() == rs.size())
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    if (ls.empty() && rs.size() == 1)
 | 
			
		||||
        return true;
 | 
			
		||||
    
 | 
			
		||||
    uint_set rpos;
 | 
			
		||||
    for (unsigned i = 0; i < szl; ++i) {
 | 
			
		||||
        bool found = false;
 | 
			
		||||
    for (expr* x : ls) {
 | 
			
		||||
        unsigned j = 0;
 | 
			
		||||
        bool is_unit = m_util.str.is_unit(l[i]);
 | 
			
		||||
        for (; !found && j < szr; ++j) {
 | 
			
		||||
            found = !rpos.contains(j) && (l[i] == r[j] || (is_unit && m_util.str.is_unit(r[j])));
 | 
			
		||||
        bool is_unit = m_util.str.is_unit(x);
 | 
			
		||||
        for (expr* y : rs) {
 | 
			
		||||
            if (!rpos.contains(j) && (x == y || (is_unit && m_util.str.is_unit(y)))) {
 | 
			
		||||
                rpos.insert(j);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            ++j;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (!found) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(0 < j && j <= szr);
 | 
			
		||||
        rpos.insert(j-1);
 | 
			
		||||
        if (j == rs.size())
 | 
			
		||||
            return true;
 | 
			
		||||
    }
 | 
			
		||||
    // if we reach here, then every element of l is contained in r in some position.
 | 
			
		||||
    // or each non-unit in l is matched by a non-unit in r, and otherwise, the non-units match up.
 | 
			
		||||
    bool change = false;
 | 
			
		||||
    ptr_vector<expr> rs;
 | 
			
		||||
    for (unsigned j = 0; j < szr; ++j) {
 | 
			
		||||
        if (rpos.contains(j)) {
 | 
			
		||||
            rs.push_back(r[j]);
 | 
			
		||||
    unsigned i = 0, j = 0;
 | 
			
		||||
    for (expr* y : rs) {
 | 
			
		||||
        if (rpos.contains(i)) {
 | 
			
		||||
            rs[j++] = y;
 | 
			
		||||
        }
 | 
			
		||||
        else if (!set_empty(1, r + j, true, eqs)) {
 | 
			
		||||
            is_sat = false;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            change = true;
 | 
			
		||||
        else if (!set_empty(1, &y, true, eqs)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
    if (!change) {
 | 
			
		||||
        return false;
 | 
			
		||||
    if (j == rs.size()) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(szl == rs.size());
 | 
			
		||||
    if (szl > 0) {
 | 
			
		||||
        sort* srt = m().get_sort(l[0]);
 | 
			
		||||
        eqs.push_back(m_util.str.mk_concat(szl, l, srt),
 | 
			
		||||
                      m_util.str.mk_concat(szl, rs.c_ptr(), srt));
 | 
			
		||||
    change = true;
 | 
			
		||||
    rs.shrink(j);
 | 
			
		||||
    SASSERT(ls.size() == rs.size());
 | 
			
		||||
    if (!ls.empty()) {
 | 
			
		||||
        sort* srt = m().get_sort(ls.get(0));
 | 
			
		||||
        eqs.push_back(m_util.str.mk_concat(ls, srt),
 | 
			
		||||
                      m_util.str.mk_concat(rs, srt));
 | 
			
		||||
        ls.reset();
 | 
			
		||||
        rs.reset();
 | 
			
		||||
        TRACE("seq", tout << "subsequence " << eqs << "\n";);
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
} 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ Notes:
 | 
			
		|||
#define SEQ_REWRITER_H_
 | 
			
		||||
 | 
			
		||||
#include "ast/seq_decl_plugin.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include "ast/arith_decl_plugin.h"
 | 
			
		||||
#include "ast/rewriter/rewriter_types.h"
 | 
			
		||||
#include "util/ref_pair_vector.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +32,13 @@ Notes:
 | 
			
		|||
 | 
			
		||||
typedef ref_pair_vector<expr, ast_manager> expr_ref_pair_vector;
 | 
			
		||||
 | 
			
		||||
inline std::ostream& operator<<(std::ostream& out, expr_ref_pair_vector const& es) {
 | 
			
		||||
    for (auto const& p : es) {
 | 
			
		||||
        out << expr_ref(p.first, es.get_manager()) << "; " << expr_ref(p.second, es.get_manager()) << "\n";
 | 
			
		||||
    }
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class sym_expr {
 | 
			
		||||
    enum ty {
 | 
			
		||||
        t_char,
 | 
			
		||||
| 
						 | 
				
			
			@ -166,15 +174,12 @@ class seq_rewriter {
 | 
			
		|||
    bool sign_is_determined(expr* len, sign& s);
 | 
			
		||||
 | 
			
		||||
    bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs);
 | 
			
		||||
    bool is_subsequence(unsigned n, expr* const* l, unsigned m, expr* const* r, 
 | 
			
		||||
                        expr_ref_pair_vector& eqs, bool& is_sat);
 | 
			
		||||
    bool length_constrained(unsigned n, expr* const* l, unsigned m, expr* const* r, 
 | 
			
		||||
                        expr_ref_pair_vector& eqs, bool& is_sat);
 | 
			
		||||
    bool solve_itos(unsigned n, expr* const* l, unsigned m, expr* const* r, 
 | 
			
		||||
                    expr_ref_pair_vector& eqs, bool& is_sat);
 | 
			
		||||
    bool solve_itos(expr* n, unsigned sz, expr* const* es, expr_ref_pair_vector& eqs);
 | 
			
		||||
    bool min_length(unsigned n, expr* const* es, unsigned& len);
 | 
			
		||||
    expr* concat_non_empty(unsigned n, expr* const* es);
 | 
			
		||||
    bool reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change);
 | 
			
		||||
    bool reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change);
 | 
			
		||||
    bool reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change);
 | 
			
		||||
    bool solve_itos(expr* n, expr_ref_vector const& es, expr_ref_pair_vector& eqs);
 | 
			
		||||
    bool min_length(expr_ref_vector const& es, unsigned& len);
 | 
			
		||||
    expr* concat_non_empty(expr_ref_vector& es);
 | 
			
		||||
 | 
			
		||||
    bool is_string(unsigned n, expr* const* es, zstring& s) const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -182,10 +187,11 @@ class seq_rewriter {
 | 
			
		|||
    bool is_sequence(expr* e, expr_ref_vector& seq);
 | 
			
		||||
    bool is_sequence(eautomaton& aut, expr_ref_vector& seq);
 | 
			
		||||
    bool is_epsilon(expr* e) const;
 | 
			
		||||
    void split_units(expr_ref_pair_vector& eqs);
 | 
			
		||||
    bool get_lengths(expr* e, expr_ref_vector& lens, rational& pos);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    bool reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change);
 | 
			
		||||
    bool reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change);
 | 
			
		||||
    void remove_empty(expr_ref_vector& es);
 | 
			
		||||
    void remove_leading(unsigned n, expr_ref_vector& es);
 | 
			
		||||
 | 
			
		||||
public:    
 | 
			
		||||
    seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -403,7 +403,6 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
 | 
			
		|||
    if (is_sort_param(sP, idx)) {
 | 
			
		||||
        if (binding.size() <= idx) binding.resize(idx+1);
 | 
			
		||||
        if (binding[idx] && (binding[idx] != s)) return false;
 | 
			
		||||
        TRACE("seq_verbose", tout << "setting binding @ " << idx << " to " << mk_pp(s, *m_manager) << "\n";);
 | 
			
		||||
        binding[idx] = s;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -433,11 +432,6 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
 | 
			
		|||
void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
 | 
			
		||||
    ptr_vector<sort> binding;
 | 
			
		||||
    ast_manager& m = *m_manager;
 | 
			
		||||
    TRACE("seq_verbose",
 | 
			
		||||
          tout << sig.m_name << ": ";
 | 
			
		||||
          for (unsigned i = 0; i < dsz; ++i) tout << mk_pp(dom[i], m) << " ";
 | 
			
		||||
          if (range) tout << " range: " << mk_pp(range, m);
 | 
			
		||||
          tout << "\n";);
 | 
			
		||||
    if (dsz == 0) {
 | 
			
		||||
        std::ostringstream strm;
 | 
			
		||||
        strm << "Unexpected number of arguments to '" << sig.m_name << "' ";
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +460,6 @@ void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* do
 | 
			
		|||
    }
 | 
			
		||||
    range_out = apply_binding(binding, sig.m_range);
 | 
			
		||||
    SASSERT(range_out);
 | 
			
		||||
    TRACE("seq_verbose", tout << mk_pp(range_out, m) << "\n";);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,12 +29,7 @@ bool theory_seq::solve_nqs(unsigned i) {
 | 
			
		|||
    context & ctx = get_context();
 | 
			
		||||
    for (; !ctx.inconsistent() && i < m_nqs.size(); ++i) {
 | 
			
		||||
        if (solve_ne(i)) {
 | 
			
		||||
            if (i + 1 != m_nqs.size()) {
 | 
			
		||||
                ne n = m_nqs[m_nqs.size()-1];
 | 
			
		||||
                m_nqs.set(i, n);
 | 
			
		||||
                --i;
 | 
			
		||||
            }
 | 
			
		||||
            m_nqs.pop_back();
 | 
			
		||||
            m_nqs.erase_and_swap(i--);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return m_new_propagation || ctx.inconsistent();
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +95,7 @@ bool theory_seq::propagate_ne2lit(unsigned idx) {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (undef_lit == null_literal) {
 | 
			
		||||
        display_disequation(verbose_stream() << "conflict:", n) << "\n";
 | 
			
		||||
        dependency* dep = n.dep();
 | 
			
		||||
        dependency* dep1 = nullptr;
 | 
			
		||||
        if (explain_eq(n.l(), n.r(), dep1)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -166,12 +162,15 @@ bool theory_seq::reduce_ne(unsigned idx) {
 | 
			
		|||
        if (!canonize(p.first,  ls, deps, change)) return false;
 | 
			
		||||
        if (!canonize(p.second, rs, deps, change)) return false;
 | 
			
		||||
        new_deps = m_dm.mk_join(deps, new_deps);
 | 
			
		||||
        bool is_sat = m_seq_rewrite.reduce_eq(ls, rs, eqs, change);
 | 
			
		||||
 | 
			
		||||
        if (!m_seq_rewrite.reduce_eq(ls, rs, eqs, change)) {
 | 
			
		||||
            TRACE("seq", display_disequation(tout << "reduces to false: ", n);
 | 
			
		||||
                  tout << p.first << " -> " << ls << "\n";
 | 
			
		||||
                  tout << p.second << " -> " << rs << "\n";);
 | 
			
		||||
            
 | 
			
		||||
        TRACE("seq", display_disequation(tout << "reduced\n", n);
 | 
			
		||||
              tout << p.first << " -> " << ls << "\n";
 | 
			
		||||
              tout << p.second << " -> " << rs << "\n";
 | 
			
		||||
              tout << eqs << "\n";
 | 
			
		||||
              );
 | 
			
		||||
        
 | 
			
		||||
        if (!is_sat) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +192,9 @@ bool theory_seq::reduce_ne(unsigned idx) {
 | 
			
		|||
            new_eqs.push_back(decomposed_eq(ls, rs));
 | 
			
		||||
        }
 | 
			
		||||
        TRACE("seq",
 | 
			
		||||
              for (auto const& p : eqs) tout << mk_pp(p.first, m) << " != " << mk_pp(p.second, m) << "\n";
 | 
			
		||||
              tout << "num eqs: " << eqs.size() << "\n";
 | 
			
		||||
              tout << "num new eqs: " << new_eqs.size() << "\n";
 | 
			
		||||
              tout << eqs << "\n";
 | 
			
		||||
              for (auto const& p : new_eqs) tout << p.first << " != " << p.second << "\n";
 | 
			
		||||
              tout << p.first << " != " << p.second << "\n";);
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -225,11 +226,15 @@ bool theory_seq::reduce_ne(unsigned idx) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    TRACE("seq", display_disequation(tout << "updated: " << updated << "\n", n););
 | 
			
		||||
    TRACE("seq", display_disequation(tout << "updated: " << updated << "\n", n);
 | 
			
		||||
          
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
    if (updated) {
 | 
			
		||||
        m_nqs.set(idx, ne(n.l(), n.r(), new_eqs, new_lits, new_deps));
 | 
			
		||||
        TRACE("seq", display_disequation(tout << "updated: ", m_nqs[idx]););
 | 
			
		||||
        auto new_n(ne(n.l(), n.r(), new_eqs, new_lits, new_deps));
 | 
			
		||||
        m_nqs.set(idx, new_n);
 | 
			
		||||
        TRACE("seq", display_disequation(tout << "updated:\n", m_nqs[idx]););
 | 
			
		||||
        TRACE("seq", display_disequation(tout << "updated:\n", new_n););
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -168,7 +168,7 @@ expr_ref seq_skolem::mk_unit_inv(expr* n) {
 | 
			
		|||
    expr* u = nullptr;
 | 
			
		||||
    VERIFY(seq.str.is_unit(n, u));
 | 
			
		||||
    sort* s = m.get_sort(u);
 | 
			
		||||
    return mk(symbol("seq.unit-inv"), n, nullptr, nullptr, nullptr, s);
 | 
			
		||||
    return mk(symbol("seq.unit-inv"), n, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,6 +85,8 @@ namespace smt {
 | 
			
		|||
        bool is_skolem(symbol const& s, expr* e) const;
 | 
			
		||||
        bool is_skolem(expr* e) const { return seq.is_skolem(e); }
 | 
			
		||||
 | 
			
		||||
        bool is_unit_inv(expr* e) const { return is_skolem(symbol("seq.unit-inv"), e); }
 | 
			
		||||
        bool is_unit_inv(expr* e, expr*& u) const { return is_unit_inv(e) && (u = to_app(e)->get_arg(0), true); }
 | 
			
		||||
        bool is_tail(expr* e) const { return is_skolem(m_tail, e); }
 | 
			
		||||
        bool is_seq_first(expr* e) const { return is_skolem(m_seq_first, e); }
 | 
			
		||||
        bool is_indexof_left(expr* e) const { return is_skolem(m_indexof_left, e); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1761,6 +1761,19 @@ std::ostream& theory_seq::display_deps(std::ostream& out, literal_vector const&
 | 
			
		|||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::ostream& theory_seq::display_deps_smt2(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const {
 | 
			
		||||
    params_ref p;
 | 
			
		||||
    for (auto const& eq : eqs) {
 | 
			
		||||
        out << "  (= " << mk_pp(eq.first->get_owner(), m)
 | 
			
		||||
            << "\n     " << mk_pp(eq.second->get_owner(), m) 
 | 
			
		||||
            << ")\n";
 | 
			
		||||
    }
 | 
			
		||||
    for (literal l : lits) {
 | 
			
		||||
        get_context().display_literal_smt2(out, l) << "\n";
 | 
			
		||||
    }
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::ostream& theory_seq::display_lit(std::ostream& out, literal l) const {
 | 
			
		||||
    context& ctx = get_context();
 | 
			
		||||
    if (l == true_literal) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2181,6 +2194,12 @@ expr_ref theory_seq::elim_skolem(expr* e) {
 | 
			
		|||
            todo.pop_back();            
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (m_sk.is_unit_inv(a, x) && cache.contains(x) && m_util.str.is_unit(cache[x], y)) {
 | 
			
		||||
            result = y;
 | 
			
		||||
            cache.insert(a, result);
 | 
			
		||||
            todo.pop_back();
 | 
			
		||||
            continue;            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        args.reset();
 | 
			
		||||
        for (expr* arg : *to_app(a)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2219,7 +2238,7 @@ void theory_seq::validate_axiom(literal_vector const& lits) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void theory_seq::validate_conflict(enode_pair_vector const& eqs, literal_vector const& lits) {
 | 
			
		||||
    IF_VERBOSE(10, display_deps(verbose_stream() << "; conflict\n", lits, eqs));
 | 
			
		||||
    IF_VERBOSE(10, display_deps_smt2(verbose_stream() << "cn ", lits, eqs));
 | 
			
		||||
    if (get_context().get_fparams().m_seq_validate) {
 | 
			
		||||
        expr_ref_vector fmls(m);
 | 
			
		||||
        validate_fmls(eqs, lits, fmls);
 | 
			
		||||
| 
						 | 
				
			
			@ -2227,7 +2246,7 @@ void theory_seq::validate_conflict(enode_pair_vector const& eqs, literal_vector
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void theory_seq::validate_assign(literal lit, enode_pair_vector const& eqs, literal_vector const& lits) {
 | 
			
		||||
    IF_VERBOSE(10, display_deps(verbose_stream() << "; assign\n", lits, eqs); display_lit(verbose_stream(), ~lit) << "\n");
 | 
			
		||||
    IF_VERBOSE(10, display_deps_smt2(verbose_stream() << "eq ", lits, eqs); display_lit(verbose_stream(), ~lit) << "\n");
 | 
			
		||||
    if (get_context().get_fparams().m_seq_validate) {
 | 
			
		||||
        literal_vector _lits(lits);
 | 
			
		||||
        _lits.push_back(~lit);
 | 
			
		||||
| 
						 | 
				
			
			@ -2269,6 +2288,7 @@ void theory_seq::validate_fmls(enode_pair_vector const& eqs, literal_vector cons
 | 
			
		|||
    for (expr* f : fmls) {
 | 
			
		||||
        k.assert_expr(f);
 | 
			
		||||
    }
 | 
			
		||||
    IF_VERBOSE(0, verbose_stream() << "validate: " << fmls << "\n";);
 | 
			
		||||
    lbool r = k.check();
 | 
			
		||||
    if (r != l_false && !m.limit().get_cancel_flag()) {
 | 
			
		||||
        model_ref mdl;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -678,6 +678,7 @@ namespace smt {
 | 
			
		|||
        std::ostream& display_disequation(std::ostream& out, ne const& e) const;
 | 
			
		||||
        std::ostream& display_deps(std::ostream& out, dependency* deps) const;
 | 
			
		||||
        std::ostream& display_deps(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const;
 | 
			
		||||
        std::ostream& display_deps_smt2(std::ostream& out, literal_vector const& lits, enode_pair_vector const& eqs) const;
 | 
			
		||||
        std::ostream& display_nc(std::ostream& out, nc const& nc) const;
 | 
			
		||||
        std::ostream& display_lit(std::ostream& out, literal l) const;
 | 
			
		||||
    public:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,7 +103,10 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    ref_pair_vector_core& push_back(T * a, T* b) {
 | 
			
		||||
        return push_back(std::make_pair(a, b));
 | 
			
		||||
        inc_ref(a);
 | 
			
		||||
        inc_ref(b);
 | 
			
		||||
        m_nodes.push_back(elem_t(a, b));
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename M>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue