Skip to content

Commit 6d6e1df

Browse files
author
Daniel Kroening
authored
Merge pull request diffblue#1407 from jasigal/fix/instantiate-not-contains#TG-592
TG-592 Implemented the correct instantiation procedure for not contains constraints
2 parents 8da3eef + e4e2b10 commit 6d6e1df

File tree

5 files changed

+101
-83
lines changed

5 files changed

+101
-83
lines changed

src/solvers/refinement/string_constraint_instantiation.cpp

+28-43
Original file line numberDiff line numberDiff line change
@@ -11,61 +11,46 @@ Author: Jesse Sigal, [email protected]
1111

1212
#include <solvers/refinement/string_constraint_instantiation.h>
1313

14-
#include <solvers/refinement/string_constraint.h>
15-
#include <solvers/refinement/string_constraint_generator.h>
16-
#include <solvers/refinement/string_refinement.h>
17-
1814
/// Instantiates a quantified formula representing `not_contains` by
1915
/// substituting the quantifiers and generating axioms.
2016
/// \related string_refinementt
2117
/// \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()`
18+
/// \param [in] index_pairs: the pairs of indices to at which to instantiate
2419
/// \param [in] generator: generator to be used to get `axiom`'s witness
2520
/// \return the lemmas produced through instantiation
2621
std::vector<exprt> instantiate_not_contains(
2722
const string_not_contains_constraintt &axiom,
28-
const std::set<exprt> &index_set0,
29-
const std::set<exprt> &index_set1,
23+
const std::set<std::pair<exprt, exprt>> &index_pairs,
3024
const string_constraint_generatort &generator)
3125
{
3226
std::vector<exprt> lemmas;
3327

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-
}
28+
const string_exprt &s0=to_string_expr(axiom.s0());
29+
const string_exprt &s1=to_string_expr(axiom.s1());
30+
31+
for(const auto &pair : index_pairs)
32+
{
33+
// We have s0[x+f(x)] and s1[f(x)], so to have i0 indexing s0 and i1
34+
// indexing s1, we need x = i0 - i1 and f(i0 - i1) = f(x) = i1.
35+
const exprt &i0=pair.first;
36+
const exprt &i1=pair.second;
37+
const minus_exprt val(i0, i1);
38+
const and_exprt universal_bound(
39+
binary_relation_exprt(axiom.univ_lower_bound(), ID_le, val),
40+
binary_relation_exprt(axiom.univ_upper_bound(), ID_gt, val));
41+
const exprt f=generator.get_witness_of(axiom, val);
42+
const equal_exprt relevancy(f, i1);
43+
const and_exprt premise(relevancy, axiom.premise(), universal_bound);
44+
45+
const notequal_exprt differ(s0[i0], s1[i1]);
46+
const and_exprt existential_bound(
47+
binary_relation_exprt(axiom.exists_lower_bound(), ID_le, i1),
48+
binary_relation_exprt(axiom.exists_upper_bound(), ID_gt, i1));
49+
const and_exprt body(differ, existential_bound);
50+
51+
const implies_exprt lemma(premise, body);
52+
lemmas.push_back(lemma);
53+
}
6954

7055
return lemmas;
7156
}

src/solvers/refinement/string_constraint_instantiation.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ Author: Jesse Sigal, [email protected]
1717

1818
std::vector<exprt> instantiate_not_contains(
1919
const string_not_contains_constraintt &axiom,
20-
const std::set<exprt> &index_set0,
21-
const std::set<exprt> &index_set1,
20+
const std::set<std::pair<exprt, exprt>> &index_pairs,
2221
const string_constraint_generatort &generator);
2322

2423
#endif // CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_INSTANTIATION_H

src/solvers/refinement/string_refinement.cpp

+47-21
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static std::vector<exprt> instantiate_not_contains(
9999
const namespacet &ns,
100100
const string_not_contains_constraintt &axiom,
101101
const std::map<exprt, std::set<exprt>> &index_set,
102+
const std::map<exprt, std::set<exprt>> &current_index_set,
102103
const string_constraint_generatort &generator);
103104

104105
static exprt get_array(
@@ -850,7 +851,12 @@ decision_proceduret::resultt string_refinementt::dec_solve()
850851
debug() << "constraint " << i << '\n';
851852
const std::vector<exprt> lemmas=
852853
instantiate_not_contains(
853-
debug(), ns, not_contains_axioms[i], index_set, generator);
854+
debug(),
855+
ns,
856+
not_contains_axioms[i],
857+
index_set,
858+
current_index_set,
859+
generator);
854860
for(const exprt &lemma : lemmas)
855861
add_lemma(lemma);
856862
}
@@ -1510,23 +1516,26 @@ static std::pair<bool, std::vector<exprt>> check_axioms(
15101516

15111517
if(use_counter_example)
15121518
{
1513-
// TODO: add counter examples for not_contains?
1519+
stream << "Adding counter-examples: " << eom;
1520+
// TODO: add counter-examples for universal constraints?
15141521

1515-
// Checking if the current solution satisfies the constraints
15161522
std::vector<exprt> lemmas;
1517-
for(const auto &v : violated)
1523+
for(const auto &v : violated_not_contains)
15181524
{
15191525
const exprt &val=v.second;
1520-
const string_constraintt &axiom=universal_axioms[v.first];
1521-
1522-
exprt premise(axiom.premise());
1523-
exprt body(axiom.body());
1524-
implies_exprt instance(premise, body);
1525-
replace_expr(symbol_resolve, instance);
1526-
replace_expr(axiom.univ_var(), val, instance);
1527-
stream << "adding counter example " << from_expr(ns, "", instance)
1528-
<< eom;
1529-
lemmas.push_back(instance);
1526+
const string_not_contains_constraintt &axiom=
1527+
not_contains_axioms[v.first];
1528+
1529+
const exprt func_val=generator.get_witness_of(axiom, val);
1530+
const exprt comp_val=simplify_sum(plus_exprt(val, func_val));
1531+
1532+
std::set<std::pair<exprt, exprt>> indices;
1533+
indices.insert(std::pair<exprt, exprt>(comp_val, func_val));
1534+
const exprt counter=::instantiate_not_contains(
1535+
axiom, indices, generator)[0];
1536+
1537+
stream << " - " << from_expr(ns, "", counter) << eom;
1538+
lemmas.push_back(counter);
15301539
}
15311540
return { false, lemmas };
15321541
}
@@ -1960,19 +1969,36 @@ static std::vector<exprt> instantiate_not_contains(
19601969
const namespacet &ns,
19611970
const string_not_contains_constraintt &axiom,
19621971
const std::map<exprt, std::set<exprt>> &index_set,
1972+
const std::map<exprt, std::set<exprt>> &current_index_set,
19631973
const string_constraint_generatort &generator)
19641974
{
1965-
const string_exprt s0=to_string_expr(axiom.s0());
1966-
const string_exprt s1=to_string_expr(axiom.s1());
1975+
const string_exprt &s0=axiom.s0();
1976+
const string_exprt &s1=axiom.s1();
19671977

19681978
stream << "instantiate not contains " << from_expr(ns, "", s0) << " : "
19691979
<< from_expr(ns, "", s1) << messaget::eom;
1970-
const auto &i0=index_set.find(s0.content());
1971-
const auto &i1=index_set.find(s1.content());
1972-
if(i0!=index_set.end() && i1!=index_set.end())
1980+
1981+
const auto &index_set0=index_set.find(s0.content());
1982+
const auto &index_set1=index_set.find(s1.content());
1983+
const auto &current_index_set0=current_index_set.find(s0.content());
1984+
const auto &current_index_set1=current_index_set.find(s1.content());
1985+
1986+
if(index_set0!=index_set.end() &&
1987+
index_set1!=index_set.end() &&
1988+
current_index_set0!=index_set.end() &&
1989+
current_index_set1!=index_set.end())
19731990
{
1974-
return ::instantiate_not_contains(
1975-
axiom, i0->second, i1->second, generator);
1991+
typedef std::pair<exprt, exprt> expr_pairt;
1992+
std::set<expr_pairt> index_pairs;
1993+
1994+
for(const auto &ic0 : current_index_set0->second)
1995+
for(const auto &i1 : index_set1->second)
1996+
index_pairs.insert(expr_pairt(ic0, i1));
1997+
for(const auto &ic1 : current_index_set1->second)
1998+
for(const auto &i0 : index_set0->second)
1999+
index_pairs.insert(expr_pairt(i0, ic1));
2000+
2001+
return ::instantiate_not_contains(axiom, index_pairs, generator);
19762002
}
19772003
return { };
19782004
}

src/solvers/refinement/string_refinement.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class string_refinementt final: public bv_refinementt
3939
bool string_non_empty=false;
4040
/// Concretize strings after solver is finished
4141
bool trace=false;
42-
bool use_counter_example=false;
42+
bool use_counter_example=true;
4343
};
4444
public:
4545
/// string_refinementt constructor arguments

unit/solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp

+24-16
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,9 @@
1111
#include <solvers/refinement/string_constraint_instantiation.h>
1212

1313
#include <solvers/sat/satcheck.h>
14-
#include <solvers/refinement/bv_refinement.h>
1514
#include <java_bytecode/java_types.h>
1615
#include <langapi/mode.h>
1716
#include <java_bytecode/java_bytecode_language.h>
18-
#include <util/namespace.h>
19-
#include <util/symbol_table.h>
2017
#include <util/simplify_expr.h>
2118

2219
/// \class Types used throughout the test. Currently it is impossible to
@@ -48,7 +45,7 @@ const tt t;
4845
/// Creates a `constant_exprt` of the proper length type.
4946
/// \param [in] i: integer to convert
5047
/// \return corresponding `constant_exprt`
51-
constant_exprt from_integer(const mp_integer i)
48+
constant_exprt from_integer(const mp_integer &i)
5249
{
5350
return from_integer(i, t.length_type());
5451
}
@@ -81,6 +78,17 @@ std::set<exprt> full_index_set(const string_exprt &s)
8178
return ret;
8279
}
8380

81+
/// Create the cartesian product of two sets.
82+
template<class T, class U>
83+
std::set<std::pair<T, U>> product(const std::set<T> ts, const std::set<U> us)
84+
{
85+
std::set<std::pair<T, U>> s;
86+
for(const auto &t : ts)
87+
for(const auto &u : us)
88+
s.insert(std::pair<T, U>(t, u));
89+
return s;
90+
}
91+
8492
/// Simplifies, and returns the conjunction of the lemmas.
8593
/// \param [in] lemmas: lemmas to process
8694
/// \param [in] ns: namespace for simplifying
@@ -152,7 +160,7 @@ SCENARIO("instantiate_not_contains",
152160

153161
// Generating the corresponding axioms and simplifying, recording info
154162
symbol_tablet symtab;
155-
namespacet empty_ns(symtab);
163+
const namespacet empty_ns(symtab);
156164
string_constraint_generatort::infot info;
157165
string_constraint_generatort generator(info, ns);
158166
exprt res=generator.add_axioms_for_function_application(func);
@@ -196,7 +204,7 @@ SCENARIO("instantiate_not_contains",
196204
for(const auto &axiom : nc_axioms)
197205
{
198206
const std::vector<exprt> l=instantiate_not_contains(
199-
axiom, index_set_ab, index_set_b, generator);
207+
axiom, product(index_set_ab, index_set_b), generator);
200208
lemmas.insert(lemmas.end(), l.begin(), l.end());
201209
}
202210

@@ -239,7 +247,7 @@ SCENARIO("instantiate_not_contains",
239247

240248
// Create witness for axiom
241249
symbol_tablet symtab;
242-
namespacet empty_ns(symtab);
250+
const namespacet empty_ns(symtab);
243251
string_constraint_generatort::infot info;
244252
string_constraint_generatort generator(info, ns);
245253
generator.witness[vacuous]=
@@ -255,7 +263,7 @@ SCENARIO("instantiate_not_contains",
255263

256264
// Instantiate the lemmas
257265
std::vector<exprt> lemmas=instantiate_not_contains(
258-
vacuous, index_set_a, index_set_a, generator);
266+
vacuous, product(index_set_a, index_set_a), generator);
259267

260268
const exprt conj=combine_lemmas(lemmas, ns);
261269
const std::string info=create_info(lemmas, ns);
@@ -297,7 +305,7 @@ SCENARIO("instantiate_not_contains",
297305

298306
// Create witness for axiom
299307
symbol_tablet symtab;
300-
namespacet ns(symtab);
308+
const namespacet ns(symtab);
301309
string_constraint_generatort::infot info;
302310
string_constraint_generatort generator(info, ns);
303311
generator.witness[trivial]=
@@ -314,7 +322,7 @@ SCENARIO("instantiate_not_contains",
314322

315323
// Instantiate the lemmas
316324
std::vector<exprt> lemmas=instantiate_not_contains(
317-
trivial, index_set_a, index_set_b, generator);
325+
trivial, product(index_set_a, index_set_b), generator);
318326

319327
const exprt conj=combine_lemmas(lemmas, ns);
320328
const std::string info=create_info(lemmas, ns);
@@ -356,7 +364,7 @@ SCENARIO("instantiate_not_contains",
356364

357365
// Create witness for axiom
358366
symbol_tablet symtab;
359-
namespacet empty_ns(symtab);
367+
const namespacet empty_ns(symtab);
360368
string_constraint_generatort::infot info;
361369
string_constraint_generatort generator(info, ns);
362370
generator.witness[trivial]=
@@ -374,7 +382,7 @@ SCENARIO("instantiate_not_contains",
374382

375383
// Instantiate the lemmas
376384
std::vector<exprt> lemmas=instantiate_not_contains(
377-
trivial, index_set_a, index_set_empty, generator);
385+
trivial, product(index_set_a, index_set_empty), generator);
378386

379387
const exprt conj=combine_lemmas(lemmas, ns);
380388
const std::string info=create_info(lemmas, ns);
@@ -416,7 +424,7 @@ SCENARIO("instantiate_not_contains",
416424

417425
// Create witness for axiom
418426
symbol_tablet symtab;
419-
namespacet empty_ns(symtab);
427+
const namespacet empty_ns(symtab);
420428

421429
string_constraint_generatort::infot info;
422430
string_constraint_generatort generator(info, ns);
@@ -433,7 +441,7 @@ SCENARIO("instantiate_not_contains",
433441

434442
// Instantiate the lemmas
435443
std::vector<exprt> lemmas=instantiate_not_contains(
436-
trivial, index_set_ab, index_set_ab, generator);
444+
trivial, product(index_set_ab, index_set_ab), generator);
437445

438446
const exprt conj=combine_lemmas(lemmas, ns);
439447
const std::string info=create_info(lemmas, ns);
@@ -476,7 +484,7 @@ SCENARIO("instantiate_not_contains",
476484

477485
// Create witness for axiom
478486
symbol_tablet symtab;
479-
namespacet empty_ns(symtab);
487+
const namespacet empty_ns(symtab);
480488
string_constraint_generatort::infot info;
481489
string_constraint_generatort generator(info, ns);
482490
generator.witness[trivial]=
@@ -493,7 +501,7 @@ SCENARIO("instantiate_not_contains",
493501

494502
// Instantiate the lemmas
495503
std::vector<exprt> lemmas=instantiate_not_contains(
496-
trivial, index_set_ab, index_set_cd, generator);
504+
trivial, product(index_set_ab, index_set_cd), generator);
497505

498506
const exprt conj=combine_lemmas(lemmas, ns);
499507
const std::string info=create_info(lemmas, ns);

0 commit comments

Comments
 (0)