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