mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	Merge branch 'develop' of github.com:mtrberzi/z3 into develop
This commit is contained in:
		
						commit
						dd03632f3d
					
				
					 2 changed files with 212 additions and 1 deletions
				
			
		|  | @ -40,6 +40,7 @@ theory_str::theory_str(ast_manager & m, theory_str_params const & params): | |||
|         opt_DisableIntegerTheoryIntegration(false), | ||||
|         opt_DeferEQCConsistencyCheck(false), | ||||
|         opt_CheckVariableScope(true), | ||||
|         opt_ConcatOverlapAvoid(true), | ||||
|         /* Internal setup */ | ||||
|         search_started(false), | ||||
|         m_autil(m), | ||||
|  | @ -2801,6 +2802,179 @@ void theory_str::simplify_concat_equality(expr * nn1, expr * nn2) { | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Returns true if attempting to process a concat equality between lhs and rhs | ||||
|  * will result in overlapping variables (false otherwise). | ||||
|  */ | ||||
| bool theory_str::will_result_in_overlap(expr * lhs, expr * rhs) { | ||||
|     ast_manager & m = get_manager(); | ||||
| 
 | ||||
|     expr_ref new_nn1(simplify_concat(lhs), m); | ||||
|     expr_ref new_nn2(simplify_concat(rhs), m); | ||||
|     app * a_new_nn1 = to_app(new_nn1); | ||||
|     app * a_new_nn2 = to_app(new_nn2); | ||||
| 
 | ||||
|     bool n1IsConcat = is_concat(a_new_nn1); | ||||
|     bool n2IsConcat = is_concat(a_new_nn2); | ||||
|     if (!n1IsConcat && !n2IsConcat) { | ||||
|         // we simplified both sides to non-concat expressions...
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     expr * v1_arg0 = a_new_nn1->get_arg(0); | ||||
|     expr * v1_arg1 = a_new_nn1->get_arg(1); | ||||
|     expr * v2_arg0 = a_new_nn2->get_arg(0); | ||||
|     expr * v2_arg1 = a_new_nn2->get_arg(1); | ||||
| 
 | ||||
|     TRACE("t_str_detail", tout << "checking whether " << mk_pp(new_nn1, m) << " and " << mk_pp(new_nn1, m) << " might overlap." << std::endl;); | ||||
| 
 | ||||
|     check_and_init_cut_var(v1_arg0); | ||||
|     check_and_init_cut_var(v1_arg1); | ||||
|     check_and_init_cut_var(v2_arg0); | ||||
|     check_and_init_cut_var(v2_arg1); | ||||
| 
 | ||||
|     //*************************************************************
 | ||||
|     // case 1: concat(x, y) = concat(m, n)
 | ||||
|     //*************************************************************
 | ||||
|     if (is_concat_eq_type1(new_nn1, new_nn2)) { | ||||
|         TRACE("t_str_detail", tout << "Type 1 check." << std::endl;); | ||||
|         expr * x = to_app(new_nn1)->get_arg(0); | ||||
|         expr * y = to_app(new_nn1)->get_arg(1); | ||||
|         expr * m = to_app(new_nn2)->get_arg(0); | ||||
|         expr * n = to_app(new_nn2)->get_arg(1); | ||||
| 
 | ||||
|         // TODO is it too slow to perform length checks here to avoid false positives?
 | ||||
| 
 | ||||
|         if (has_self_cut(m, y)) { | ||||
|             TRACE("t_str_detail", tout << "Possible overlap found" << std::endl; print_cut_var(m, tout); print_cut_var(y, tout);); | ||||
|             return true; | ||||
|         } else if (has_self_cut(x, n)) { | ||||
|             TRACE("t_str_detail", tout << "Possible overlap found" << std::endl; print_cut_var(x, tout); print_cut_var(n, tout);); | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //*************************************************************
 | ||||
|     // case 2: concat(x, y) = concat(m, "str")
 | ||||
|     //*************************************************************
 | ||||
|     if (is_concat_eq_type2(new_nn1, new_nn2)) { | ||||
|         expr * x = NULL; | ||||
|         expr * y = NULL; | ||||
|         expr * strAst = NULL; | ||||
|         expr * m = NULL; | ||||
| 
 | ||||
|         expr * v1_arg0 = to_app(new_nn1)->get_arg(0); | ||||
|         expr * v1_arg1 = to_app(new_nn1)->get_arg(1); | ||||
|         expr * v2_arg0 = to_app(new_nn2)->get_arg(0); | ||||
|         expr * v2_arg1 = to_app(new_nn2)->get_arg(1); | ||||
| 
 | ||||
|         if (m_strutil.is_string(v1_arg1) && !m_strutil.is_string(v2_arg1)) { | ||||
|             m = v1_arg0; | ||||
|             strAst = v1_arg1; | ||||
|             x = v2_arg0; | ||||
|             y = v2_arg1; | ||||
|         } else { | ||||
|             m = v2_arg0; | ||||
|             strAst = v2_arg1; | ||||
|             x = v1_arg0; | ||||
|             y = v1_arg1; | ||||
|         } | ||||
| 
 | ||||
|         if (has_self_cut(m, y)) { | ||||
|             TRACE("t_str_detail", tout << "Possible overlap found" << std::endl; print_cut_var(m, tout); print_cut_var(y, tout);); | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //*************************************************************
 | ||||
|     // case 3: concat(x, y) = concat("str", n)
 | ||||
|     //*************************************************************
 | ||||
|     if (is_concat_eq_type3(new_nn1, new_nn2)) { | ||||
|         expr * v1_arg0 = to_app(new_nn1)->get_arg(0); | ||||
|         expr * v1_arg1 = to_app(new_nn1)->get_arg(1); | ||||
|         expr * v2_arg0 = to_app(new_nn2)->get_arg(0); | ||||
|         expr * v2_arg1 = to_app(new_nn2)->get_arg(1); | ||||
| 
 | ||||
|         expr * x = NULL; | ||||
|         expr * y = NULL; | ||||
|         expr * strAst = NULL; | ||||
|         expr * n = NULL; | ||||
| 
 | ||||
|         if (m_strutil.is_string(v1_arg0) && !m_strutil.is_string(v2_arg0)) { | ||||
|             strAst = v1_arg0; | ||||
|             n = v1_arg1; | ||||
|             x = v2_arg0; | ||||
|             y = v2_arg1; | ||||
|         } else { | ||||
|             strAst = v2_arg0; | ||||
|             n = v2_arg1; | ||||
|             x = v1_arg0; | ||||
|             y = v1_arg1; | ||||
|         } | ||||
|         if (has_self_cut(x, n)) { | ||||
|             TRACE("t_str_detail", tout << "Possible overlap found" << std::endl; print_cut_var(x, tout); print_cut_var(n, tout);); | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //*************************************************************
 | ||||
|     //  case 4: concat("str1", y) = concat("str2", n)
 | ||||
|     //*************************************************************
 | ||||
|     if (is_concat_eq_type4(new_nn1, new_nn2)) { | ||||
|         // This case can never result in an overlap.
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     //*************************************************************
 | ||||
|     //  case 5: concat(x, "str1") = concat(m, "str2")
 | ||||
|     //*************************************************************
 | ||||
|     if (is_concat_eq_type5(new_nn1, new_nn2)) { | ||||
|         // This case can never result in an overlap.
 | ||||
|         return false; | ||||
|     } | ||||
|     //*************************************************************
 | ||||
|     //  case 6: concat("str1", y) = concat(m, "str2")
 | ||||
|     //*************************************************************
 | ||||
|     if (is_concat_eq_type6(new_nn1, new_nn2)) { | ||||
|         expr * v1_arg0 = to_app(new_nn1)->get_arg(0); | ||||
|         expr * v1_arg1 = to_app(new_nn1)->get_arg(1); | ||||
|         expr * v2_arg0 = to_app(new_nn2)->get_arg(0); | ||||
|         expr * v2_arg1 = to_app(new_nn2)->get_arg(1); | ||||
| 
 | ||||
|         expr * str1Ast = NULL; | ||||
|         expr * y = NULL; | ||||
|         expr * m = NULL; | ||||
|         expr * str2Ast = NULL; | ||||
| 
 | ||||
|         if (m_strutil.is_string(v1_arg0)) { | ||||
|             str1Ast = v1_arg0; | ||||
|             y = v1_arg1; | ||||
|             m = v2_arg0; | ||||
|             str2Ast = v2_arg1; | ||||
|         } else { | ||||
|             str1Ast = v2_arg0; | ||||
|             y = v2_arg1; | ||||
|             m = v1_arg0; | ||||
|             str2Ast = v1_arg1; | ||||
|         } | ||||
|         if (has_self_cut(m, y)) { | ||||
|             TRACE("t_str_detail", tout << "Possible overlap found" << std::endl; print_cut_var(m, tout); print_cut_var(y, tout);); | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     TRACE("t_str_detail", tout << "warning: unrecognized concat case" << std::endl;); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| /*************************************************************
 | ||||
|  * Type 1: concat(x, y) = concat(m, n) | ||||
|  *         x, y, m and n all variables | ||||
|  | @ -6629,7 +6803,33 @@ void theory_str::handle_equality(expr * lhs, expr * rhs) { | |||
|             } | ||||
|         } | ||||
|         if (hasCommon == 0) { | ||||
|             simplify_concat_equality(*(eqc_concat_lhs.begin()), *(eqc_concat_rhs.begin())); | ||||
|             if (opt_ConcatOverlapAvoid) { | ||||
|                 bool found = false; | ||||
|                 // check each pair and take the first ones that won't immediately overlap
 | ||||
|                 for (itor1 = eqc_concat_lhs.begin(); itor1 != eqc_concat_lhs.end() && !found; ++itor1) { | ||||
|                     expr * concat_lhs = *itor1; | ||||
|                     for (itor2 = eqc_concat_rhs.begin(); itor2 != eqc_concat_rhs.end() && !found; ++itor2) { | ||||
|                         expr * concat_rhs = *itor2; | ||||
|                         if (will_result_in_overlap(concat_lhs, concat_rhs)) { | ||||
|                             TRACE("t_str_detail", tout << "Concats " << mk_pp(concat_lhs, m) << " and " | ||||
|                                     << mk_pp(concat_rhs, m) << " will result in overlap; skipping." << std::endl;); | ||||
|                         } else { | ||||
|                             TRACE("t_str_detail", tout << "Concats " << mk_pp(concat_lhs, m) << " and " | ||||
|                                     << mk_pp(concat_rhs, m) << " won't overlap. Simplifying here." << std::endl;); | ||||
|                             simplify_concat_equality(concat_lhs, concat_rhs); | ||||
|                             found = true; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (!found) { | ||||
|                     TRACE("t_str_detail", tout << "All pairs of concats expected to overlap, falling back." << std::endl;); | ||||
|                     simplify_concat_equality(*(eqc_concat_lhs.begin()), *(eqc_concat_rhs.begin())); | ||||
|                 } | ||||
|             } else { | ||||
|                 // default behaviour
 | ||||
|                 simplify_concat_equality(*(eqc_concat_lhs.begin()), *(eqc_concat_rhs.begin())); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -180,6 +180,14 @@ namespace smt { | |||
|          */ | ||||
|         bool opt_CheckVariableScope; | ||||
| 
 | ||||
|         /*
 | ||||
|          * If ConcatOverlapAvoid is set to true, | ||||
|          * the check to simplify Concat = Concat in handle_equality() will | ||||
|          * avoid simplifying wrt. pairs of Concat terms that will immediately | ||||
|          * result in an overlap. (false = Z3str2 behaviour) | ||||
|          */ | ||||
|         bool opt_ConcatOverlapAvoid; | ||||
| 
 | ||||
|         bool search_started; | ||||
|         arith_util m_autil; | ||||
|         str_util m_strutil; | ||||
|  | @ -350,6 +358,9 @@ namespace smt { | |||
|         void add_cut_info_merge(expr * destNode, int slevel, expr * srcNode); | ||||
|         bool has_self_cut(expr * n1, expr * n2); | ||||
| 
 | ||||
|         // for ConcatOverlapAvoid
 | ||||
|         bool will_result_in_overlap(expr * lhs, expr * rhs); | ||||
| 
 | ||||
|         void track_variable_scope(expr * var); | ||||
|         app * mk_str_var(std::string name); | ||||
|         app * mk_int_var(std::string name); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue