mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-03 21:09:11 +00:00 
			
		
		
		
	perf improvements by reordering variable branching #1676
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									da5486563d
								
							
						
					
					
						commit
						bfcea7a819
					
				
					 2 changed files with 44 additions and 27 deletions
				
			
		| 
						 | 
				
			
			@ -312,12 +312,7 @@ final_check_status theory_seq::final_check_eh() {
 | 
			
		|||
        TRACEFIN("branch_binary_variable");
 | 
			
		||||
        return FC_CONTINUE;
 | 
			
		||||
    }
 | 
			
		||||
    if (branch_ternary_variable1() || branch_ternary_variable2() || branch_quat_variable()) {
 | 
			
		||||
        ++m_stats.m_branch_variable;
 | 
			
		||||
        TRACEFIN("split_based_on_alignment");
 | 
			
		||||
        return FC_CONTINUE;
 | 
			
		||||
    }
 | 
			
		||||
    if (branch_variable_mb() || branch_variable()) {
 | 
			
		||||
    if (branch_variable()) {
 | 
			
		||||
        ++m_stats.m_branch_variable;
 | 
			
		||||
        TRACEFIN("branch_variable");
 | 
			
		||||
        return FC_CONTINUE;
 | 
			
		||||
| 
						 | 
				
			
			@ -387,7 +382,7 @@ bool theory_seq::branch_binary_variable(eq const& e) {
 | 
			
		|||
    
 | 
			
		||||
    rational lenX, lenY;
 | 
			
		||||
    context& ctx = get_context();
 | 
			
		||||
    if (branch_variable(e)) {
 | 
			
		||||
    if (branch_variable_eq(e)) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (!get_length(x, lenX)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -457,6 +452,9 @@ bool theory_seq::is_unit_eq(expr_ref_vector const& ls, expr_ref_vector const& rs
 | 
			
		|||
    if (ls.empty() || !is_var(ls[0])) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    //std::function<bool(expr*)> is_unit = [&](expr* elem) { return m_util.str.is_unit(elem); }
 | 
			
		||||
    //return rs.forall(is_unit);
 | 
			
		||||
 | 
			
		||||
    for (auto const& elem : rs) {
 | 
			
		||||
        if (!m_util.str.is_unit(elem)) {
 | 
			
		||||
            return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -502,10 +500,9 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool theory_seq::branch_ternary_variable1() {
 | 
			
		||||
 | 
			
		||||
    //std::function<bool(eq const& e)> branch = [&](eq const& e) { return branch_ternary_variable(e) || branch_ternary_variable2(e); };
 | 
			
		||||
    //return m_eqs.exists(branch);
 | 
			
		||||
    for (auto const& e : m_eqs) {
 | 
			
		||||
    int start = get_context().get_random_value();
 | 
			
		||||
    for (unsigned i = 0; i < m_eqs.size(); ++i) {
 | 
			
		||||
        eq const& e = m_eqs[(i + start) % m_eqs.size()];
 | 
			
		||||
        if (branch_ternary_variable(e) || branch_ternary_variable2(e)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -514,7 +511,9 @@ bool theory_seq::branch_ternary_variable1() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool theory_seq::branch_ternary_variable2() {
 | 
			
		||||
    for (auto const& e : m_eqs) {
 | 
			
		||||
    int start = get_context().get_random_value();
 | 
			
		||||
    for (unsigned i = 0; i < m_eqs.size(); ++i) {
 | 
			
		||||
        eq const& e = m_eqs[(i + start) % m_eqs.size()];
 | 
			
		||||
        if (branch_ternary_variable(e, true)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1339,6 +1338,20 @@ bool theory_seq::len_based_split(eq const& e) {
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
   \brief select branching on variable equality.
 | 
			
		||||
   preference mb > eq > ternary > quat
 | 
			
		||||
   this performs much better on #1628
 | 
			
		||||
*/
 | 
			
		||||
bool theory_seq::branch_variable() {
 | 
			
		||||
    if (branch_variable_mb()) return true;
 | 
			
		||||
    if (branch_variable_eq()) return true;
 | 
			
		||||
    if (branch_ternary_variable1()) return true;
 | 
			
		||||
    if (branch_ternary_variable2()) return true;
 | 
			
		||||
    if (branch_quat_variable()) return true;
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool theory_seq::branch_variable_mb() {
 | 
			
		||||
    bool change = false;
 | 
			
		||||
    for (auto const& e : m_eqs) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1517,7 +1530,7 @@ bool theory_seq::enforce_length(expr_ref_vector const& es, vector<rational> & le
 | 
			
		|||
    return all_have_length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool theory_seq::branch_variable() {
 | 
			
		||||
bool theory_seq::branch_variable_eq() {
 | 
			
		||||
    context& ctx = get_context();
 | 
			
		||||
    unsigned sz = m_eqs.size();
 | 
			
		||||
    int start = ctx.get_random_value();
 | 
			
		||||
| 
						 | 
				
			
			@ -1526,24 +1539,15 @@ bool theory_seq::branch_variable() {
 | 
			
		|||
        unsigned k = (i + start) % sz;
 | 
			
		||||
        eq const& e = m_eqs[k];
 | 
			
		||||
 | 
			
		||||
        if (branch_variable(e)) {
 | 
			
		||||
        if (branch_variable_eq(e)) {
 | 
			
		||||
            TRACE("seq", tout << "branch variable\n";);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
        if (!has_length(e.ls())) {
 | 
			
		||||
            enforce_length(e.ls());
 | 
			
		||||
        }
 | 
			
		||||
        if (!has_length(e.rs())) {
 | 
			
		||||
            enforce_length(e.rs());
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    return ctx.inconsistent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool theory_seq::branch_variable(eq const& e) {
 | 
			
		||||
bool theory_seq::branch_variable_eq(eq const& e) {
 | 
			
		||||
    unsigned id = e.id();
 | 
			
		||||
    unsigned s = find_branch_start(2*id);
 | 
			
		||||
    TRACE("seq", tout << s << " " << id << ": " << e.ls() << " = " << e.rs() << "\n";);
 | 
			
		||||
| 
						 | 
				
			
			@ -4450,6 +4454,7 @@ expr_ref theory_seq::add_elim_string_axiom(expr* n) {
 | 
			
		|||
    - len(str) = str.length()       if x = str
 | 
			
		||||
    - len(empty) = 0                if x = empty
 | 
			
		||||
    - len(int.to.str(i)) >= 1       if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|))
 | 
			
		||||
    - len(substr(s,i,l)) <= l       if x = substr(s,i,l)
 | 
			
		||||
    - len(x) >= 0                   otherwise
 | 
			
		||||
 */
 | 
			
		||||
void theory_seq::add_length_axiom(expr* n) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4467,8 +4472,13 @@ void theory_seq::add_length_axiom(expr* n) {
 | 
			
		|||
    }
 | 
			
		||||
    else if (m_util.str.is_itos(x)) {
 | 
			
		||||
        add_itos_length_axiom(n);
 | 
			
		||||
    }
 | 
			
		||||
    }   
 | 
			
		||||
    else {
 | 
			
		||||
        expr* s = nullptr, *i = nullptr, *l = nullptr;
 | 
			
		||||
        if (m_util.str.is_extract(x, s, i, l)) {
 | 
			
		||||
            literal len_le_l = mk_simplified_literal(m_autil.mk_ge(mk_sub(l, n), m_autil.mk_int(0)));
 | 
			
		||||
            add_axiom(len_le_l); 
 | 
			
		||||
        }
 | 
			
		||||
        add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
 | 
			
		||||
    }
 | 
			
		||||
    if (!ctx.at_base_level()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -5186,6 +5196,8 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
 | 
			
		|||
            f = mk_skolem(m_prefix, e1, e2);
 | 
			
		||||
            f = mk_concat(e1, f);
 | 
			
		||||
            propagate_eq(lit, f, e2, true);
 | 
			
		||||
            //literal len1_le_len2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e2), mk_len(e1)), m_autil.mk_int(0)));
 | 
			
		||||
            //add_axiom(~lit, len1_le_len2);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            propagate_not_prefix(e);
 | 
			
		||||
| 
						 | 
				
			
			@ -5196,6 +5208,8 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
 | 
			
		|||
            f = mk_skolem(m_suffix, e1, e2);
 | 
			
		||||
            f = mk_concat(f, e1);
 | 
			
		||||
            propagate_eq(lit, f, e2, true);
 | 
			
		||||
            //literal len1_le_len2 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e2), mk_len(e1)), m_autil.mk_int(0)));
 | 
			
		||||
            //add_axiom(~lit, len1_le_len2);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            propagate_not_suffix(e);
 | 
			
		||||
| 
						 | 
				
			
			@ -5222,6 +5236,8 @@ void theory_seq::assign_eh(bool_var v, bool is_true) {
 | 
			
		|||
            expr_ref f2 = mk_skolem(m_indexof_right, e1, e2);
 | 
			
		||||
            f = mk_concat(f1, e2, f2);
 | 
			
		||||
            propagate_eq(lit, f, e1, true);
 | 
			
		||||
            //literal len2_le_len1 = mk_simplified_literal(m_autil.mk_ge(mk_sub(mk_len(e1), mk_len(e2)), m_autil.mk_int(0)));
 | 
			
		||||
            //add_axiom(~lit, len2_le_len1);
 | 
			
		||||
        }
 | 
			
		||||
        else if (!canonizes(false, e)) {
 | 
			
		||||
            propagate_non_empty(lit, e2);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -420,12 +420,13 @@ namespace smt {
 | 
			
		|||
        bool reduce_length_eq();
 | 
			
		||||
        bool branch_unit_variable();     // branch on XYZ = abcdef
 | 
			
		||||
        bool branch_binary_variable();   // branch on abcX = Ydefg 
 | 
			
		||||
        bool branch_variable();          // branch on 
 | 
			
		||||
        bool branch_ternary_variable1(); // branch on XabcY = Zdefg or XabcY = defgZ
 | 
			
		||||
        bool branch_ternary_variable2(); // branch on XabcY = defgZmnpq
 | 
			
		||||
        bool branch_quat_variable();     // branch on XabcY = ZdefgT
 | 
			
		||||
        bool len_based_split();          // split based on len offset
 | 
			
		||||
        bool branch_variable_mb();       // branch on a variable, model based on length
 | 
			
		||||
        bool branch_variable();          // branch on a variable
 | 
			
		||||
        bool branch_variable_eq();       // branch on a variable, by an alignment among variable boundaries.
 | 
			
		||||
        bool is_solved(); 
 | 
			
		||||
        bool check_length_coherence();
 | 
			
		||||
        bool check_length_coherence0(expr* e);
 | 
			
		||||
| 
						 | 
				
			
			@ -433,7 +434,7 @@ namespace smt {
 | 
			
		|||
        bool fixed_length(bool is_zero = false);
 | 
			
		||||
        bool fixed_length(expr* e, bool is_zero);
 | 
			
		||||
        void branch_unit_variable(dependency* dep, expr* X, expr_ref_vector const& units);
 | 
			
		||||
        bool branch_variable(eq const& e);
 | 
			
		||||
        bool branch_variable_eq(eq const& e);
 | 
			
		||||
        bool branch_binary_variable(eq const& e);
 | 
			
		||||
        bool eq_unit(expr* const& l, expr* const &r) const;       
 | 
			
		||||
        unsigned_vector overlap(expr_ref_vector const& ls, expr_ref_vector const& rs);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue