Skip to content

Commit 561f38d

Browse files
Merge pull request #1215 from jasigal/test/string-refinement-not-contains-unit-tests#884
Unit tests for `solvers/refinement/string_constraint_instantiation.cpp:instantiate_not_contains`
2 parents e5c21c0 + f5ebce0 commit 561f38d

File tree

8 files changed

+635
-55
lines changed

8 files changed

+635
-55
lines changed

src/solvers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ SRC = $(BOOLEFORCE_SRC) \
171171
refinement/string_constraint_generator_testing.cpp \
172172
refinement/string_constraint_generator_transformation.cpp \
173173
refinement/string_constraint_generator_valueof.cpp \
174+
refinement/string_constraint_instantiation.cpp \
174175
sat/cnf.cpp \
175176
sat/cnf_clause_list.cpp \
176177
sat/dimacs_cnf.cpp \

src/solvers/refinement/string_constraint.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Author: Romain Brenguier, [email protected]
2424
#include <solvers/refinement/bv_refinement.h>
2525
#include <solvers/refinement/string_refinement_invariant.h>
2626
#include <util/refined_string_type.h>
27+
#include <util/string_expr.h>
2728
#include <langapi/language_util.h>
2829

2930
/*! \brief Universally quantified string constraint
@@ -138,12 +139,20 @@ extern inline string_constraintt &to_string_constraint(exprt &expr)
138139
return static_cast<string_constraintt &>(expr);
139140
}
140141

142+
/// Used for debug printing.
143+
/// \param [in] ns: namespace for `from_expr`
144+
/// \param [in] identifier: identifier for `from_expr`
145+
/// \param [in] expr: constraint to render
146+
/// \return rendered string
141147
inline static std::string from_expr(
142148
const namespacet &ns,
143149
const irep_idt &identifier,
144150
const string_constraintt &expr)
145151
{
146-
return from_expr(ns, identifier, expr.premise())+" => "+
152+
return "forall "+from_expr(ns, identifier, expr.univ_var())+" in ["+
153+
from_expr(ns, identifier, expr.lower_bound())+", "+
154+
from_expr(ns, identifier, expr.upper_bound())+"). "+
155+
from_expr(ns, identifier, expr.premise())+" => "+
147156
from_expr(ns, identifier, expr.body());
148157
}
149158

@@ -204,6 +213,26 @@ class string_not_contains_constraintt: public exprt
204213
}
205214
};
206215

216+
/// Used for debug printing.
217+
/// \param [in] ns: namespace for `from_expr`
218+
/// \param [in] identifier: identifier for `from_expr`
219+
/// \param [in] expr: constraint to render
220+
/// \return rendered string
221+
inline static std::string from_expr(
222+
const namespacet &ns,
223+
const irep_idt &identifier,
224+
const string_not_contains_constraintt &expr)
225+
{
226+
return "forall x in ["+
227+
from_expr(ns, identifier, expr.univ_lower_bound())+", "+
228+
from_expr(ns, identifier, expr.univ_upper_bound())+"). "+
229+
from_expr(ns, identifier, expr.premise())+" => ("+
230+
"exists y in ["+from_expr(ns, identifier, expr.exists_lower_bound())+", "+
231+
from_expr(ns, identifier, expr.exists_upper_bound())+"). "+
232+
from_expr(ns, identifier, expr.s0())+"[x+y] != "+
233+
from_expr(ns, identifier, expr.s1())+"[y])";
234+
}
235+
207236
inline const string_not_contains_constraintt
208237
&to_string_not_contains_constraint(const exprt &expr)
209238
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*******************************************************************\
2+
3+
Module: Defines functions related to string constraints.
4+
5+
Author: Jesse Sigal, [email protected]
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Defines related function for string constraints.
11+
12+
#include <solvers/refinement/string_constraint_instantiation.h>
13+
14+
#include <solvers/refinement/string_constraint.h>
15+
#include <solvers/refinement/string_constraint_generator.h>
16+
#include <solvers/refinement/string_refinement.h>
17+
18+
/// Instantiates a quantified formula representing `not_contains` by
19+
/// substituting the quantifiers and generating axioms.
20+
/// \related string_refinementt
21+
/// \param [in] axiom: the axiom to instantiate
22+
/// \param [in] index_set0: the index set for `axiom.s0()`
23+
/// \param [in] index_set1: the index set for `axiom.s1()`
24+
/// \param [in] generator: generator to be used to get `axiom`'s witness
25+
/// \return the lemmas produced through instantiation
26+
std::vector<exprt> instantiate_not_contains(
27+
const string_not_contains_constraintt &axiom,
28+
const std::set<exprt> &index_set0,
29+
const std::set<exprt> &index_set1,
30+
const string_constraint_generatort &generator)
31+
{
32+
std::vector<exprt> lemmas;
33+
34+
const string_exprt s0=to_string_expr(axiom.s0());
35+
const string_exprt s1=to_string_expr(axiom.s1());
36+
37+
for(const auto &i0 : index_set0)
38+
for(const auto &i1 : index_set1)
39+
{
40+
const minus_exprt val(i0, i1);
41+
const exprt witness=generator.get_witness_of(axiom, val);
42+
const and_exprt prem_and_is_witness(
43+
axiom.premise(),
44+
equal_exprt(witness, i1));
45+
46+
const not_exprt differ(equal_exprt(s0[i0], s1[i1]));
47+
const implies_exprt lemma(prem_and_is_witness, differ);
48+
lemmas.push_back(lemma);
49+
50+
// we put bounds on the witnesses:
51+
// 0 <= v <= |s0| - |s1| ==> 0 <= v+w[v] < |s0| && 0 <= w[v] < |s1|
52+
const exprt zero=from_integer(0, val.type());
53+
const binary_relation_exprt c1(zero, ID_le, plus_exprt(val, witness));
54+
const binary_relation_exprt c2(
55+
s0.length(), ID_gt, plus_exprt(val, witness));
56+
const binary_relation_exprt c3(s1.length(), ID_gt, witness);
57+
const binary_relation_exprt c4(zero, ID_le, witness);
58+
59+
const minus_exprt diff(s0.length(), s1.length());
60+
61+
const and_exprt premise(
62+
binary_relation_exprt(zero, ID_le, val),
63+
binary_relation_exprt(diff, ID_ge, val));
64+
const implies_exprt witness_bounds(
65+
premise,
66+
and_exprt(and_exprt(c1, c2), and_exprt(c3, c4)));
67+
lemmas.push_back(witness_bounds);
68+
}
69+
70+
return lemmas;
71+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*******************************************************************\
2+
3+
Module: Defines related function for string constraints.
4+
5+
Author: Jesse Sigal, [email protected]
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Defines related function for string constraints.
11+
12+
#ifndef CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_INSTANTIATION_H
13+
#define CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_INSTANTIATION_H
14+
15+
#include <solvers/refinement/string_constraint.h>
16+
#include <solvers/refinement/string_constraint_generator.h>
17+
18+
std::vector<exprt> instantiate_not_contains(
19+
const string_not_contains_constraintt &axiom,
20+
const std::set<exprt> &index_set0,
21+
const std::set<exprt> &index_set1,
22+
const string_constraint_generatort &generator);
23+
24+
#endif // CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_INSTANTIATION_H

src/solvers/refinement/string_refinement.cpp

Lines changed: 15 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Author: Alberto Griggio, [email protected]
2929
#include <util/simplify_expr.h>
3030
#include <solvers/sat/satcheck.h>
3131
#include <solvers/refinement/string_refinement_invariant.h>
32+
#include <solvers/refinement/string_constraint_instantiation.h>
3233
#include <langapi/language_util.h>
3334
#include <java_bytecode/java_types.h>
3435

@@ -606,8 +607,8 @@ decision_proceduret::resultt string_refinementt::dec_solve()
606607
for(unsigned i=0; i<not_contains_axioms.size(); i++)
607608
{
608609
debug()<< "constraint " << i << eom;
609-
std::list<exprt> lemmas;
610-
instantiate_not_contains(not_contains_axioms[i], lemmas);
610+
const std::vector<exprt> lemmas=
611+
instantiate_not_contains(not_contains_axioms[i]);
611612
for(const exprt &lemma : lemmas)
612613
add_lemma(lemma);
613614
}
@@ -1603,60 +1604,23 @@ exprt string_refinementt::instantiate(
16031604
return implies_exprt(bounds, instance);
16041605
}
16051606

1606-
/// instantiate a quantified formula representing `not_contains` by substituting
1607-
/// the quantifiers and generating axioms
1608-
/// \par parameters: a quantified formula representing `not_contains`, and a
1609-
/// list to which to add the created lemmas to
1610-
void string_refinementt::instantiate_not_contains(
1611-
const string_not_contains_constraintt &axiom, std::list<exprt> &new_lemmas)
1607+
/// Instantiates a quantified formula representing `not_contains` by
1608+
/// substituting the quantifiers and generating axioms.
1609+
/// \param [in] axiom: the axiom to instantiate
1610+
/// \return the lemmas produced through instantiation
1611+
std::vector<exprt> string_refinementt::instantiate_not_contains(
1612+
const string_not_contains_constraintt &axiom)
16121613
{
1613-
exprt s0=axiom.s0();
1614-
exprt s1=axiom.s1();
1614+
const string_exprt s0=to_string_expr(axiom.s0());
1615+
const string_exprt s1=to_string_expr(axiom.s1());
16151616

16161617
debug() << "instantiate not contains " << from_expr(ns, "", s0) << " : "
16171618
<< from_expr(ns, "", s1) << eom;
1618-
expr_sett index_set0=index_set[to_string_expr(s0).content()];
1619-
expr_sett index_set1=index_set[to_string_expr(s1).content()];
1619+
const expr_sett index_set0=index_set[s0.content()];
1620+
const expr_sett index_set1=index_set[s1.content()];
16201621

1621-
for(auto it0 : index_set0)
1622-
for(auto it1 : index_set1)
1623-
{
1624-
debug() << from_expr(ns, "", it0) << " : " << from_expr(ns, "", it1)
1625-
<< eom;
1626-
exprt val=minus_exprt(it0, it1);
1627-
exprt witness=generator.get_witness_of(axiom, val);
1628-
and_exprt prem_and_is_witness(
1629-
axiom.premise(),
1630-
equal_exprt(witness, it1));
1631-
1632-
not_exprt differ(
1633-
equal_exprt(
1634-
to_string_expr(s0)[it0],
1635-
to_string_expr(s1)[it1]));
1636-
exprt lemma=implies_exprt(prem_and_is_witness, differ);
1637-
1638-
new_lemmas.push_back(lemma);
1639-
// we put bounds on the witnesses:
1640-
// 0 <= v <= |s0| - |s1| ==> 0 <= v+w[v] < |s0| && 0 <= w[v] < |s1|
1641-
exprt zero=from_integer(0, val.type());
1642-
binary_relation_exprt c1(zero, ID_le, plus_exprt(val, witness));
1643-
binary_relation_exprt c2
1644-
(to_string_expr(s0).length(), ID_gt, plus_exprt(val, witness));
1645-
binary_relation_exprt c3(to_string_expr(s1).length(), ID_gt, witness);
1646-
binary_relation_exprt c4(zero, ID_le, witness);
1647-
1648-
minus_exprt diff(
1649-
to_string_expr(s0).length(),
1650-
to_string_expr(s1).length());
1651-
1652-
and_exprt premise(
1653-
binary_relation_exprt(zero, ID_le, val),
1654-
binary_relation_exprt(diff, ID_ge, val));
1655-
exprt witness_bounds=implies_exprt(
1656-
premise,
1657-
and_exprt(and_exprt(c1, c2), and_exprt(c3, c4)));
1658-
new_lemmas.push_back(witness_bounds);
1659-
}
1622+
return ::instantiate_not_contains(
1623+
axiom, index_set0, index_set1, generator);
16601624
}
16611625

16621626
/// replace array-lists by 'with' expressions

src/solvers/refinement/string_refinement.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,8 @@ class string_refinementt: public bv_refinementt
133133
exprt instantiate(
134134
const string_constraintt &axiom, const exprt &str, const exprt &val);
135135

136-
void instantiate_not_contains(
137-
const string_not_contains_constraintt &axiom,
138-
std::list<exprt> &new_lemmas);
136+
std::vector<exprt> instantiate_not_contains(
137+
const string_not_contains_constraintt &axiom);
139138

140139
exprt substitute_array_lists(exprt) const;
141140

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ SRC += unit_tests.cpp \
2424
solvers/refinement/string_constraint_generator_valueof/get_numeric_value_from_character.cpp \
2525
solvers/refinement/string_constraint_generator_valueof/is_digit_with_radix.cpp \
2626
solvers/refinement/string_constraint_generator_valueof/is_digit_with_radix_lower_case.cpp \
27+
solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp \
2728
catch_example.cpp \
2829
# Empty last line
2930

0 commit comments

Comments
 (0)