| 1 | /*
|
|---|
| 2 | COST Verification Competition. vladimir@cost-ic0701.org
|
|---|
| 3 |
|
|---|
| 4 | Challenge 3: Two equal elements
|
|---|
| 5 |
|
|---|
| 6 | Given: An integer array a of length n+2 with n>=2. It is known that at
|
|---|
| 7 | least two values stored in the array appear twice (i.e., there are at
|
|---|
| 8 | least two duplets).
|
|---|
| 9 |
|
|---|
| 10 | Implement and verify a program finding such two values.
|
|---|
| 11 |
|
|---|
| 12 | You may assume that the array contains values between 0 and n-1.
|
|---|
| 13 | */
|
|---|
| 14 | #pragma CIVL ACSL
|
|---|
| 15 | #ifndef NULL
|
|---|
| 16 | #define NULL (void*)0
|
|---|
| 17 | #endif
|
|---|
| 18 |
|
|---|
| 19 | /* duplet(a) returns the indexes (i,j) of a duplet in a.
|
|---|
| 20 | * moreover, if except is not null, the value of this duplet must
|
|---|
| 21 | * be different from it.
|
|---|
| 22 | */
|
|---|
| 23 |
|
|---|
| 24 | $input int N;
|
|---|
| 25 | $assume(N > 2);
|
|---|
| 26 | $input int a[N + 2];
|
|---|
| 27 |
|
|---|
| 28 | /* A duplet in array a is a pair of indexes (i,j) in the bounds of array
|
|---|
| 29 | a such that a[i] = a[j] */
|
|---|
| 30 |
|
|---|
| 31 | /*@ predicate is_duplet(int * a, integer len, integer i, integer j) =
|
|---|
| 32 | @ 0 <= i && i < j && j < len && a[i] == a[j];
|
|---|
| 33 | @*/
|
|---|
| 34 |
|
|---|
| 35 | /* equality between an integer and a possibly null int* */
|
|---|
| 36 | #define eq_opt(x, o) (((x)==*(o))&&(o!=NULL))
|
|---|
| 37 |
|
|---|
| 38 | _Bool duplet(int len, int *except, int *pi, int *pj) {
|
|---|
| 39 | _Bool found = 0;
|
|---|
| 40 |
|
|---|
| 41 | /*@ loop invariant 0 <= i && i <= len - 1;
|
|---|
| 42 | @ loop invariant \forall int k, l;
|
|---|
| 43 | @ 0 <= k && k < i-1 &&
|
|---|
| 44 | @ k < l && l < len ==>
|
|---|
| 45 | @ (!eq_opt(a[k], except) ==> !is_duplet(a, len, k, l));
|
|---|
| 46 | @ loop invariant !found ==> (\forall int l;
|
|---|
| 47 | @ 0 < l && i <= l && l < len ==>
|
|---|
| 48 | @ (!eq_opt(a[i-1], except) ==> !is_duplet(a, len, i-1, l))
|
|---|
| 49 | @ );
|
|---|
| 50 | @ loop invariant found ==> (is_duplet(a, len, *pi, *pj) && *pi == i-1 && *pj > *pi && *pj < len &&
|
|---|
| 51 | @ !eq_opt(a[*pi], except)
|
|---|
| 52 | @ );
|
|---|
| 53 | @ loop invariant !found ==> *pi == 0;
|
|---|
| 54 | @ loop invariant i == 0 ==> !found;
|
|---|
| 55 | @ loop assigns *pi, *pj, found, i;
|
|---|
| 56 | @*/
|
|---|
| 57 | for(int i=0; i <= len - 2 && !found; i++) {
|
|---|
| 58 | int v = a[i];
|
|---|
| 59 |
|
|---|
| 60 | if (except == NULL || *except != v) {
|
|---|
| 61 | /*@ loop invariant i + 1 <= j && j <= len;
|
|---|
| 62 | @ loop invariant \forall int l; i < l && l < j - 1 ==> !is_duplet(a, len, i, l);
|
|---|
| 63 | @ loop invariant !found ==> !is_duplet(a, len, i, j - 1);
|
|---|
| 64 | @ loop invariant !found ==> *pi == 0;
|
|---|
| 65 | @ loop invariant found ==> (is_duplet(a, len, i, j - 1) && (*pi == i && *pj == j - 1));
|
|---|
| 66 | @ loop assigns *pi, *pj, found, j;
|
|---|
| 67 | @*/
|
|---|
| 68 | for (int j = i + 1; j < len && !found; j++) {
|
|---|
| 69 | if (a[j] == v) {
|
|---|
| 70 | *pi = i;
|
|---|
| 71 | *pj = j;
|
|---|
| 72 | found = 1;
|
|---|
| 73 | }
|
|---|
| 74 | }
|
|---|
| 75 | }
|
|---|
| 76 | }
|
|---|
| 77 | $assert(!found => ($forall (int i, j | 0 <= i && i < j && j < len)
|
|---|
| 78 | !eq_opt(a[i], except) => !is_duplet(a, len, i, j))
|
|---|
| 79 | );
|
|---|
| 80 | $assert(found => ($forall (int i, j | 0 <= i && i < *pi && *pi < j && j < len)
|
|---|
| 81 | !eq_opt(a[i], except) => !is_duplet(a, len, i, j))
|
|---|
| 82 | );
|
|---|
| 83 | $assert(is_duplet(a, len, *pi, *pj));
|
|---|
| 84 | return found;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | int pi, pj, pk, pl;
|
|---|
| 88 |
|
|---|
| 89 | int main() {
|
|---|
| 90 | _Bool found_one = duplet(N, NULL, &pi, &pj);
|
|---|
| 91 | _Bool found_two = duplet(N, &a[pi], &pk, &pl);
|
|---|
| 92 |
|
|---|
| 93 | $assert(found_one =>
|
|---|
| 94 | (is_duplet(a, N, pi, pj) && is_duplet(a, N, pk, pl) && a[pi] != a[pk]));
|
|---|
| 95 | }
|
|---|
| 96 |
|
|---|