Skip to content

let_exprt can now do multiple bindings #4992

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

Merged
merged 2 commits into from
Oct 10, 2019
Merged

let_exprt can now do multiple bindings #4992

merged 2 commits into from
Oct 10, 2019

Conversation

kroening
Copy link
Member

@kroening kroening commented Aug 6, 2019

This matches what the SMT-LIB standard does. It also matches what our own
binding_exprt can do, i.e., let_exprt can be re-written into a lambda
binding plus a function application in the standard way.

  • Each commit message has a non-empty body, explaining why the change was made.
  • n/a Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • n/a My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • n/a White-space or formatting changes outside the feature-related changed lines are in commits of their own.

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: 13c457b).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/122229305

where,
where.type())
{
}

symbol_value_sequencet &symbol_value_sequence()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So someone retrieving this needs to know it's an alternating sequence of symbol, value, symbol, value? Seems better to either have a sequence of 2-tuples called bindings, or else provide accessors for nth_symbol, nth_value etc. Either of these can also enforce that the symbols are symbol_exprt.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did consider both options.
Problems of the "accessor" option are that a) you can't easily iterate, and b) it kills the USE_LIST option for performance reasons (but we may want to kill that anyway).
The two-tuple option would be somewhat more memory-consuming, but maybe that's not a genuine issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now with the "sequence of 2-tuples" option.

Copy link
Collaborator

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't strike me as particularly great design to build something rather fragile just to satisfy a potential, yet unproven future use.

{
}

using symbol_value_sequencet = std::vector<exprt>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't the first time/only place we are doing this, but we really shouldn't: this should be exprt::operandst, unless we are very intentionally (but still somewhat questionably) using a subtype that we know has the same memory layout (as was the case for binding_exprt).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see much of an alternative to strengthen typing while still exposing something that can be iterated over.
An option could be to invent a custom range-like setup, which would essentially wrap the underlying iterator. That would eliminate the scary casts at the level of the container.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be happy to look into this, but given that this is a very global problem, I would declare that to be outside of the scope of this PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, can we at least not make it any worse? I.e., not introduce yet another local definition of what we believe to be the type of exprt::operands()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without that, it's not possible to type the symbols.

where,
where.type())
{
}

symbol_value_sequencet &symbol_value_sequence()
{
return (symbol_value_sequencet &)op0().operands();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do find these type casts scary. Right now, this one actually is unnecessary. But if in future there were to be a difference then only runtime crashes would tell us.

{
public:
let_exprt(symbol_exprt symbol, exprt value, const exprt &where)
: ternary_exprt(
class let_binding_exprt : public binary_exprt
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another question: why is a let_binding_exprt not at all related to a binding_exprt? That seems surprising to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not trivial: there's only one "where", and not one per binding, whereas the let bindings need an additional "value". Thus, the "is-a" relationship is not easy to establish.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack, but then the binding_exprt may need to be reconsidered if it isn't actually as generic as was hoped? Maybe it should just not be called binding_exprt and instead its API should be folded into that of a quantifier_exprt? I would just like to avoid confusion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did consider that, but it does fit array_comprehension_exprt. That would then need to be a quantifier (odd) or have it's own API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another idea. An option could be that let_exprt gets a binding_exprt as operand!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would seem nice and consistent with the other uses of binding_exprt!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, will go for it!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@kroening kroening force-pushed the let-is-a-binding branch 3 times, most recently from cff58cd to eba4578 Compare August 7, 2019 21:46
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: eba4578).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/122360496

Daniel Kroening added 2 commits August 13, 2019 12:08
This enables let_exprt to use binding_exprt.
This enables let_exprt to do multiple binding, which matches what the
SMT-LIB standard does.  The new let_exprt can be re-written into a lambda
binding plus a function application in the standard way.
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: 71a20e9).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/122980484

@kroening kroening merged commit 31cd424 into develop Oct 10, 2019
@kroening kroening deleted the let-is-a-binding branch October 10, 2019 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants