Skip to content

Commit 9f4179f

Browse files
committed
Fixed checking of not contains axioms
Previously, the Skolem form the not contains axioms was checked by negating it with the Skolem function for the existential still being used. This is logically incorrect and has been fixed. In the negation of the not contains axiom (whence the existential becomes a universal qunatifier), we expand the universal as a conjunction. Additionally, `string_refinement::get` did not properly get refined strings, which it does now.
1 parent 7b5fb34 commit 9f4179f

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

src/solvers/refinement/string_refinement.cpp

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,12 +1023,10 @@ void string_refinementt::substitute_array_access(exprt &expr) const
10231023
/// \pre Symbols other than the universal variable should have been replaced by
10241024
/// their valuation in the current model.
10251025
/// \param axiom: the not_contains constraint to add the negation of
1026-
/// \param val: the existential witness for the axiom
10271026
/// \param univ_var: the universal variable for the negation of the axiom
10281027
/// \return: the negation of the axiom under the current evaluation
10291028
exprt string_refinementt::negation_of_not_contains_constraint(
10301029
const string_not_contains_constraintt &axiom,
1031-
const exprt &val,
10321030
const symbol_exprt &univ_var)
10331031
{
10341032
exprt lbu=axiom.univ_lower_bound();
@@ -1040,34 +1038,47 @@ exprt string_refinementt::negation_of_not_contains_constraint(
10401038
to_integer(to_constant_expr(ubu), ub_int);
10411039
if(ub_int<=lb_int)
10421040
{
1043-
debug() << "empty constraint with current model" << eom;
1041+
debug() << "(string_refinement::check_axioms) empty constraint with "
1042+
<< "current model, adding false" << eom;
10441043
return false_exprt();
10451044
}
10461045
}
10471046

10481047
exprt lbe=axiom.exists_lower_bound();
10491048
exprt ube=axiom.exists_upper_bound();
10501049

1050+
INVARIANT(
1051+
lbe.id()==ID_constant && ube.id()==ID_constant,
1052+
string_refinement_invariantt("please"));
1053+
1054+
mp_integer lbe_int, ube_int;
1055+
to_integer(to_constant_expr(lbe), lbe_int);
1056+
to_integer(to_constant_expr(ube), ube_int);
1057+
10511058
if(axiom.premise()==false_exprt())
10521059
{
1053-
debug() << "(string_refinement::check_axioms) adding false" << eom;
1060+
debug() << "(string_refinement::check_axioms) false premise, adding false"
1061+
<< eom;
10541062
return false_exprt();
10551063
}
10561064

1057-
// Witness is the Skolem function for the existential, which we evaluate at
1058-
// univ_var.
10591065
and_exprt univ_bounds(
10601066
binary_relation_exprt(lbu, ID_le, univ_var),
10611067
binary_relation_exprt(ubu, ID_gt, univ_var));
1062-
and_exprt exists_bounds(
1063-
binary_relation_exprt(lbe, ID_le, val),
1064-
binary_relation_exprt(ube, ID_gt, val));
1065-
equal_exprt equal_chars(
1066-
axiom.s0()[plus_exprt(univ_var, val)],
1067-
axiom.s1()[val]);
1068-
and_exprt negaxiom(univ_bounds, axiom.premise(), exists_bounds, equal_chars);
1069-
1070-
debug() << "(sr::check_axioms) negated not_contains axiom: "
1068+
1069+
std::vector<exprt> conjuncts;
1070+
for(mp_integer i=lbe_int; i<ube_int; i=i+1)
1071+
{
1072+
const constant_exprt i_exprt=from_integer(i, univ_var.type());
1073+
const equal_exprt equal_chars(
1074+
axiom.s0()[plus_exprt(univ_var, i_exprt)],
1075+
axiom.s1()[i_exprt]);
1076+
conjuncts.push_back(equal_chars);
1077+
}
1078+
exprt equal_strings=conjunction(conjuncts);
1079+
and_exprt negaxiom(univ_bounds, axiom.premise(), equal_strings);
1080+
1081+
debug() << "(string_refinement::check_axioms) negated not_contains axiom: "
10711082
<< from_expr(ns, "", negaxiom) << eom;
10721083
substitute_array_access(negaxiom);
10731084
return negaxiom;
@@ -1093,21 +1104,23 @@ exprt string_refinementt::negation_of_constraint(
10931104
to_integer(to_constant_expr(ub), ub_int);
10941105
if(ub_int<=lb_int)
10951106
{
1096-
debug() << "empty constraint with current model" << eom;
1107+
debug() << "(string_refinement::check_axioms) empty constraint with "
1108+
<< "current model, adding false" << eom;
10971109
return false_exprt();
10981110
}
10991111
}
11001112

11011113
if(axiom.premise()==false_exprt())
11021114
{
1103-
debug() << "(string_refinement::check_axioms) adding false" << eom;
1115+
debug() << "(string_refinement::check_axioms) false premise, adding false"
1116+
<< eom;
11041117
return false_exprt();
11051118
}
11061119

11071120
and_exprt premise(axiom.premise(), axiom.univ_within_bounds());
11081121
and_exprt negaxiom(premise, not_exprt(axiom.body()));
11091122

1110-
debug() << "(sr::check_axioms) negated axiom: "
1123+
debug() << "(string_refinement::check_axioms) negated universal axiom: "
11111124
<< from_expr(ns, "", negaxiom) << eom;
11121125
substitute_array_access(negaxiom);
11131126
return negaxiom;
@@ -1172,8 +1185,6 @@ bool string_refinementt::check_axioms()
11721185

11731186
symbol_exprt univ_var=generator.fresh_univ_index(
11741187
"not_contains_univ_var", nc_axiom.s0().length().type());
1175-
exprt wit=generator.get_witness_of(nc_axiom, univ_var);
1176-
exprt val=get(wit);
11771188
const string_not_contains_constraintt nc_axiom_in_model(
11781189
get(univ_bound_inf),
11791190
get(univ_bound_sup),
@@ -1184,7 +1195,7 @@ bool string_refinementt::check_axioms()
11841195
to_string_expr(get(s1)));
11851196

11861197
const exprt negaxiom=negation_of_not_contains_constraint(
1187-
nc_axiom_in_model, val, univ_var);
1198+
nc_axiom_in_model, univ_var);
11881199
exprt witness;
11891200

11901201
bool is_sat=is_axiom_sat(negaxiom, univ_var, witness);
@@ -1741,6 +1752,18 @@ exprt string_refinementt::get(const exprt &expr) const
17411752
if(it!=found_length.end())
17421753
return get_array(ecopy, it->second);
17431754
}
1755+
else if(refined_string_typet::is_refined_string_type(ecopy.type()) &&
1756+
ecopy.id()==ID_struct)
1757+
{
1758+
string_exprt ecopy2=to_string_expr(ecopy);
1759+
const exprt &econtent=ecopy2.content();
1760+
const exprt &elength=ecopy2.length();
1761+
1762+
exprt len=supert::get(elength);
1763+
len=simplify_expr(len, ns);
1764+
const exprt arr=get_array(econtent, len);
1765+
ecopy=string_exprt(len, arr, ecopy.type());
1766+
}
17441767

17451768
ecopy=supert::get(ecopy);
17461769

@@ -1772,6 +1795,7 @@ bool string_refinementt::is_axiom_sat(
17721795
}
17731796
case decision_proceduret::resultt::D_UNSATISFIABLE:
17741797
return false;
1798+
case decision_proceduret::resultt::D_ERROR:
17751799
default:
17761800
INVARIANT(false, string_refinement_invariantt("failure in checking axiom"));
17771801
// To tell the compiler that the previous line bails

src/solvers/refinement/string_refinement.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ class string_refinementt: public bv_refinementt
120120
void add_instantiations();
121121
exprt negation_of_not_contains_constraint(
122122
const string_not_contains_constraintt &axiom,
123-
const exprt &val,
124123
const symbol_exprt &univ_var);
125124
exprt negation_of_constraint(const string_constraintt &axiom);
126125
void debug_model();

0 commit comments

Comments
 (0)