-
Notifications
You must be signed in to change notification settings - Fork 273
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
Partial cleanup in solver code #1810
Partial cleanup in solver code #1810
Conversation
7362161
to
e9742ac
Compare
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.
These are all great changes, I cannot approve them enough.
f200f2b
to
b0ead02
Compare
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.
Most of the changes are great, some need review as indicated. (A common theme: please don't remove blank lines that serve as conceptual separators. Wedon'tpaysomeper-linepriceandwhitespaceisreallyusefultohumanreaders.)
The request-for-changes is for a bit that I haven't seen any comment on: what are the performance differences?
src/solvers/prop/prop_conv.h
Outdated
bool use_cache; | ||
bool equality_propagation; | ||
bool freeze_all; // freezing variables (for incremental solving) | ||
virtual optionalt<literalt> literal(const exprt &expr) const; |
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.
I don't know why this line was moved, but certainly the comment must move together with it.
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.
I moved it back
src/solvers/prop/prop_conv.h
Outdated
use_cache(true), | ||
equality_propagation(true), | ||
freeze_all(false), | ||
post_processing_done(false), |
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.
" Initialize at declaration instead of construction
This avoids having to initialize them the same way in all constructors."
There just seems to be a single constructor - what sort of story is being made up here?!
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.
Should another constructor be added in the future (copy, move, default, overload of existing constructor), we'll have one set of default arguments, and the user won't have to repeat himself. Also, they're much easier to look up now - they're just when the values are declared. No need to dig through the .cpp
file looking for the constructor that isn't there.
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.
I get your point, but I don't want to be lied to in the commit message.
- They will always be initialised upon construction, the declaration is just a syntactic construct.
- There just is one constructor at this time, so don't use the plural.
If the commit message said what your comment said, all would be well.
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.
I updated the commit message.
src/solvers/prop/prop_conv.h
Outdated
@@ -110,14 +110,14 @@ class prop_conv_solvert:public prop_convt | |||
|
|||
virtual void clear_cache() { cache.clear();} | |||
|
|||
typedef std::map<irep_idt, literalt> symbolst; | |||
typedef std::unordered_map<exprt, literalt, irep_hash> cachet; |
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.
Please don't do this. Type names also carry useful information about what a data structure is intended to hold/do.
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.
typedef
s do the opposite. Especially when concealing standard data structure, such as map
. When reading code using typedefs this way one might think that cachet
and symbolst
is a user-defined class that needs special treatment. When explicitly written as std:::vector
or std::map
the interface and structure of the variable becomes obvious. The name of the variable should signify intent, not the type alias.
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.
As you please.
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.
symbolst
is not great here, but cachet
actually conveys intent.
Unless the typedef is only used once, I'm strongly in favour of using typedefs, in particular at interfaces.
If you think that typedefs hide information then you should use an IDE that solves that problem for you.
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.
Yeah; even if used once, these can still be worth having.
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.
I think symbolst
is misleading (you would expect a vector of symbolt
). cachet
does carry the intent but it's already present in the variable name (cache
).
src/solvers/flattening/boolbv.cpp
Outdated
if(auto s = numeric_cast<mp_integer>(size)) | ||
return unbounded_array == unbounded_arrayt::U_AUTO && | ||
*s > MAX_FLATTENED_ARRAY_SIZE; | ||
return true; |
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.
To be honest, I don't see how this is a "simplification". I'd much more accept that if you really gathered all the bits together. How about this:
if(type.id()==ID_symbol)
return is_unbounded_array(ns.follow(type));
const exprt &size=to_array_type(type).size();
return
type.id() == ID_array &&
(unbounded_array == unbounded_arrayt::U_ALL ||
!(auto s = numeric_cast<mp_integer>(size)) ||
(unbounded_array == unbounded_arrayt::U_AUTO &&
*s > MAX_FLATTENED_ARRAY_SIZE));
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.
return (auto s = func()) && s > 0)
is not valid C++. if-declarations are allowed, but not this.
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.
Ok, thanks, so just declare s
beforehand and just do the assignment in there.
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.
Yeah; not sure this change is actually a simplification. Also -- what problem is this solving?
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.
Changed according to Michael's comment.
src/solvers/flattening/boolbv.cpp
Outdated
bv_sub.resize(bv.size()); | ||
|
||
for(std::size_t i=0; i<bv.size(); i++) | ||
bv_sub[i].id(std::to_string(bv[i].get())); | ||
return dest; |
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.
Nit pick: a blank line before return
would help readability.
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.
I'd say removing double blank lines before this for loop would.
src/solvers/flattening/boolbv.cpp
Outdated
<< it.second.get_value(prop) << '\n'; | ||
} | ||
for(const auto &pair : map.mapping) | ||
out << pair.first << "=" << pair.second.get_value(prop) << '\n'; |
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.
The commit message doesn't really reflect what happened here (which mainly is renaming it -> pair (which is good).
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.
I changed the commit message: d400deb
if(width==0) | ||
return conversion_failed(expr); | ||
|
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.
Please stop removing blank lines that clearly separate steps. Code readability matters. Really.
#ifdef COMPACT_EQUAL_CONST | ||
bv_utils.equal_const_register(convert_bv(index)); // Definitely | ||
bv_utils.equal_const_register(convert_bv(result)); // Maybe | ||
#endif |
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.
Where is this gone?
|
||
#ifdef COMPACT_EQUAL_CONST | ||
bv_utils.equal_const_register(convert_bv(index)); // Definitely | ||
#endif |
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.
Again, where is this gone?
|
||
#ifdef COMPACT_EQUAL_CONST | ||
bv_utils.equal_const_register(convert_bv(index)); // Definitely | ||
#endif |
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.
?
I'll try to work through the commits as some of these are "yes, we should have done this years ago" and others seem problematic. As for the white-space removal -- I though the whole point of the long and bloody campaign to get clang-format working was so that we didn't have to argue about this. I'll check how many of my patch sets are broken by these changes as well. |
const exprt &op0=expr.op0(); | ||
|
||
bool no_overflow=expr.id()=="no-overflow-mult"; | ||
const bool no_overflow = expr.id() == "no-overflow-mult"; |
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.
Would be good to add an irepid for this.
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.
Actually it does not seem any exprt
gets this id anywhere. So it may be better to just remove it. And same thing with the other no-overflow
s
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.
@kroening Is there code elsewhere that generates no-overflow
variants of the arithmetic expressions?
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.
If there isn't then there should be; it is useful to know whether overflow matters or not / can be ignored. Especially for multiplication.
src/solvers/prop/prop_conv.h
Outdated
{ | ||
prop.set_frozen(a); | ||
} | ||
void set_assumptions(const bvt &_assumptions) override |
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.
the formatting of these one-line functions is inconsistent
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.
Also unnecessary IMHO.
d6e8668
to
1071652
Compare
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.
About half of this patch set is brilliant and changes we should have made ages ago and we really should merge. Then there is a fair amount of reformatting and whitespace changes plus a few API changes which are wrong IMHO.
const exprt &expr, | ||
const std::size_t bit, | ||
literalt &dest) const | ||
optionalt<literalt> |
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.
I don't see why this change is needed. If there is a real error then an exception should be thrown. If not then returning constant literals is acceptable.
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.
The function is not returning a constant literal when there is an error, it is just leaving dest
untouched. So this is not changing the behavior of the function, just making the interface clearer.
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.
May I suggest a different route: please just #ifdef 0
this code. Whether you change the interface to an optionalt
I don't care as much then. (Background: I wanted to figure out whether throwing an exception would be fine. I couldn't tell, because the code is never used.)
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.
Not sure I get your comment. If I #ifdef 0
the function when cbmc will not build because get_bool
is called from somewhere.
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.
Sorry, this is not about get_bool
, but about literal
(both boolbvt::literal
and prop_convt::literal
).
src/solvers/prop/prop_conv.h
Outdated
@@ -128,7 +128,7 @@ class prop_conv_solvert:public prop_convt | |||
bool post_processing_done; | |||
|
|||
// get a _boolean_ value from counterexample if not valid | |||
virtual bool get_bool(const exprt &expr, tvt &value) const; | |||
virtual optionalt<tvt> get_bool(const exprt &expr) const; |
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.
Again; this doesn't seem broken and so doesn't need to be fixed. If someone gives a true expression in then it is perfectly OK to give a true literal back.
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.
Again, this doesn't change the behavior. The interface as it was before is confusing because you would think that the result of get_bool
is the returned bool
, while in fact it is stored in tvt &value
(your comment makes me think you are confused yourself). Using optional makes it much clearer that it's actually a tvt
which is the result.
(note to myself) the documentation should be updated.
@@ -305,29 +305,13 @@ literalt prop_conv_solvert::convert_rest(const exprt &expr) | |||
|
|||
bool prop_conv_solvert::set_equality_to_true(const equal_exprt &expr) | |||
{ | |||
if(!equality_propagation) | |||
if(!equality_propagation || expr.lhs().id() != ID_symbol) |
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.
Why is this changed -- what problem does this solve?
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.
Maybe it's subjective but I find the second version much more readable.
The problems were missing const
, uninformative result
variable name, confusing fall through in the case of result.second
being false.
src/solvers/prop/prop_conv.cpp
Outdated
|
||
bvt bv; | ||
|
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.
Whitespace changes should be in their own commit.
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.
I reverted this change
src/solvers/prop/prop_conv.h
Outdated
@@ -110,14 +110,14 @@ class prop_conv_solvert:public prop_convt | |||
|
|||
virtual void clear_cache() { cache.clear();} | |||
|
|||
typedef std::map<irep_idt, literalt> symbolst; | |||
typedef std::unordered_map<exprt, literalt, irep_hash> cachet; |
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.
Yeah; even if used once, these can still be worth having.
if(op.size()!=width) | ||
throw "convert_mult: unexpected operand width"; | ||
|
||
INVARIANT(op.size() == width, "convert_mult: unexpected operand width"); |
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.
DATA_INVARIANT
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.
or CHECK_RETURN, but not just a plain INVARIANT
if(op0.type()!=expr.type()) | ||
throw "multiplication with mixed types"; | ||
|
||
INVARIANT(op0.type() == expr.type(), "multiplication with mixed types"); |
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.
DATA_INVARIANT
if(bv.size()!=width) | ||
throw "convert_mult: unexpected operand width"; | ||
|
||
INVARIANT(bv.size() == width, "convert_mult: unexpected operand width"); |
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.
DATA_INVARIANT
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.
I'm not sure about this one, it's more like we are checking that convert_bv
did its work correctly.
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.
OK, CHECK_RETURN then.
if(it->type()!=expr.type()) | ||
throw "multiplication with mixed types"; | ||
|
||
INVARIANT(it->type() == expr.type(), "multiplication with mixed types"); |
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.
DATA_INVARIANT
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.
Actually CHECK_RETURN.
src/solvers/prop/prop_conv.h
Outdated
{ | ||
prop.set_frozen(a); | ||
} | ||
void set_assumptions(const bvt &_assumptions) override |
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.
Also unnecessary IMHO.
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 addition to my comment below, on the discussion of get_bool
: it's probably not on a hot path so changing the interface isn't that a big deal. Actually it just has a single user in prop_conv_solvert::get
.
Edit: shouldn't get_bool
just 1. throw an exception if the expression type is not ID_bool
and 2. return TV_UNKNOWN
in all those cases where it presently returns true
?
const exprt &expr, | ||
const std::size_t bit, | ||
literalt &dest) const | ||
optionalt<literalt> |
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.
May I suggest a different route: please just #ifdef 0
this code. Whether you change the interface to an optionalt
I don't care as much then. (Background: I wanted to figure out whether throwing an exception would be fine. I couldn't tell, because the code is never used.)
1311f15
to
bfeac6d
Compare
@romainbrenguier (author), @tautschnig (reviewer), @peterschrammel (other owner) how should we handle this? As it's now 43 commits it seems a little unwieldy and I'm worried that the majority of patches which are fine might get forgotten while we discuss the few controversial ones. Would it be entirely implausible to think of a meeting with three of us to work through and merge things? |
@martin-cs what I could first do is make a separate PR with the non controversial commits, could you list the ones that you think are ready to go (or the opposite)? I would be ok with a meeting but when can it happen? |
@romainbrenguier Would you mind merging the fix-ups into their corresponding commits so that we have a clean list to mark as (non-)controversial? |
bfeac6d
to
58dc939
Compare
@tautschnig done |
I'd list the following as straight forward:
The others vary in the amount of discussion required. Many of them include good changes mixed with unnecessary ones. All those that include changing |
@@ -64,13 +55,13 @@ bvt boolbvt::convert_bitwise(const exprt &expr) | |||
else if(expr.id()==ID_bitxnor) | |||
bv[i]=prop.lequal(bv[i], op[i]); | |||
else | |||
throw "unexpected operand"; | |||
UNIMPLEMENTED; |
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.
Maybe UNHANDLED_CASE?
} | ||
} | ||
} | ||
|
||
return bv; | ||
} | ||
|
||
throw "unexpected bitwise operand"; | ||
UNIMPLEMENTED; |
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.
Maybe UNHANDLED_CASE?
"__CPROVER_internal_actual_array_"+ | ||
std::to_string(actual_array_counter++); | ||
const std::string identifier = "__CPROVER_internal_actual_array_" + | ||
std::to_string(actual_array_counter++); |
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.
Use CPROVER_PREFIX
Things I feel are straight forward: Things that I am ambivalent about and if @tautschnig thinks they are clear cut, then let's have them in: Things I think need more discussion: HTH |
58dc939
to
ee3ac60
Compare
@martin-cs @tautschnig thanks for making these lists of commits, here is a first PR in which I just selected the intersection of what Michael considers straightforward and what Martin considers straightforward or is ambivalent #1950 |
No worries about the delay and that you for persevering. I'll have a
look after today's deadline.
|
ee3ac60
to
c61a5d8
Compare
Another set of commits which Martin listed as straightforward #1956 |
@romainbrenguier My apologies this stalled; will pick up on #1956 |
This is clearer than a boolean signaling an error
The class actualy designated by this is a base class and not a subclass, so baset is clearer.
Factor out is_uniform function to reduce size of big function and make it clearer. Add const keyword where possible. Change assertions in INVARIANTS. Remove blank lines that are not helping clarity (for example between comments and instructions to which they apply). Use numeric_cast instead of to_integer.
c61a5d8
to
1e4e071
Compare
Most commits have been merged via other PRs so I'm closing this one. |
This regroup several commits that do only small refactoring changes in the solver module.
The goal is to improve clarity and use the same conventions as elsewhere (for instance use invariant
instead of assert or throw).