-
Notifications
You must be signed in to change notification settings - Fork 274
Multidimensional decreases clauses #6236
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
Conversation
30f3be2
to
f9f274c
Compare
Codecov Report
@@ Coverage Diff @@
## develop #6236 +/- ##
===========================================
+ Coverage 67.40% 76.18% +8.77%
===========================================
Files 1157 1478 +321
Lines 95236 161669 +66433
===========================================
+ Hits 64197 123165 +58968
- Misses 31039 38504 +7465
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
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.
Looks good apart from the code placement issue flagged.
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.
Some general comments:
- Please remove
activate-multi-line-match
from .desc files that don't need multi-line regex matching - Please only check regexes specific to the functionality you want to test (i.e. decreases clauses), because the other assertions (and especially their count, like
^.*0 of 5 failed \(1 iterations\)$
) may change in future if we introduce additional default checks.
regression/contracts/variant_multidimensional_not_decreasing_fail/test.desc
Outdated
Show resolved
Hide resolved
decreases clause, it should be placed inside a single __CPROVER_decreases(...), | ||
where each component of the multidimensional decreases clause is separated by a | ||
comma. Hence, in this test, the correct syntax is | ||
__CPROVER_decreases(N - i, 42). |
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.
Nice! :) These test.desc files are very well written.
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.
Shouldn't we support multiple decreases clauses in the future?
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.
It's unclear as of now.
__CPROVER_decreases
is unlike the other contracts. You can arbitrarily reorder multiple ENSURES, REQUIRES, ASSIGNS, LOOP_INVARIANT clauses, but the order of expressions matters for DECREASES clauses. They are not a conjunction (or a set), but an ordered tuple.
Moreover,
__CPROVER_decreases(X)
__CPROVER_decreases(Y)
reads as "both" X and Y monotonically decrease at each iteration, but for termination we simply need either one to monotonically decrease, and this sort of annotation would just be confusing.
a801204
to
31fe7de
Compare
src/util/std_expr.cpp
Outdated
binary_relation_exprt(small[i], ID_equal, large[i]); | ||
consecutive_equalities[i] = | ||
and_exprt(consecutive_equalities[i - 1], current_component_equality); | ||
} |
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 would separate the creation of the equalities and the forming of the conjunction. In particular, we have a conjunction(...)
helper, which takes exprt::operandst
as argument.
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 we use conjunction(...)
to create conjunctions of equalities of all necessary lengths (i.e. from 1 up to the size of the multidimensional decreases clause), I believe it will take quadratic time in total. Of course, the size of multidimensional decreases clauses is usually small. So the algorithmic performance should not be a concern. Nonetheless, I think it is better to simply traverse the vector and incrementally build conjunctions of equalities, which will take linear time.
bc56169
to
41a0198
Compare
regression/contracts/variant_missing_invariant_warning/test.desc
Outdated
Show resolved
Hide resolved
regression/contracts/variant_multidimensional_ackermann/test.desc
Outdated
Show resolved
Hide resolved
regression/contracts/variant_multidimensional_not_decreasing_fail1/main.c
Outdated
Show resolved
Hide resolved
regression/contracts/variant_multidimensional_not_decreasing_fail1/test.desc
Show resolved
Hide resolved
regression/contracts/variant_multidimensional_not_decreasing_fail2/main.c
Outdated
Show resolved
Hide resolved
typecheck_expr(variant); | ||
implicit_typecast_arithmetic(variant); | ||
for(auto &decreases_clause_component : | ||
(static_cast<exprt &>(code.add(ID_C_spec_decreases)).operands())) |
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.
Are there any guarantees that this cast is safe? Take a look at this comment #5403 (comment).
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.
Good catch. As suggested on the other thread, we should create "safe" accessors at some point.
However, currently, this issue also applies to invariant contracts, so may be we can table this change for a separate future PR and fix both together?
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.
Thanks for the link. For now, I will just leave it as it is. When someone cleans up the code for loop invariants, then we will also clean the code for decreases clauses.
3ad043a
to
048d022
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.
Thanks for all the changes!
LGTM with a couple of nitpicks:
048d022
to
36f661e
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.
Thank you for implementing all comments!
It tests whether we can prove (only partially) the termination of the Ackermann | ||
function using a multidimensional decreases clause. | ||
|
||
Note that this particular implementation of the Ackermann function contains | ||
both a while-loop and recursion. Therefore, to fully prove the termination of | ||
the Ackermann function, we must prove both | ||
(i) the termination of the while-loop and | ||
(ii) the termination of the recursion. | ||
Because CBMC does not support termination proofs of recursions (yet), we cannot | ||
prove the latter, but the former. Hence, the termination proof in the code is | ||
only "partial." | ||
|
||
Furthermore, the Ackermann function has a function contract that the result | ||
is always non-negative. This post-condition is necessary for establishing | ||
the loop invariant. However, in this test, we do not enforce the function | ||
contract. Instead, we assume that the function contract is correct and use it | ||
(i.e. replace a recursive call of the Ackermann function with its contract). | ||
|
||
We cannot verify/enforce the function contract of the Ackermann function, since | ||
CBMC does not support function contracts for recursively defined functions. | ||
As of now, CBMC only supports function contracts for non-recursive functions. |
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.
Kudos for your bar-raising test descriptions! @LongPham7
This pull request is about the implementation of "multidimensional" decreases clauses. "One-dimensional" decreases clauses are already supported by the existing version of CBMC. We extend one-dimensional decreases clauses to multidimensional ones by admitting tuples of integer-typed functions. The syntax of a multidimensional decrease clause is
__CPROVER_decreases(f1, ..., fn)
. We use the lexicographic order to compare two tuples.