-
Notifications
You must be signed in to change notification settings - Fork 273
TG-592 Implemented the correct instantiation procedure for not contains constraints #1407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,61 +11,46 @@ Author: Jesse Sigal, [email protected] | |
|
||
#include <solvers/refinement/string_constraint_instantiation.h> | ||
|
||
#include <solvers/refinement/string_constraint.h> | ||
#include <solvers/refinement/string_constraint_generator.h> | ||
#include <solvers/refinement/string_refinement.h> | ||
|
||
/// Instantiates a quantified formula representing `not_contains` by | ||
/// substituting the quantifiers and generating axioms. | ||
/// \related string_refinementt | ||
/// \param [in] axiom: the axiom to instantiate | ||
/// \param [in] index_set0: the index set for `axiom.s0()` | ||
/// \param [in] index_set1: the index set for `axiom.s1()` | ||
/// \param [in] index_pairs: the pairs of indices to at which to instantiate | ||
/// \param [in] generator: generator to be used to get `axiom`'s witness | ||
/// \return the lemmas produced through instantiation | ||
std::vector<exprt> instantiate_not_contains( | ||
const string_not_contains_constraintt &axiom, | ||
const std::set<exprt> &index_set0, | ||
const std::set<exprt> &index_set1, | ||
const std::set<std::pair<exprt, exprt>> &index_pairs, | ||
const string_constraint_generatort &generator) | ||
{ | ||
std::vector<exprt> lemmas; | ||
|
||
const string_exprt s0=to_string_expr(axiom.s0()); | ||
const string_exprt s1=to_string_expr(axiom.s1()); | ||
|
||
for(const auto &i0 : index_set0) | ||
for(const auto &i1 : index_set1) | ||
{ | ||
const minus_exprt val(i0, i1); | ||
const exprt witness=generator.get_witness_of(axiom, val); | ||
const and_exprt prem_and_is_witness( | ||
axiom.premise(), | ||
equal_exprt(witness, i1)); | ||
|
||
const not_exprt differ(equal_exprt(s0[i0], s1[i1])); | ||
const implies_exprt lemma(prem_and_is_witness, differ); | ||
lemmas.push_back(lemma); | ||
|
||
// we put bounds on the witnesses: | ||
// 0 <= v <= |s0| - |s1| ==> 0 <= v+w[v] < |s0| && 0 <= w[v] < |s1| | ||
const exprt zero=from_integer(0, val.type()); | ||
const binary_relation_exprt c1(zero, ID_le, plus_exprt(val, witness)); | ||
const binary_relation_exprt c2( | ||
s0.length(), ID_gt, plus_exprt(val, witness)); | ||
const binary_relation_exprt c3(s1.length(), ID_gt, witness); | ||
const binary_relation_exprt c4(zero, ID_le, witness); | ||
|
||
const minus_exprt diff(s0.length(), s1.length()); | ||
|
||
const and_exprt premise( | ||
binary_relation_exprt(zero, ID_le, val), | ||
binary_relation_exprt(diff, ID_ge, val)); | ||
const implies_exprt witness_bounds( | ||
premise, | ||
and_exprt(and_exprt(c1, c2), and_exprt(c3, c4))); | ||
lemmas.push_back(witness_bounds); | ||
} | ||
const string_exprt &s0=to_string_expr(axiom.s0()); | ||
const string_exprt &s1=to_string_expr(axiom.s1()); | ||
|
||
for(const auto &pair : index_pairs) | ||
{ | ||
// We have s0[x+f(x)] and s1[f(x)], so to have i0 indexing s0 and i1 | ||
// indexing s1, we need x = i0 - i1 and f(i0 - i1) = f(x) = i1. | ||
const exprt &i0=pair.first; | ||
const exprt &i1=pair.second; | ||
const minus_exprt val(i0, i1); | ||
const and_exprt universal_bound( | ||
binary_relation_exprt(axiom.univ_lower_bound(), ID_le, val), | ||
binary_relation_exprt(axiom.univ_upper_bound(), ID_gt, val)); | ||
const exprt f=generator.get_witness_of(axiom, val); | ||
const equal_exprt relevancy(f, i1); | ||
const and_exprt premise(relevancy, axiom.premise(), universal_bound); | ||
|
||
const notequal_exprt differ(s0[i0], s1[i1]); | ||
const and_exprt existential_bound( | ||
binary_relation_exprt(axiom.exists_lower_bound(), ID_le, i1), | ||
binary_relation_exprt(axiom.exists_upper_bound(), ID_gt, i1)); | ||
const and_exprt body(differ, existential_bound); | ||
|
||
const implies_exprt lemma(premise, body); | ||
lemmas.push_back(lemma); | ||
} | ||
|
||
return lemmas; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,8 +17,7 @@ Author: Jesse Sigal, [email protected] | |
|
||
std::vector<exprt> instantiate_not_contains( | ||
const string_not_contains_constraintt &axiom, | ||
const std::set<exprt> &index_set0, | ||
const std::set<exprt> &index_set1, | ||
const std::set<std::pair<exprt, exprt>> &index_pairs, | ||
const string_constraint_generatort &generator); | ||
|
||
#endif // CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_INSTANTIATION_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,7 +39,7 @@ class string_refinementt final: public bv_refinementt | |
bool string_non_empty=false; | ||
/// Concretize strings after solver is finished | ||
bool trace=false; | ||
bool use_counter_example=false; | ||
bool use_counter_example=true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could remove this variable has it is never modified There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it should still be kept, as it was kept before, because it can have a big effect on the solver. If you're not using not contains constraints, I think it's pretty unnecessary based on our tests. However, it will probably add a good number of new lemmas. I think there may a command line argument in test-gen that can set this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would you decide when to turn off/on that flag? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would leave it on by default so that more tests are produced by test-gen, but would be turned off it test-gen mem'd or timed out (and could be tracked to strings). Then you could turn it off, which would keep correctness but possibly produce less tests when not contains constraints are involved. |
||
}; | ||
public: | ||
/// string_refinementt constructor arguments | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,12 +11,9 @@ | |
#include <solvers/refinement/string_constraint_instantiation.h> | ||
|
||
#include <solvers/sat/satcheck.h> | ||
#include <solvers/refinement/bv_refinement.h> | ||
#include <java_bytecode/java_types.h> | ||
#include <langapi/mode.h> | ||
#include <java_bytecode/java_bytecode_language.h> | ||
#include <util/namespace.h> | ||
#include <util/symbol_table.h> | ||
#include <util/simplify_expr.h> | ||
|
||
/// \class Types used throughout the test. Currently it is impossible to | ||
|
@@ -48,7 +45,7 @@ const tt t; | |
/// Creates a `constant_exprt` of the proper length type. | ||
/// \param [in] i: integer to convert | ||
/// \return corresponding `constant_exprt` | ||
constant_exprt from_integer(const mp_integer i) | ||
constant_exprt from_integer(const mp_integer &i) | ||
{ | ||
return from_integer(i, t.length_type()); | ||
} | ||
|
@@ -81,6 +78,17 @@ std::set<exprt> full_index_set(const string_exprt &s) | |
return ret; | ||
} | ||
|
||
/// Create the cartesian product of two sets. | ||
template<class T, class U> | ||
std::set<std::pair<T, U>> product(const std::set<T> ts, const std::set<U> us) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. depending on the usage, you could replace this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The sets are used because sets are used in |
||
{ | ||
std::set<std::pair<T, U>> s; | ||
for(const auto &t : ts) | ||
for(const auto &u : us) | ||
s.insert(std::pair<T, U>(t, u)); | ||
return s; | ||
} | ||
|
||
/// Simplifies, and returns the conjunction of the lemmas. | ||
/// \param [in] lemmas: lemmas to process | ||
/// \param [in] ns: namespace for simplifying | ||
|
@@ -152,7 +160,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Generating the corresponding axioms and simplifying, recording info | ||
symbol_tablet symtab; | ||
namespacet empty_ns(symtab); | ||
const namespacet empty_ns(symtab); | ||
string_constraint_generatort::infot info; | ||
string_constraint_generatort generator(info, ns); | ||
exprt res=generator.add_axioms_for_function_application(func); | ||
|
@@ -196,7 +204,7 @@ SCENARIO("instantiate_not_contains", | |
for(const auto &axiom : nc_axioms) | ||
{ | ||
const std::vector<exprt> l=instantiate_not_contains( | ||
axiom, index_set_ab, index_set_b, generator); | ||
axiom, product(index_set_ab, index_set_b), generator); | ||
lemmas.insert(lemmas.end(), l.begin(), l.end()); | ||
} | ||
|
||
|
@@ -239,7 +247,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Create witness for axiom | ||
symbol_tablet symtab; | ||
namespacet empty_ns(symtab); | ||
const namespacet empty_ns(symtab); | ||
string_constraint_generatort::infot info; | ||
string_constraint_generatort generator(info, ns); | ||
generator.witness[vacuous]= | ||
|
@@ -255,7 +263,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Instantiate the lemmas | ||
std::vector<exprt> lemmas=instantiate_not_contains( | ||
vacuous, index_set_a, index_set_a, generator); | ||
vacuous, product(index_set_a, index_set_a), generator); | ||
|
||
const exprt conj=combine_lemmas(lemmas, ns); | ||
const std::string info=create_info(lemmas, ns); | ||
|
@@ -297,7 +305,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Create witness for axiom | ||
symbol_tablet symtab; | ||
namespacet ns(symtab); | ||
const namespacet ns(symtab); | ||
string_constraint_generatort::infot info; | ||
string_constraint_generatort generator(info, ns); | ||
generator.witness[trivial]= | ||
|
@@ -314,7 +322,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Instantiate the lemmas | ||
std::vector<exprt> lemmas=instantiate_not_contains( | ||
trivial, index_set_a, index_set_b, generator); | ||
trivial, product(index_set_a, index_set_b), generator); | ||
|
||
const exprt conj=combine_lemmas(lemmas, ns); | ||
const std::string info=create_info(lemmas, ns); | ||
|
@@ -356,7 +364,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Create witness for axiom | ||
symbol_tablet symtab; | ||
namespacet empty_ns(symtab); | ||
const namespacet empty_ns(symtab); | ||
string_constraint_generatort::infot info; | ||
string_constraint_generatort generator(info, ns); | ||
generator.witness[trivial]= | ||
|
@@ -374,7 +382,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Instantiate the lemmas | ||
std::vector<exprt> lemmas=instantiate_not_contains( | ||
trivial, index_set_a, index_set_empty, generator); | ||
trivial, product(index_set_a, index_set_empty), generator); | ||
|
||
const exprt conj=combine_lemmas(lemmas, ns); | ||
const std::string info=create_info(lemmas, ns); | ||
|
@@ -416,7 +424,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Create witness for axiom | ||
symbol_tablet symtab; | ||
namespacet empty_ns(symtab); | ||
const namespacet empty_ns(symtab); | ||
|
||
string_constraint_generatort::infot info; | ||
string_constraint_generatort generator(info, ns); | ||
|
@@ -433,7 +441,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Instantiate the lemmas | ||
std::vector<exprt> lemmas=instantiate_not_contains( | ||
trivial, index_set_ab, index_set_ab, generator); | ||
trivial, product(index_set_ab, index_set_ab), generator); | ||
|
||
const exprt conj=combine_lemmas(lemmas, ns); | ||
const std::string info=create_info(lemmas, ns); | ||
|
@@ -476,7 +484,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Create witness for axiom | ||
symbol_tablet symtab; | ||
namespacet empty_ns(symtab); | ||
const namespacet empty_ns(symtab); | ||
string_constraint_generatort::infot info; | ||
string_constraint_generatort generator(info, ns); | ||
generator.witness[trivial]= | ||
|
@@ -493,7 +501,7 @@ SCENARIO("instantiate_not_contains", | |
|
||
// Instantiate the lemmas | ||
std::vector<exprt> lemmas=instantiate_not_contains( | ||
trivial, index_set_ab, index_set_cd, generator); | ||
trivial, product(index_set_ab, index_set_cd), generator); | ||
|
||
const exprt conj=combine_lemmas(lemmas, ns); | ||
const std::string info=create_info(lemmas, ns); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we put this block into a new function, and call it from
dec_solve
? Because this is not really checking axioms but adding new things to the solver.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my refactor ticket, I really rearrange
dec_solve
, including this. Is that okay?