| 1 | /*
|
|---|
| 2 | * Verify that the abstraction of function 'lcp2' is sound.
|
|---|
| 3 | *
|
|---|
| 4 | * Note: requires Why3 with TIMEOUT > 10 seconds!
|
|---|
| 5 | *
|
|---|
| 6 | * Command: civl verify -collectSymbolicConstants lcp2.cvl
|
|---|
| 7 | */
|
|---|
| 8 | #include <stdlib.h>
|
|---|
| 9 | #include <string.h>
|
|---|
| 10 | #include <civlc.cvh>
|
|---|
| 11 | #include <assert.h>
|
|---|
| 12 |
|
|---|
| 13 | #pragma CIVL ACSL
|
|---|
| 14 |
|
|---|
| 15 | $input int N;
|
|---|
| 16 | $assume(N > 0);
|
|---|
| 17 | $input int X1[N];
|
|---|
| 18 |
|
|---|
| 19 | /* string 'x' is not greater than string 'y' with the specific length */
|
|---|
| 20 | /*@
|
|---|
| 21 | @ predicate ngt_len(int * X1, int N, int x, int y, int l) =
|
|---|
| 22 | @ 0 <= l && l <= N && x + l <= N && y + l <= N
|
|---|
| 23 | @ && (x + l == N || (y + l < N ==> X1[y+l] > X1[x+l]))
|
|---|
| 24 | @ && (\forall int k1; 0 <= k1 && k1 < l ==> X1[(x)+k1] == X1[(y)+k1]);
|
|---|
| 25 | */
|
|---|
| 26 |
|
|---|
| 27 | /* string 'x' is NOT greater than string 'y' */
|
|---|
| 28 | /*@
|
|---|
| 29 | @ predicate ngt(int * X1, int N, int x, int y) =
|
|---|
| 30 | @ (\exists int l; ngt_len(X1, N, x, y, l) &&
|
|---|
| 31 | @ !(\exists int o; ngt_len(X1, N, x, y, o) && o != l)
|
|---|
| 32 | @ );
|
|---|
| 33 | @*/
|
|---|
| 34 |
|
|---|
| 35 | int lcp(int *arr, int n, int x, int y) {
|
|---|
| 36 | int l = 0;
|
|---|
| 37 |
|
|---|
| 38 | /*@ loop invariant 0 <= l && l <= n;
|
|---|
| 39 | @ loop invariant 0 <= x + l && x + l <= n;
|
|---|
| 40 | @ loop invariant 0 <= y + l && y + l <= n;
|
|---|
| 41 | @ loop invariant \forall int i; 0 <= i && i < l ==> arr[x+i]==arr[y+i];
|
|---|
| 42 | @*/
|
|---|
| 43 | while (x+l<n && y+l<n && arr[x+l]==arr[y+l]) {
|
|---|
| 44 | l++;
|
|---|
| 45 | }
|
|---|
| 46 | return l;
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | /* returns:
|
|---|
| 50 | * 0 if x and y points to the same suffix;
|
|---|
| 51 | * poistive value if x "is greater than" y;
|
|---|
| 52 | * negative or zero value if x "is NO greater than" y;
|
|---|
| 53 | */
|
|---|
| 54 | int compare(int *a, int n, int x, int y) {
|
|---|
| 55 | if (x == y) return 0;
|
|---|
| 56 |
|
|---|
| 57 | int c = $choose_int(2);
|
|---|
| 58 | int ret;
|
|---|
| 59 |
|
|---|
| 60 | $havoc(&ret);
|
|---|
| 61 | if (c == 0) {
|
|---|
| 62 | $assume(ngt(X1, N, x, y) && ret <= 0);
|
|---|
| 63 | return ret;
|
|---|
| 64 | } else {
|
|---|
| 65 | $assume(ngt(X1, N, y, x) && ret > 0);
|
|---|
| 66 | return ret;
|
|---|
| 67 | }
|
|---|
| 68 | }
|
|---|
| 69 |
|
|---|
| 70 | void sort(int *a, int n, int *data) {
|
|---|
| 71 | /*@ loop invariant 1 <= i && i <= n;
|
|---|
| 72 | @ loop invariant \forall int k; 1 <= k && k < i ==> ngt(a, n, data[k-1],data[k]);
|
|---|
| 73 | @ loop invariant \forall int k; 0 <= k && k < n ==> 0 <= data[k] && data[k] < n; // data elements are valid
|
|---|
| 74 | @ loop invariant \forall int t, k; 0 <= k && k < n && 0 <= t && t < n && k != t ==>
|
|---|
| 75 | @ data[k] != data[t];
|
|---|
| 76 | @ loop assigns i, data[0 .. n-1];
|
|---|
| 77 | @*/
|
|---|
| 78 | for(int i = 1; i < n; i++) {
|
|---|
| 79 | int comp = compare(a, n, data[i - 1], data[i]);
|
|---|
| 80 |
|
|---|
| 81 | /*@ loop invariant 0 <= j && j <= i;
|
|---|
| 82 | @ loop invariant \forall int k; 0 <= k && k < n ==> 0 <= data[k] && data[k] < n; // data elements are valid
|
|---|
| 83 | @ loop invariant \forall int t, k; 0 <= k && k < n && 0 <= t && t < n && k != t ==>
|
|---|
| 84 | @ data[k] != data[t];
|
|---|
| 85 | @ loop invariant \forall int k; j < k && k <= i ==> ngt(a, n, data[k-1],data[k]);
|
|---|
| 86 | @ loop invariant \forall int k; 0 < k && k < j ==> ngt(a, n, data[k-1],data[k]);
|
|---|
| 87 | @ loop invariant comp <= 0 ==> (\forall int k; 0 < k && k <= j ==> ngt(a, n, data[k-1],data[k]));
|
|---|
| 88 | @ loop invariant (comp > 0 && 0 < j) ==> ngt(a, n, data[j], data[j-1]);
|
|---|
| 89 | @ loop invariant (comp > 0 && 0 < j && j < i) ==> ngt(a, n, data[j-1], data[j+1]) ;
|
|---|
| 90 | @ loop assigns j, comp, data[0 .. n-1];
|
|---|
| 91 | @*/
|
|---|
| 92 | for(int j = i; j > 0 && comp > 0;) {
|
|---|
| 93 | // swap:
|
|---|
| 94 | int tmp = data[j];
|
|---|
| 95 |
|
|---|
| 96 | data[j] = data[j-1];
|
|---|
| 97 | data[j-1] = tmp;
|
|---|
| 98 | j--;
|
|---|
| 99 | if (j > 0)
|
|---|
| 100 | comp = compare(a, n, data[j - 1], data[j]);
|
|---|
| 101 | }
|
|---|
| 102 | }
|
|---|
| 103 | $assert($forall (int i : 1 .. N-1) ngt(a, n, data[i - 1], data[i]));
|
|---|
| 104 | }
|
|---|
| 105 |
|
|---|
| 106 | /* An abstraction of the 'sort' function */
|
|---|
| 107 | void sort2(int *a, int n, int *data) {
|
|---|
| 108 | int new_data[n];
|
|---|
| 109 |
|
|---|
| 110 | memcpy(data, new_data, sizeof(int) * n);
|
|---|
| 111 | $assume($forall (int i : 1 .. N-1) ngt(a, n, data[i - 1], data[i]));
|
|---|
| 112 | $assume($forall (int i : 0 .. N-1) 0 <= data[i] && data[i] < n);
|
|---|
| 113 | $assume($forall (int i : 0 .. N-1)
|
|---|
| 114 | ($forall (int j | 0 <= j && j < N && j != i) data[i] != data[j])
|
|---|
| 115 | );
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | int lcp2(int *a, int n, int index, int* suffixes) {
|
|---|
| 119 | return lcp(a,n,suffixes[index], suffixes[index-1]);
|
|---|
| 120 | }
|
|---|
| 121 |
|
|---|
| 122 | /**
|
|---|
| 123 | result[0]: index
|
|---|
| 124 | result[1]: length
|
|---|
| 125 | */
|
|---|
| 126 | void lrs(int* a, int n, int *result) {
|
|---|
| 127 | int suffixes[n];
|
|---|
| 128 |
|
|---|
| 129 | /*@ loop invariant 0 <= i && i <= n;
|
|---|
| 130 | @ loop invariant \forall int t; 0 <= t && t < i ==> suffixes[t] == t;
|
|---|
| 131 | @ loop assigns suffixes[0 .. n-1], i;
|
|---|
| 132 | @*/
|
|---|
| 133 | for(int i=0; i<n; i++) {
|
|---|
| 134 | suffixes[i] = i;
|
|---|
| 135 | }
|
|---|
| 136 |
|
|---|
| 137 | sort2(a, n, suffixes);
|
|---|
| 138 |
|
|---|
| 139 | int arbi_idx;
|
|---|
| 140 | int len;
|
|---|
| 141 |
|
|---|
| 142 | $havoc(&arbi_idx);
|
|---|
| 143 | $assume(0 < arbi_idx && arbi_idx < n);
|
|---|
| 144 | len = lcp2(a, n, arbi_idx, suffixes);
|
|---|
| 145 | $assert(ngt_len(a, n, suffixes[arbi_idx-1], suffixes[arbi_idx], len));
|
|---|
| 146 | }
|
|---|
| 147 |
|
|---|
| 148 | int main() {
|
|---|
| 149 | int result[2] = {0, 0};
|
|---|
| 150 | lrs(X1, N, result);
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|