Skip to content

Commit 94df20e

Browse files
committed
Extended check_axioms for not_contains
Previously when checking if axioms were satisfied by the model returned after SAT, the check_axioms function would assume all not_contains axioms were violated. They are now actually checked.
1 parent a1c44e1 commit 94df20e

File tree

2 files changed

+117
-10
lines changed

2 files changed

+117
-10
lines changed

src/solvers/refinement/string_refinement.cpp

+114-10
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,70 @@ void string_refinementt::substitute_array_access(exprt &expr) const
923923
}
924924
}
925925

926+
/// negates the constraint and add it to the solver. the intended usage is to
927+
/// find an assignement of the universal variable that would violate the axiom,
928+
/// to avoid false positives the symbols other than the universal variable
929+
/// should have been replaced by there valuation in the current model
930+
/// \par parameters: a string constraint and a solver for non string expressions
931+
void string_refinementt::add_negation_of_not_contains_constraint_to_solver(
932+
const string_not_contains_constraintt &axiom, symbol_exprt &univ_var,
933+
exprt val, supert &solver)
934+
{
935+
exprt lbu=axiom.univ_lower_bound();
936+
exprt ubu=axiom.univ_upper_bound();
937+
if(lbu.id()==ID_constant && ubu.id()==ID_constant)
938+
{
939+
mp_integer lb_int, ub_int;
940+
to_integer(to_constant_expr(lbu), lb_int);
941+
to_integer(to_constant_expr(ubu), ub_int);
942+
if(ub_int<=lb_int)
943+
{
944+
debug() << "empty constraint with current model" << eom;
945+
solver << false_exprt();
946+
return;
947+
}
948+
}
949+
950+
exprt lbe=axiom.exists_lower_bound();
951+
exprt ube=axiom.exists_upper_bound();
952+
if(lbe.id()==ID_constant && ube.id()==ID_constant)
953+
{
954+
mp_integer lb_int, ub_int;
955+
to_integer(to_constant_expr(lbe), lb_int);
956+
to_integer(to_constant_expr(ube), ub_int);
957+
if(ub_int<=lb_int)
958+
{
959+
debug() << "empty constraint with current model" << eom;
960+
solver << false_exprt();
961+
return;
962+
}
963+
}
964+
965+
if(axiom.premise()==false_exprt())
966+
{
967+
debug() << "(string_refinement::check_axioms) adding false" << eom;
968+
solver << false_exprt();
969+
return;
970+
}
971+
972+
// Witness is the Skolem function for the existential, which we evaluate at
973+
// univ_var.
974+
and_exprt univ_bounds(
975+
binary_relation_exprt(lbu, ID_le, univ_var),
976+
binary_relation_exprt(ubu, ID_gt, univ_var));
977+
and_exprt exists_bounds(
978+
binary_relation_exprt(lbu, ID_le, val),
979+
binary_relation_exprt(ubu, ID_gt, val));
980+
equal_exprt equal_chars(
981+
axiom.s0()[plus_exprt(univ_var, val)],
982+
axiom.s1()[val]);
983+
and_exprt negaxiom(univ_bounds, axiom.premise(), exists_bounds, equal_chars);
984+
985+
debug() << "(sr::check_axioms) negated axiom: " << from_expr(ns, "", negaxiom) << eom;
986+
substitute_array_access(negaxiom);
987+
solver << negaxiom;
988+
}
989+
926990
/// negates the constraint and add it to the solver. the intended usage is to
927991
/// find an assignement of the universal variable that would violate the axiom,
928992
/// to avoid false positives the symbols other than the universal variable
@@ -1011,31 +1075,71 @@ bool string_refinementt::check_axioms()
10111075
}
10121076
}
10131077

1014-
// tells whether one of the not_contains constraint can be violated
1015-
bool violated_not_contains=false;
1078+
// Maps from indexes of violated not_contains axiom to a witness of violation
1079+
std::map<size_t, exprt> violated_not;
1080+
10161081
debug() << "there are " << not_contains_axioms.size()
10171082
<< " not_contains axioms" << eom;
1018-
1019-
for(auto nc_axiom : not_contains_axioms)
1083+
for(size_t i=0; i<not_contains_axioms.size(); i++)
10201084
{
1021-
typet index_type=nc_axiom.s0().length().type();
1022-
exprt zero=from_integer(0, index_type);
1023-
exprt witness=generator.get_witness_of(nc_axiom, zero);
1085+
const string_not_contains_constraintt &nc_axiom=not_contains_axioms[i];
1086+
exprt univ_bound_inf=nc_axiom.univ_lower_bound();
1087+
exprt univ_bound_sup=nc_axiom.univ_upper_bound();
1088+
exprt prem=nc_axiom.premise();
1089+
exprt exists_bound_inf=nc_axiom.exists_lower_bound();
1090+
exprt exists_bound_sup=nc_axiom.exists_upper_bound();
1091+
const string_exprt s0=nc_axiom.s0();
1092+
const string_exprt s1=nc_axiom.s1();
1093+
1094+
symbol_exprt univ_var=generator.fresh_symbol(
1095+
"not_contains_univ_var", nc_axiom.s0().length().type());
1096+
exprt witness=generator.get_witness_of(nc_axiom, univ_var);
10241097
exprt val=get(witness);
1025-
violated_not_contains=true;
1098+
string_not_contains_constraintt nc_axiom_in_model(
1099+
get(univ_bound_inf), get(univ_bound_sup), get(prem),
1100+
get(exists_bound_inf), get(exists_bound_sup),
1101+
to_string_expr(get(s0)), to_string_expr(get(s1)));
1102+
1103+
satcheck_no_simplifiert sat_check;
1104+
supert solver(ns, sat_check);
1105+
solver.set_ui(ui);
1106+
add_negation_of_not_contains_constraint_to_solver(
1107+
nc_axiom_in_model, univ_var, val, solver);
1108+
1109+
switch(solver())
1110+
{
1111+
case decision_proceduret::resultt::D_SATISFIABLE:
1112+
{
1113+
exprt val=solver.get(univ_var);
1114+
debug() << "string constraint can be violated for "
1115+
<< univ_var.get_identifier()
1116+
<< " = " << from_expr(ns, "", val) << eom;
1117+
violated_not[i]=val;
1118+
}
1119+
break;
1120+
case decision_proceduret::resultt::D_UNSATISFIABLE:
1121+
break;
1122+
default:
1123+
throw "failure in checking axiom";
1124+
}
10261125
}
10271126

1028-
if(violated.empty() && !violated_not_contains)
1127+
if(violated.empty() && violated_not.empty())
10291128
{
10301129
debug() << "no violated property" << eom;
10311130
return true;
10321131
}
10331132
else
10341133
{
1035-
debug() << violated.size() << " string axioms can be violated" << eom;
1134+
debug() << violated.size()
1135+
<< " universal string axioms can be violated" << eom;
1136+
debug() << violated_not.size()
1137+
<< " not_contains string axioms can be violated" << eom;
10361138

10371139
if(use_counter_example)
10381140
{
1141+
// TODO: add counter examples for not_contains?
1142+
10391143
// Checking if the current solution satisfies the constraints
10401144
for(const auto &v : violated)
10411145
{

src/solvers/refinement/string_refinement.h

+3
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ class string_refinementt: public bv_refinementt
121121
void set_to(const exprt &expr, bool value) override;
122122

123123
void add_instantiations();
124+
void add_negation_of_not_contains_constraint_to_solver(
125+
const string_not_contains_constraintt &axiom, symbol_exprt &univ_var,
126+
exprt val, supert &solver);
124127
void add_negation_of_constraint_to_solver(
125128
const string_constraintt &axiom, supert &solver);
126129
void fill_model();

0 commit comments

Comments
 (0)