mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	theory_str caching of all string constants
This commit is contained in:
		
							parent
							
								
									e85f9d33c4
								
							
						
					
					
						commit
						e5d3e425f1
					
				
					 2 changed files with 101 additions and 62 deletions
				
			
		| 
						 | 
				
			
			@ -56,6 +56,9 @@ theory_str::theory_str(ast_manager & m, theory_str_params const & params):
 | 
			
		|||
        loopDetected(false),
 | 
			
		||||
        contains_map(m),
 | 
			
		||||
        string_int_conversion_terms(m),
 | 
			
		||||
        totalCacheAccessCount(0),
 | 
			
		||||
        cacheHitCount(0),
 | 
			
		||||
        cacheMissCount(0),
 | 
			
		||||
        m_find(*this),
 | 
			
		||||
        m_trail_stack(*this)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -66,6 +69,34 @@ theory_str::~theory_str() {
 | 
			
		|||
    m_trail_stack.reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr * theory_str::mk_string(std::string str) {
 | 
			
		||||
    ++totalCacheAccessCount;
 | 
			
		||||
    expr * val;
 | 
			
		||||
    if (stringConstantCache.find(str, val)) {
 | 
			
		||||
        // cache hit
 | 
			
		||||
        ++cacheHitCount;
 | 
			
		||||
        TRACE("t_str_cache", tout << "cache hit: \"" << str << "\" ("
 | 
			
		||||
                << cacheHitCount << " hits, " << cacheMissCount << " misses out of "
 | 
			
		||||
                << totalCacheAccessCount << " accesses)" << std::endl;);
 | 
			
		||||
        return val;
 | 
			
		||||
    } else {
 | 
			
		||||
        // cache miss
 | 
			
		||||
        ++cacheMissCount;
 | 
			
		||||
        TRACE("t_str_cache", tout << "cache miss: \"" << str << "\" ("
 | 
			
		||||
                        << cacheHitCount << " hits, " << cacheMissCount << " misses out of "
 | 
			
		||||
                        << totalCacheAccessCount << " accesses)" << std::endl;);
 | 
			
		||||
        val = m_strutil.mk_string(str);
 | 
			
		||||
        m_trail.push_back(val);
 | 
			
		||||
        stringConstantCache.insert(str, val);
 | 
			
		||||
        return val;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr * theory_str::mk_string(const char * str) {
 | 
			
		||||
    std::string valStr(str);
 | 
			
		||||
    return mk_string(valStr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void theory_str::initialize_charset() {
 | 
			
		||||
	bool defaultCharset = true;
 | 
			
		||||
	if (defaultCharset) {
 | 
			
		||||
| 
						 | 
				
			
			@ -615,7 +646,7 @@ void theory_str::add_nonempty_constraint(expr * s) {
 | 
			
		|||
    context & ctx = get_context();
 | 
			
		||||
    ast_manager & m = get_manager();
 | 
			
		||||
 | 
			
		||||
    expr_ref ax1(m.mk_not(ctx.mk_eq_atom(s, m_strutil.mk_string(""))), m);
 | 
			
		||||
    expr_ref ax1(m.mk_not(ctx.mk_eq_atom(s, mk_string(""))), m);
 | 
			
		||||
    assert_axiom(ax1);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -685,7 +716,7 @@ app * theory_str::mk_unroll(expr * n, expr * bound) {
 | 
			
		|||
	m_trail.push_back(unrollFunc);
 | 
			
		||||
 | 
			
		||||
	expr_ref_vector items(m);
 | 
			
		||||
	items.push_back(ctx.mk_eq_atom(ctx.mk_eq_atom(bound, mk_int(0)), ctx.mk_eq_atom(unrollFunc, m_strutil.mk_string(""))));
 | 
			
		||||
	items.push_back(ctx.mk_eq_atom(ctx.mk_eq_atom(bound, mk_int(0)), ctx.mk_eq_atom(unrollFunc, mk_string(""))));
 | 
			
		||||
	items.push_back(m_autil.mk_ge(bound, mk_int(0)));
 | 
			
		||||
	items.push_back(m_autil.mk_ge(mk_strlen(unrollFunc), mk_int(0)));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -760,7 +791,7 @@ expr * theory_str::mk_concat_const_str(expr * n1, expr * n2) {
 | 
			
		|||
        m_strutil.is_string(v2, & n2_str_tmp);
 | 
			
		||||
        std::string n2_str(n2_str_tmp);
 | 
			
		||||
        std::string result = n1_str + n2_str;
 | 
			
		||||
        return m_strutil.mk_string(result);
 | 
			
		||||
        return mk_string(result);
 | 
			
		||||
    } else if (n1HasEqcValue && !n2HasEqcValue) {
 | 
			
		||||
        const char * n1_str_tmp;
 | 
			
		||||
        m_strutil.is_string(v1, & n1_str_tmp);
 | 
			
		||||
| 
						 | 
				
			
			@ -1013,7 +1044,7 @@ void theory_str::try_eval_concat(enode * cat) {
 | 
			
		|||
    }
 | 
			
		||||
    if (constOK) {
 | 
			
		||||
        TRACE("t_str_detail", tout << "flattened to \"" << flattenedString << "\"" << std::endl;);
 | 
			
		||||
        expr_ref constStr(m_strutil.mk_string(flattenedString), m);
 | 
			
		||||
        expr_ref constStr(mk_string(flattenedString), m);
 | 
			
		||||
        expr_ref axiom(ctx.mk_eq_atom(a_cat, constStr), m);
 | 
			
		||||
        assert_axiom(axiom);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1132,7 +1163,7 @@ void theory_str::instantiate_basic_string_axioms(enode * str) {
 | 
			
		|||
            SASSERT(lhs);
 | 
			
		||||
            // build RHS of iff
 | 
			
		||||
            expr_ref empty_str(m);
 | 
			
		||||
            empty_str = m_strutil.mk_string("");
 | 
			
		||||
            empty_str = mk_string("");
 | 
			
		||||
            SASSERT(empty_str);
 | 
			
		||||
            expr_ref rhs(m);
 | 
			
		||||
            rhs = ctx.mk_eq_atom(a_str, empty_str);
 | 
			
		||||
| 
						 | 
				
			
			@ -1203,7 +1234,7 @@ void theory_str::instantiate_axiom_CharAt(enode * e) {
 | 
			
		|||
    and_item.push_back(ctx.mk_eq_atom(mk_strlen(ts1), mk_int(1)));
 | 
			
		||||
 | 
			
		||||
    expr_ref thenBranch(m.mk_and(and_item.size(), and_item.c_ptr()), m);
 | 
			
		||||
    expr_ref elseBranch(ctx.mk_eq_atom(ts1, m_strutil.mk_string("")), m);
 | 
			
		||||
    expr_ref elseBranch(ctx.mk_eq_atom(ts1, mk_string("")), m);
 | 
			
		||||
 | 
			
		||||
    expr_ref axiom(m.mk_ite(cond, thenBranch, elseBranch), m);
 | 
			
		||||
    expr_ref reductionVar(ctx.mk_eq_atom(expr, ts1), m);
 | 
			
		||||
| 
						 | 
				
			
			@ -1644,7 +1675,7 @@ void theory_str::instantiate_axiom_str_to_int(enode * e) {
 | 
			
		|||
 | 
			
		||||
	{
 | 
			
		||||
		expr_ref lhs(ctx.mk_eq_atom(ex, m_autil.mk_numeral(rational::zero(), true)), m);
 | 
			
		||||
		expr_ref rhs(ctx.mk_eq_atom(S, m_strutil.mk_string("0")), m);
 | 
			
		||||
		expr_ref rhs(ctx.mk_eq_atom(S, mk_string("0")), m);
 | 
			
		||||
		expr_ref axiom2(ctx.mk_eq_atom(lhs, rhs), m);
 | 
			
		||||
		SASSERT(axiom2);
 | 
			
		||||
		assert_axiom(axiom2);
 | 
			
		||||
| 
						 | 
				
			
			@ -1656,7 +1687,7 @@ void theory_str::instantiate_axiom_str_to_int(enode * e) {
 | 
			
		|||
		expr_ref tl(mk_str_var("tl"), m);
 | 
			
		||||
		expr_ref conclusion1(ctx.mk_eq_atom(S, mk_concat(hd, tl)), m);
 | 
			
		||||
		expr_ref conclusion2(ctx.mk_eq_atom(mk_strlen(hd), m_autil.mk_numeral(rational::one(), true)), m);
 | 
			
		||||
		expr_ref conclusion3(m.mk_not(ctx.mk_eq_atom(hd, m_strutil.mk_string("0"))), m);
 | 
			
		||||
		expr_ref conclusion3(m.mk_not(ctx.mk_eq_atom(hd, mk_string("0"))), m);
 | 
			
		||||
		expr_ref conclusion(m.mk_and(conclusion1, conclusion2, conclusion3), m);
 | 
			
		||||
		SASSERT(premise);
 | 
			
		||||
		SASSERT(conclusion);
 | 
			
		||||
| 
						 | 
				
			
			@ -1681,7 +1712,7 @@ void theory_str::instantiate_axiom_int_to_str(enode * e) {
 | 
			
		|||
    expr * N = ex->get_arg(0);
 | 
			
		||||
    {
 | 
			
		||||
        expr_ref axiom1_lhs(m.mk_not(m_autil.mk_ge(N, m_autil.mk_numeral(rational::zero(), true))), m);
 | 
			
		||||
        expr_ref axiom1_rhs(ctx.mk_eq_atom(ex, m_strutil.mk_string("")), m);
 | 
			
		||||
        expr_ref axiom1_rhs(ctx.mk_eq_atom(ex, mk_string("")), m);
 | 
			
		||||
        expr_ref axiom1(ctx.mk_eq_atom(axiom1_lhs, axiom1_rhs), m);
 | 
			
		||||
        SASSERT(axiom1);
 | 
			
		||||
        assert_axiom(axiom1);
 | 
			
		||||
| 
						 | 
				
			
			@ -1766,7 +1797,7 @@ void theory_str::instantiate_axiom_RegexIn(enode * e) {
 | 
			
		|||
    	expr_ref unrollFunc(mk_unroll(regex1, unrollCount), m);
 | 
			
		||||
    	expr_ref_vector items(m);
 | 
			
		||||
    	items.push_back(ctx.mk_eq_atom(ex, ctx.mk_eq_atom(str, unrollFunc)));
 | 
			
		||||
    	items.push_back(ctx.mk_eq_atom(ctx.mk_eq_atom(unrollCount, mk_int(0)), ctx.mk_eq_atom(unrollFunc, m_strutil.mk_string(""))));
 | 
			
		||||
    	items.push_back(ctx.mk_eq_atom(ctx.mk_eq_atom(unrollCount, mk_int(0)), ctx.mk_eq_atom(unrollFunc, mk_string(""))));
 | 
			
		||||
    	expr_ref finalAxiom(mk_and(items), m);
 | 
			
		||||
    	SASSERT(finalAxiom);
 | 
			
		||||
    	assert_axiom(finalAxiom);
 | 
			
		||||
| 
						 | 
				
			
			@ -1947,7 +1978,7 @@ expr * theory_str::eval_concat(expr * n1, expr * n2) {
 | 
			
		|||
        std::string n1_str = m_strutil.get_string_constant_value(v1);
 | 
			
		||||
        std::string n2_str = m_strutil.get_string_constant_value(v2);
 | 
			
		||||
        std::string result = n1_str + n2_str;
 | 
			
		||||
        return m_strutil.mk_string(result);
 | 
			
		||||
        return mk_string(result);
 | 
			
		||||
    } else if (n1HasEqcValue && !n2HasEqcValue) {
 | 
			
		||||
        if (m_strutil.get_string_constant_value(v1) == "") {
 | 
			
		||||
            return n2;
 | 
			
		||||
| 
						 | 
				
			
			@ -2286,7 +2317,7 @@ expr * theory_str::simplify_concat(expr * node) {
 | 
			
		|||
        // no simplification possible
 | 
			
		||||
        return node;
 | 
			
		||||
    } else {
 | 
			
		||||
        expr * resultAst = m_strutil.mk_string("");
 | 
			
		||||
        expr * resultAst = mk_string("");
 | 
			
		||||
        for (unsigned i = 0; i < argVec.size(); ++i) {
 | 
			
		||||
            bool vArgHasEqcValue = false;
 | 
			
		||||
            expr * vArg = get_eqc_value(argVec[i], vArgHasEqcValue);
 | 
			
		||||
| 
						 | 
				
			
			@ -3377,9 +3408,9 @@ void theory_str::process_concat_eq_type2(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
	    std::string part1Str = strValue.substr(0, lenDelta.get_unsigned());
 | 
			
		||||
	    std::string part2Str = strValue.substr(lenDelta.get_unsigned(), strValue.length() - lenDelta.get_unsigned());
 | 
			
		||||
 | 
			
		||||
	    expr_ref prefixStr(m_strutil.mk_string(part1Str), mgr);
 | 
			
		||||
	    expr_ref prefixStr(mk_string(part1Str), mgr);
 | 
			
		||||
	    expr_ref x_concat(mk_concat(m, prefixStr), mgr);
 | 
			
		||||
	    expr_ref cropStr(m_strutil.mk_string(part2Str), mgr);
 | 
			
		||||
	    expr_ref cropStr(mk_string(part2Str), mgr);
 | 
			
		||||
 | 
			
		||||
	    if (can_two_nodes_eq(x, x_concat) && can_two_nodes_eq(y, cropStr)) {
 | 
			
		||||
	        expr_ref_vector r_items(mgr);
 | 
			
		||||
| 
						 | 
				
			
			@ -3436,9 +3467,9 @@ void theory_str::process_concat_eq_type2(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
		for (int i = 0; i <= (int)strValue.size(); ++i) {
 | 
			
		||||
			std::string part1Str = strValue.substr(0, i);
 | 
			
		||||
			std::string part2Str = strValue.substr(i, strValue.size() - i);
 | 
			
		||||
			expr_ref prefixStr(m_strutil.mk_string(part1Str), mgr);
 | 
			
		||||
			expr_ref prefixStr(mk_string(part1Str), mgr);
 | 
			
		||||
			expr_ref x_concat(mk_concat(m, prefixStr), mgr);
 | 
			
		||||
			expr_ref cropStr(m_strutil.mk_string(part2Str), mgr);
 | 
			
		||||
			expr_ref cropStr(mk_string(part2Str), mgr);
 | 
			
		||||
			if (can_two_nodes_eq(x, x_concat) && can_two_nodes_eq(y, cropStr)) {
 | 
			
		||||
				// break down option 2-2
 | 
			
		||||
			    expr_ref_vector and_item(mgr);
 | 
			
		||||
| 
						 | 
				
			
			@ -3630,8 +3661,8 @@ void theory_str::process_concat_eq_type3(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
        std::string prefixStr = strValue.substr(0, prefixLen.get_unsigned());
 | 
			
		||||
        rational str_sub_prefix = str_len - prefixLen;
 | 
			
		||||
        std::string suffixStr = strValue.substr(prefixLen.get_unsigned(), str_sub_prefix.get_unsigned());
 | 
			
		||||
        expr_ref prefixAst(m_strutil.mk_string(prefixStr), mgr);
 | 
			
		||||
        expr_ref suffixAst(m_strutil.mk_string(suffixStr), mgr);
 | 
			
		||||
        expr_ref prefixAst(mk_string(prefixStr), mgr);
 | 
			
		||||
        expr_ref suffixAst(mk_string(suffixStr), mgr);
 | 
			
		||||
        expr_ref ax_l(mgr.mk_and(litems.size(), litems.c_ptr()), mgr);
 | 
			
		||||
 | 
			
		||||
        expr_ref suf_n_concat(mk_concat(suffixAst, n), mgr);
 | 
			
		||||
| 
						 | 
				
			
			@ -3726,8 +3757,8 @@ void theory_str::process_concat_eq_type3(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
        for (int i = 0; i <= (int) strValue.size(); i++) {
 | 
			
		||||
            std::string part1Str = strValue.substr(0, i);
 | 
			
		||||
            std::string part2Str = strValue.substr(i, strValue.size() - i);
 | 
			
		||||
            expr_ref cropStr(m_strutil.mk_string(part1Str), mgr);
 | 
			
		||||
            expr_ref suffixStr(m_strutil.mk_string(part2Str), mgr);
 | 
			
		||||
            expr_ref cropStr(mk_string(part1Str), mgr);
 | 
			
		||||
            expr_ref suffixStr(mk_string(part2Str), mgr);
 | 
			
		||||
            expr_ref y_concat(mk_concat(suffixStr, n), mgr);
 | 
			
		||||
 | 
			
		||||
            if (can_two_nodes_eq(x, cropStr) && can_two_nodes_eq(y, y_concat)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3857,7 +3888,7 @@ void theory_str::process_concat_eq_type4(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
    } else {
 | 
			
		||||
        if (str1Len > str2Len) {
 | 
			
		||||
            std::string deltaStr = str1Value.substr(str2Len, str1Len - str2Len);
 | 
			
		||||
            expr_ref tmpAst(mk_concat(m_strutil.mk_string(deltaStr), y), mgr);
 | 
			
		||||
            expr_ref tmpAst(mk_concat(mk_string(deltaStr), y), mgr);
 | 
			
		||||
            if (!in_same_eqc(tmpAst, n)) {
 | 
			
		||||
                // break down option 4-1
 | 
			
		||||
                expr_ref implyR(ctx.mk_eq_atom(n, tmpAst), mgr);
 | 
			
		||||
| 
						 | 
				
			
			@ -3882,7 +3913,7 @@ void theory_str::process_concat_eq_type4(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            std::string deltaStr = str2Value.substr(str1Len, str2Len - str1Len);
 | 
			
		||||
            expr_ref tmpAst(mk_concat(m_strutil.mk_string(deltaStr), n), mgr);
 | 
			
		||||
            expr_ref tmpAst(mk_concat(mk_string(deltaStr), n), mgr);
 | 
			
		||||
            if (!in_same_eqc(y, tmpAst)) {
 | 
			
		||||
                //break down option 4-3
 | 
			
		||||
                expr_ref implyR(ctx.mk_eq_atom(y, tmpAst), mgr);
 | 
			
		||||
| 
						 | 
				
			
			@ -3960,7 +3991,7 @@ void theory_str::process_concat_eq_type5(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
    } else {
 | 
			
		||||
        if (str1Len > str2Len) {
 | 
			
		||||
            std::string deltaStr = str1Value.substr(0, str1Len - str2Len);
 | 
			
		||||
            expr_ref x_deltaStr(mk_concat(x, m_strutil.mk_string(deltaStr)), mgr);
 | 
			
		||||
            expr_ref x_deltaStr(mk_concat(x, mk_string(deltaStr)), mgr);
 | 
			
		||||
            if (!in_same_eqc(m, x_deltaStr)) {
 | 
			
		||||
                expr_ref implyR(ctx.mk_eq_atom(m, x_deltaStr), mgr);
 | 
			
		||||
                if (m_params.m_AssertStrongerArrangements) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3983,7 +4014,7 @@ void theory_str::process_concat_eq_type5(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            std::string deltaStr = str2Value.substr(0, str2Len - str1Len);
 | 
			
		||||
            expr_ref m_deltaStr(mk_concat(m, m_strutil.mk_string(deltaStr)), mgr);
 | 
			
		||||
            expr_ref m_deltaStr(mk_concat(m, mk_string(deltaStr)), mgr);
 | 
			
		||||
            if (!in_same_eqc(x, m_deltaStr)) {
 | 
			
		||||
                expr_ref implyR(ctx.mk_eq_atom(x, m_deltaStr), mgr);
 | 
			
		||||
                if (m_params.m_AssertStrongerArrangements) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4178,7 +4209,7 @@ void theory_str::process_concat_eq_type6(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
 | 
			
		||||
        expr_ref_vector and_item(mgr);
 | 
			
		||||
 | 
			
		||||
        expr_ref prefixAst(m_strutil.mk_string(prefix), mgr);
 | 
			
		||||
        expr_ref prefixAst(mk_string(prefix), mgr);
 | 
			
		||||
        expr_ref x_eq_prefix(ctx.mk_eq_atom(m, prefixAst), mgr);
 | 
			
		||||
        and_item.push_back(x_eq_prefix);
 | 
			
		||||
        pos += 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -4189,7 +4220,7 @@ void theory_str::process_concat_eq_type6(expr * concatAst1, expr * concatAst2) {
 | 
			
		|||
 | 
			
		||||
        // adding length constraint for _ = constStr seems slowing things down.
 | 
			
		||||
 | 
			
		||||
        expr_ref suffixAst(m_strutil.mk_string(suffix), mgr);
 | 
			
		||||
        expr_ref suffixAst(mk_string(suffix), mgr);
 | 
			
		||||
        expr_ref y_eq_suffix(ctx.mk_eq_atom(y, suffixAst), mgr);
 | 
			
		||||
        and_item.push_back(y_eq_suffix);
 | 
			
		||||
        pos += 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -4262,7 +4293,7 @@ void theory_str::process_concat_eq_unroll(expr * concat, expr * unroll) {
 | 
			
		|||
 | 
			
		||||
		expr_ref t2(mk_unroll_bound_var(), mgr);
 | 
			
		||||
		expr_ref t3(mk_unroll_bound_var(), mgr);
 | 
			
		||||
		expr_ref emptyStr(m_strutil.mk_string(""), mgr);
 | 
			
		||||
		expr_ref emptyStr(mk_string(""), mgr);
 | 
			
		||||
 | 
			
		||||
		expr_ref unroll1(mk_unroll(r1, t2), mgr);
 | 
			
		||||
		expr_ref unroll2(mk_unroll(r1, t3), mgr);
 | 
			
		||||
| 
						 | 
				
			
			@ -6093,7 +6124,7 @@ void theory_str::solve_concat_eq_str(expr * concat, expr * str) {
 | 
			
		|||
					assert_axiom(diseq);
 | 
			
		||||
					return;
 | 
			
		||||
				} else {
 | 
			
		||||
					expr_ref tmpStrConst(m_strutil.mk_string(firstPart), m);
 | 
			
		||||
					expr_ref tmpStrConst(mk_string(firstPart), m);
 | 
			
		||||
					expr_ref premise(ctx.mk_eq_atom(newConcat, str), m);
 | 
			
		||||
					expr_ref conclusion(ctx.mk_eq_atom(arg1, tmpStrConst), m);
 | 
			
		||||
					assert_implication(premise, conclusion);
 | 
			
		||||
| 
						 | 
				
			
			@ -6133,7 +6164,7 @@ void theory_str::solve_concat_eq_str(expr * concat, expr * str) {
 | 
			
		|||
					assert_axiom(diseq);
 | 
			
		||||
					return;
 | 
			
		||||
				} else {
 | 
			
		||||
					expr_ref tmpStrConst(m_strutil.mk_string(secondPart), m);
 | 
			
		||||
					expr_ref tmpStrConst(mk_string(secondPart), m);
 | 
			
		||||
					expr_ref premise(ctx.mk_eq_atom(newConcat, str), m);
 | 
			
		||||
					expr_ref conclusion(ctx.mk_eq_atom(arg2, tmpStrConst), m);
 | 
			
		||||
					assert_implication(premise, conclusion);
 | 
			
		||||
| 
						 | 
				
			
			@ -6200,8 +6231,8 @@ void theory_str::solve_concat_eq_str(expr * concat, expr * str) {
 | 
			
		|||
        		        return;
 | 
			
		||||
        		    }
 | 
			
		||||
        		    expr_ref_vector r_items(m);
 | 
			
		||||
        		    r_items.push_back(ctx.mk_eq_atom(arg1, m_strutil.mk_string(prefixStr)));
 | 
			
		||||
        		    r_items.push_back(ctx.mk_eq_atom(arg2, m_strutil.mk_string(suffixStr)));
 | 
			
		||||
        		    r_items.push_back(ctx.mk_eq_atom(arg1, mk_string(prefixStr)));
 | 
			
		||||
        		    r_items.push_back(ctx.mk_eq_atom(arg2, mk_string(suffixStr)));
 | 
			
		||||
        		    if (!arg1Len_exists) {
 | 
			
		||||
        		        r_items.push_back(ctx.mk_eq_atom(mk_strlen(arg1), mk_int(prefixStr.size())));
 | 
			
		||||
        		    }
 | 
			
		||||
| 
						 | 
				
			
			@ -6292,12 +6323,12 @@ void theory_str::solve_concat_eq_str(expr * concat, expr * str) {
 | 
			
		|||
        				    continue;
 | 
			
		||||
        				}
 | 
			
		||||
 | 
			
		||||
        				expr_ref prefixAst(m_strutil.mk_string(prefixStr), m);
 | 
			
		||||
        				expr_ref prefixAst(mk_string(prefixStr), m);
 | 
			
		||||
        				expr_ref arg1_eq (ctx.mk_eq_atom(arg1, prefixAst), m);
 | 
			
		||||
        				and_items.push_back(arg1_eq);
 | 
			
		||||
        				and_count += 1;
 | 
			
		||||
 | 
			
		||||
        				expr_ref suffixAst(m_strutil.mk_string(suffixStr), m);
 | 
			
		||||
        				expr_ref suffixAst(mk_string(suffixStr), m);
 | 
			
		||||
        				expr_ref arg2_eq (ctx.mk_eq_atom(arg2, suffixAst), m);
 | 
			
		||||
        				and_items.push_back(arg2_eq);
 | 
			
		||||
        				and_count += 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -6450,7 +6481,7 @@ void theory_str::handle_equality(expr * lhs, expr * rhs) {
 | 
			
		|||
        rational nn1Len, nn2Len;
 | 
			
		||||
        bool nn1Len_exists = get_len_value(lhs, nn1Len);
 | 
			
		||||
        bool nn2Len_exists = get_len_value(rhs, nn2Len);
 | 
			
		||||
        expr * emptyStr = m_strutil.mk_string("");
 | 
			
		||||
        expr * emptyStr = mk_string("");
 | 
			
		||||
 | 
			
		||||
        if (nn1Len_exists && nn1Len.is_zero()) {
 | 
			
		||||
            if (!in_same_eqc(lhs, emptyStr) && rhs != emptyStr) {
 | 
			
		||||
| 
						 | 
				
			
			@ -7853,7 +7884,7 @@ bool theory_str::finalcheck_str2int(app * a) {
 | 
			
		|||
		if (!Ival.is_minus_one()) {
 | 
			
		||||
			std::string Ival_str = Ival.to_string();
 | 
			
		||||
			expr_ref premise(ctx.mk_eq_atom(a, m_autil.mk_numeral(Ival, true)), m);
 | 
			
		||||
			expr_ref conclusion(ctx.mk_eq_atom(S, m_strutil.mk_string(Ival_str)), m);
 | 
			
		||||
			expr_ref conclusion(ctx.mk_eq_atom(S, mk_string(Ival_str)), m);
 | 
			
		||||
			expr_ref axiom(rewrite_implication(premise, conclusion), m);
 | 
			
		||||
			if (!string_int_axioms.contains(axiom)) {
 | 
			
		||||
				string_int_axioms.insert(axiom);
 | 
			
		||||
| 
						 | 
				
			
			@ -7907,7 +7938,7 @@ bool theory_str::finalcheck_int2str(app * a) {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (conversionOK) {
 | 
			
		||||
                expr_ref premise(ctx.mk_eq_atom(a, m_strutil.mk_string(Sval)), m);
 | 
			
		||||
                expr_ref premise(ctx.mk_eq_atom(a, mk_string(Sval)), m);
 | 
			
		||||
                expr_ref conclusion(ctx.mk_eq_atom(N, m_autil.mk_numeral(convertedRepresentation, true)), m);
 | 
			
		||||
                expr_ref axiom(rewrite_implication(premise, conclusion), m);
 | 
			
		||||
                if (!string_int_axioms.contains(axiom)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -7917,7 +7948,7 @@ bool theory_str::finalcheck_int2str(app * a) {
 | 
			
		|||
                    axiomAdd = true;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                expr_ref axiom(m.mk_not(ctx.mk_eq_atom(a, m_strutil.mk_string(Sval))), m);
 | 
			
		||||
                expr_ref axiom(m.mk_not(ctx.mk_eq_atom(a, mk_string(Sval))), m);
 | 
			
		||||
                // always assert this axiom because this is a conflict clause
 | 
			
		||||
                assert_axiom(axiom);
 | 
			
		||||
                axiomAdd = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -8036,7 +8067,7 @@ final_check_status theory_str::final_check_eh() {
 | 
			
		|||
    			expr_ref lhs1(ctx.mk_eq_atom(concat_lhs, concat_lhs_str), m);
 | 
			
		||||
    			expr_ref lhs2(ctx.mk_eq_atom(concat_rhs, concat_rhs_str), m);
 | 
			
		||||
    			expr_ref lhs(m.mk_and(lhs1, lhs2), m);
 | 
			
		||||
    			expr_ref rhs(ctx.mk_eq_atom(concat, m_strutil.mk_string(concatString)), m);
 | 
			
		||||
    			expr_ref rhs(ctx.mk_eq_atom(concat, mk_string(concatString)), m);
 | 
			
		||||
    			assert_implication(lhs, rhs);
 | 
			
		||||
    			backpropagation_occurred = true;
 | 
			
		||||
    		}
 | 
			
		||||
| 
						 | 
				
			
			@ -8130,7 +8161,7 @@ final_check_status theory_str::final_check_eh() {
 | 
			
		|||
            TRACE("t_str", tout << "Assigning decoy values to free internal variables." << std::endl;);
 | 
			
		||||
            for (std::set<expr*>::iterator it = unused_internal_variables.begin(); it != unused_internal_variables.end(); ++it) {
 | 
			
		||||
                expr * var = *it;
 | 
			
		||||
                expr_ref assignment(m.mk_eq(var, m_strutil.mk_string("**unused**")), m);
 | 
			
		||||
                expr_ref assignment(m.mk_eq(var, mk_string("**unused**")), m);
 | 
			
		||||
                assert_axiom(assignment);
 | 
			
		||||
            }
 | 
			
		||||
            return FC_CONTINUE;
 | 
			
		||||
| 
						 | 
				
			
			@ -8463,9 +8494,9 @@ expr * theory_str::gen_val_options(expr * freeVar, expr * len_indicator, expr *
 | 
			
		|||
 | 
			
		||||
	for (long long i = l; i < h; i++) {
 | 
			
		||||
		// TODO can we share the val_indicator constants with the length tester cache?
 | 
			
		||||
		orList.push_back(m.mk_eq(val_indicator, m_strutil.mk_string(longlong_to_string(i).c_str()) ));
 | 
			
		||||
		orList.push_back(m.mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()) ));
 | 
			
		||||
		if (m_params.m_AggressiveValueTesting) {
 | 
			
		||||
		    literal l = mk_eq(val_indicator, m_strutil.mk_string(longlong_to_string(i).c_str()), false);
 | 
			
		||||
		    literal l = mk_eq(val_indicator, mk_string(longlong_to_string(i).c_str()), false);
 | 
			
		||||
		    ctx.mark_as_relevant(l);
 | 
			
		||||
		    ctx.force_phase(l);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -8474,19 +8505,19 @@ expr * theory_str::gen_val_options(expr * freeVar, expr * len_indicator, expr *
 | 
			
		|||
		expr * strAst;
 | 
			
		||||
		if (m_params.m_UseFastValueTesterCache) {
 | 
			
		||||
			if (!valueTesterCache.find(aStr, strAst)) {
 | 
			
		||||
				strAst = m_strutil.mk_string(aStr);
 | 
			
		||||
				strAst = mk_string(aStr);
 | 
			
		||||
				valueTesterCache.insert(aStr, strAst);
 | 
			
		||||
				m_trail.push_back(strAst);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			strAst = m_strutil.mk_string(aStr);
 | 
			
		||||
			strAst = mk_string(aStr);
 | 
			
		||||
		}
 | 
			
		||||
		andList.push_back(m.mk_eq(orList[orList.size() - 1], m.mk_eq(freeVar, strAst)));
 | 
			
		||||
	}
 | 
			
		||||
	if (!coverAll) {
 | 
			
		||||
		orList.push_back(m.mk_eq(val_indicator, m_strutil.mk_string("more")));
 | 
			
		||||
		orList.push_back(m.mk_eq(val_indicator, mk_string("more")));
 | 
			
		||||
		if (m_params.m_AggressiveValueTesting) {
 | 
			
		||||
		    literal l = mk_eq(val_indicator, m_strutil.mk_string("more"), false);
 | 
			
		||||
		    literal l = mk_eq(val_indicator, mk_string("more"), false);
 | 
			
		||||
		    ctx.mark_as_relevant(l);
 | 
			
		||||
		    ctx.force_phase(~l);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -8513,11 +8544,11 @@ expr * theory_str::gen_val_options(expr * freeVar, expr * len_indicator, expr *
 | 
			
		|||
	// Should add ($$_len_x_j = 16) /\ ($$_val_x_16_i = "more")
 | 
			
		||||
	// ---------------------------------------
 | 
			
		||||
	andList.reset();
 | 
			
		||||
	andList.push_back(m.mk_eq(len_indicator, m_strutil.mk_string(lenStr.c_str())));
 | 
			
		||||
	andList.push_back(m.mk_eq(len_indicator, mk_string(lenStr.c_str())));
 | 
			
		||||
	for (int i = 0; i < tries; i++) {
 | 
			
		||||
		expr * vTester = fvar_valueTester_map[freeVar][len][i].second;
 | 
			
		||||
		if (vTester != val_indicator)
 | 
			
		||||
			andList.push_back(m.mk_eq(vTester, m_strutil.mk_string("more")));
 | 
			
		||||
			andList.push_back(m.mk_eq(vTester, mk_string("more")));
 | 
			
		||||
	}
 | 
			
		||||
	expr * assertL = NULL;
 | 
			
		||||
	if (andList.size() == 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -8772,7 +8803,7 @@ void theory_str::gen_assign_unroll_reg(std::set<expr*> & unrolls) {
 | 
			
		|||
 | 
			
		||||
				// option 0
 | 
			
		||||
				expr_ref op0(ctx.mk_eq_atom(cntInUnr, mk_int(0)), mgr);
 | 
			
		||||
				expr_ref ast1(ctx.mk_eq_atom(unrFunc, m_strutil.mk_string("")), mgr);
 | 
			
		||||
				expr_ref ast1(ctx.mk_eq_atom(unrFunc, mk_string("")), mgr);
 | 
			
		||||
				expr_ref ast2(ctx.mk_eq_atom(mk_strlen(unrFunc), mk_int(0)), mgr);
 | 
			
		||||
				expr_ref and1(mgr.mk_and(ast1, ast2), mgr);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8856,7 +8887,7 @@ expr * theory_str::gen_assign_unroll_Str2Reg(expr * n, std::set<expr*> & unrolls
 | 
			
		|||
		return gen_unroll_conditional_options(n, unrolls, lcmStr);
 | 
			
		||||
	} else {
 | 
			
		||||
		expr_ref implyL(mk_and(litems), mgr);
 | 
			
		||||
		expr_ref implyR(ctx.mk_eq_atom(n, m_strutil.mk_string("")), mgr);
 | 
			
		||||
		expr_ref implyR(ctx.mk_eq_atom(n, mk_string("")), mgr);
 | 
			
		||||
		// want to return (implyL -> implyR)
 | 
			
		||||
		expr * final_axiom = rewrite_implication(implyL, implyR);
 | 
			
		||||
		return final_axiom;
 | 
			
		||||
| 
						 | 
				
			
			@ -8869,7 +8900,7 @@ expr * theory_str::gen_unroll_conditional_options(expr * var, std::set<expr*> &
 | 
			
		|||
 | 
			
		||||
	int dist = opt_LCMUnrollStep;
 | 
			
		||||
	expr_ref_vector litems(mgr);
 | 
			
		||||
	expr_ref moreAst(m_strutil.mk_string("more"), mgr);
 | 
			
		||||
	expr_ref moreAst(mk_string("more"), mgr);
 | 
			
		||||
	for (std::set<expr*>::iterator itor = unrolls.begin(); itor != unrolls.end(); itor++) {
 | 
			
		||||
		expr_ref item(ctx.mk_eq_atom(var, *itor), mgr);
 | 
			
		||||
		TRACE("t_str_detail", tout << "considering unroll " << mk_pp(item, mgr) << std::endl;);
 | 
			
		||||
| 
						 | 
				
			
			@ -8972,10 +9003,10 @@ expr * theory_str::gen_unroll_assign(expr * var, std::string lcmStr, expr * test
 | 
			
		|||
 | 
			
		||||
	for (int i = l; i < h; i++) {
 | 
			
		||||
		std::string iStr = int_to_string(i);
 | 
			
		||||
		expr_ref testerEqAst(ctx.mk_eq_atom(testerVar, m_strutil.mk_string(iStr)), mgr);
 | 
			
		||||
		expr_ref testerEqAst(ctx.mk_eq_atom(testerVar, mk_string(iStr)), mgr);
 | 
			
		||||
		TRACE("t_str_detail", tout << "testerEqAst = " << mk_pp(testerEqAst, mgr) << std::endl;);
 | 
			
		||||
		if (m_params.m_AggressiveUnrollTesting) {
 | 
			
		||||
		    literal l = mk_eq(testerVar, m_strutil.mk_string(iStr), false);
 | 
			
		||||
		    literal l = mk_eq(testerVar, mk_string(iStr), false);
 | 
			
		||||
		    ctx.mark_as_relevant(l);
 | 
			
		||||
		    ctx.force_phase(l);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -8983,7 +9014,7 @@ expr * theory_str::gen_unroll_assign(expr * var, std::string lcmStr, expr * test
 | 
			
		|||
		orItems.push_back(testerEqAst);
 | 
			
		||||
		std::string unrollStrInstance = get_unrolled_string(lcmStr, i);
 | 
			
		||||
 | 
			
		||||
		expr_ref x1(ctx.mk_eq_atom(testerEqAst, ctx.mk_eq_atom(var, m_strutil.mk_string(unrollStrInstance))), mgr);
 | 
			
		||||
		expr_ref x1(ctx.mk_eq_atom(testerEqAst, ctx.mk_eq_atom(var, mk_string(unrollStrInstance))), mgr);
 | 
			
		||||
		TRACE("t_str_detail", tout << "x1 = " << mk_pp(x1, mgr) << std::endl;);
 | 
			
		||||
		andItems.push_back(x1);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8991,10 +9022,10 @@ expr * theory_str::gen_unroll_assign(expr * var, std::string lcmStr, expr * test
 | 
			
		|||
		TRACE("t_str_detail", tout << "x2 = " << mk_pp(x2, mgr) << std::endl;);
 | 
			
		||||
		andItems.push_back(x2);
 | 
			
		||||
	}
 | 
			
		||||
	expr_ref testerEqMore(ctx.mk_eq_atom(testerVar, m_strutil.mk_string("more")), mgr);
 | 
			
		||||
	expr_ref testerEqMore(ctx.mk_eq_atom(testerVar, mk_string("more")), mgr);
 | 
			
		||||
	TRACE("t_str_detail", tout << "testerEqMore = " << mk_pp(testerEqMore, mgr) << std::endl;);
 | 
			
		||||
	if (m_params.m_AggressiveUnrollTesting) {
 | 
			
		||||
	    literal l = mk_eq(testerVar, m_strutil.mk_string("more"), false);
 | 
			
		||||
	    literal l = mk_eq(testerVar, mk_string("more"), false);
 | 
			
		||||
	    ctx.mark_as_relevant(l);
 | 
			
		||||
	    ctx.force_phase(~l);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -9051,14 +9082,14 @@ expr * theory_str::gen_len_test_options(expr * freeVar, expr * indicator, int tr
 | 
			
		|||
	        } else {
 | 
			
		||||
	            // no match; create and insert
 | 
			
		||||
	            std::string i_str = int_to_string(i);
 | 
			
		||||
                expr_ref new_val(m_strutil.mk_string(i_str), m);
 | 
			
		||||
                expr_ref new_val(mk_string(i_str), m);
 | 
			
		||||
                lengthTesterCache.insert(ri, new_val);
 | 
			
		||||
                m_trail.push_back(new_val);
 | 
			
		||||
                str_indicator = expr_ref(new_val, m);
 | 
			
		||||
	        }
 | 
			
		||||
	    } else {
 | 
			
		||||
	        std::string i_str = int_to_string(i);
 | 
			
		||||
	        str_indicator = expr_ref(m_strutil.mk_string(i_str), m);
 | 
			
		||||
	        str_indicator = expr_ref(mk_string(i_str), m);
 | 
			
		||||
	    }
 | 
			
		||||
		expr_ref or_expr(ctx.mk_eq_atom(indicator, str_indicator), m);
 | 
			
		||||
		orList.push_back(or_expr);
 | 
			
		||||
| 
						 | 
				
			
			@ -9074,9 +9105,9 @@ expr * theory_str::gen_len_test_options(expr * freeVar, expr * indicator, int tr
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO cache mk_string("more")
 | 
			
		||||
	orList.push_back(m.mk_eq(indicator, m_strutil.mk_string("more")));
 | 
			
		||||
	orList.push_back(m.mk_eq(indicator, mk_string("more")));
 | 
			
		||||
	if (m_params.m_AggressiveLengthTesting) {
 | 
			
		||||
	    literal l = mk_eq(indicator, m_strutil.mk_string("more"), false);
 | 
			
		||||
	    literal l = mk_eq(indicator, mk_string("more"), false);
 | 
			
		||||
	    ctx.mark_as_relevant(l);
 | 
			
		||||
	    ctx.force_phase(~l);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -9104,7 +9135,7 @@ expr * theory_str::gen_len_test_options(expr * freeVar, expr * indicator, int tr
 | 
			
		|||
	int testerCount = tries - 1;
 | 
			
		||||
	if (testerCount > 0) {
 | 
			
		||||
	    expr_ref_vector and_items_LHS(m);
 | 
			
		||||
		expr_ref moreAst(m_strutil.mk_string("more"), m);
 | 
			
		||||
		expr_ref moreAst(mk_string("more"), m);
 | 
			
		||||
		for (int i = 0; i < testerCount; ++i) {
 | 
			
		||||
		    expr * indicator = fvar_lenTester_map[freeVar][i];
 | 
			
		||||
		    if (internal_variable_set.find(indicator) == internal_variable_set.end()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -9530,7 +9561,7 @@ app * theory_str::mk_value_helper(app * n) {
 | 
			
		|||
            std::string a0_s(a0_str);
 | 
			
		||||
            std::string a1_s(a1_str);
 | 
			
		||||
            std::string result = a0_s + a1_s;
 | 
			
		||||
            return m_strutil.mk_string(result);
 | 
			
		||||
            return to_app(mk_string(result));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // fallback path
 | 
			
		||||
| 
						 | 
				
			
			@ -9562,7 +9593,7 @@ model_value_proc * theory_str::mk_value(enode * n, model_generator & mg) {
 | 
			
		|||
        TRACE("t_str", tout << "WARNING: failed to find a concrete value, falling back" << std::endl;);
 | 
			
		||||
        // TODO make absolutely sure the reason we can't find a concrete value is because of an unassigned temporary
 | 
			
		||||
        // e.g. for an expression like (Concat X $$_str0)
 | 
			
		||||
        return alloc(expr_wrapper_proc, m_strutil.mk_string("**UNUSED**"));
 | 
			
		||||
        return alloc(expr_wrapper_proc, to_app(mk_string("**UNUSED**")));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -263,6 +263,11 @@ namespace smt {
 | 
			
		|||
        // used when opt_FastValueTesterCache is true
 | 
			
		||||
        string_map valueTesterCache;
 | 
			
		||||
 | 
			
		||||
        string_map stringConstantCache;
 | 
			
		||||
        unsigned long totalCacheAccessCount;
 | 
			
		||||
        unsigned long cacheHitCount;
 | 
			
		||||
        unsigned long cacheMissCount;
 | 
			
		||||
 | 
			
		||||
        // cache mapping each string S to Length(S)
 | 
			
		||||
        obj_map<expr, app*> length_ast_map;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -277,6 +282,9 @@ namespace smt {
 | 
			
		|||
        void assert_implication(expr * premise, expr * conclusion);
 | 
			
		||||
        expr * rewrite_implication(expr * premise, expr * conclusion);
 | 
			
		||||
 | 
			
		||||
        expr * mk_string(std::string str);
 | 
			
		||||
        expr * mk_string(const char * str);
 | 
			
		||||
 | 
			
		||||
        app * mk_strlen(expr * e);
 | 
			
		||||
        expr * mk_concat(expr * n1, expr * n2);
 | 
			
		||||
        expr * mk_concat_const_str(expr * n1, expr * n2);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue