diff --git a/example/c/README.md b/example/c/README.md index 1ff87f222..d16b9ee46 100644 --- a/example/c/README.md +++ b/example/c/README.md @@ -210,10 +210,7 @@ Reached problem! ## Dobble example - -```c -// An encoding representing the problem of finding a suitable -// set of cards for https://en.wikipedia.org/wiki/Dobble. + + ```c +#define MAX_SIZE 100 + #include +#include -/*@ requires y != 0; - behavior yes: - assumes x % y == 0; - ensures \result == 1; - behavior no: - assumes x % y != 0; - ensures \result == 1; */ -int is_dividable(int x, int y) { - return x % y == 0; +/*@ requires 2 <= n <= MAX_SIZE; + requires \valid(is_prime + (0 .. (n - 1))); + ensures \forall integer i; 0 <= i < n ==> + (is_prime[i] == 1 <==> + (i >= 2 && \forall integer j; 2 <= j < i ==> i % j != 0)); +*/ +void primes(int *is_prime, int n) { + for (int i = 0; i < n; ++i) is_prime[i] = 1; + for (int i = 2; i * i < n; ++i) { + if (is_prime[i] == 0) continue; + for (int j = i; i * j < n; ++j) { + is_prime[i * j] = 0; + } + } } int main(void) { - int x = owi_i32(); - int y = owi_i32(); + int *is_prime; + is_prime = malloc(MAX_SIZE * sizeof(int)); - owi_assume(y != 0); + int n = owi_i32(); + owi_assume(n >= 2); + owi_assume(n <= MAX_SIZE); - is_dividable(x, y); - return 0; + primes(is_prime, n); + return 0; } ``` ```sh -$ owi c --e-acsl ./integer_dividable.c -w1 -... +$ owi c --e-acsl primes.c +Assert failure: false Model: (model - (symbol_0 (i32 1043398666)) - (symbol_1 (i32 387481605))) + (symbol_0 (i32 2))) Reached problem! [13] ``` -The result indicates that our annotation is incorrect with a model where the two symbols have different values, that is the `no` behavior. +The execution got aborted because one of the specifications has been violated with `n = 2`. (The error message is not so informative for the time being, extra information aiding the diagnostic of errors may be added in the future.) -If we correct the `ensures` clause and recall the function: +The problem is that we should mark `0` and `1` as non-prime during the initialization. Let's fix it and rerun the program. - + ```c +#define MAX_SIZE 100 + #include +#include -/*@ requires y != 0; - behavior yes: - assumes x % y == 0; - ensures \result == 1; - behavior no: - assumes x % y != 0; - ensures \result == 0; */ -int is_dividable(int x, int y) { - return x % y == 0; +/*@ requires 2 <= n <= MAX_SIZE; + requires \valid(is_prime + (0 .. (n - 1))); + ensures \forall integer i; 0 <= i < n ==> + (is_prime[i] == 1 <==> + (i >= 2 && \forall integer j; 2 <= j < i ==> i % j != 0)); +*/ +void primes(int *is_prime, int n) { + for (int i = 0; i < n; ++i) is_prime[i] = 1; + is_prime[0] = is_prime[1] = 0; + for (int i = 2; i * i < n; ++i) { + if (is_prime[i] == 0) continue; + for (int j = i; i * j < n; ++j) { + is_prime[i * j] = 0; + } + } } int main(void) { - int x = owi_i32(); - int y = owi_i32(); + int *is_prime; + is_prime = malloc(MAX_SIZE * sizeof(int)); - owi_assume(y != 0); + int n = owi_i32(); + owi_assume(n >= 2); + owi_assume(n <= MAX_SIZE); - is_dividable(x, y); - return 0; + primes(is_prime, n); + return 0; } ``` ```sh -$ owi c --e-acsl ./integer_dividable2.c -w1 +$ owi c --e-acsl primes2.c All OK ``` -The result `All OK` shows that our function annotation is correct. +All the specified properties have been satisfied during the execution. ## Man page diff --git a/example/c/dune b/example/c/dune index 7c906503c..9505c8750 100644 --- a/example/c/dune +++ b/example/c/dune @@ -5,5 +5,7 @@ (file poly.c) (file poly2.c) (file dobble.c) + (file primes.c) + (file primes2.c) (package owi)) (files README.md)) diff --git a/example/c/integer_dividable.c b/example/c/integer_dividable.c deleted file mode 100644 index ef34fc929..000000000 --- a/example/c/integer_dividable.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -/*@ requires y != 0; - behavior yes: - assumes x % y == 0; - ensures \result == 1; - behavior no: - assumes x % y != 0; - ensures \result == 1; */ -int is_dividable(int x, int y) { - return x % y == 0; -} - -int main(void) { - int x = owi_i32(); - int y = owi_i32(); - - owi_assume(y != 0); - - is_dividable(x, y); - return 0; -} diff --git a/example/c/integer_dividable2.c b/example/c/integer_dividable2.c deleted file mode 100644 index 4b713e449..000000000 --- a/example/c/integer_dividable2.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -/*@ requires y != 0; - behavior yes: - assumes x % y == 0; - ensures \result == 1; - behavior no: - assumes x % y != 0; - ensures \result == 0; */ -int is_dividable(int x, int y) { - return x % y == 0; -} - -int main(void) { - int x = owi_i32(); - int y = owi_i32(); - - owi_assume(y != 0); - - is_dividable(x, y); - return 0; -} diff --git a/example/c/primes.c b/example/c/primes.c new file mode 100644 index 000000000..ae04b6626 --- /dev/null +++ b/example/c/primes.c @@ -0,0 +1,32 @@ +#define MAX_SIZE 100 + +#include +#include + +/*@ requires 2 <= n <= MAX_SIZE; + requires \valid(is_prime + (0 .. (n - 1))); + ensures \forall integer i; 0 <= i < n ==> + (is_prime[i] == 1 <==> + (i >= 2 && \forall integer j; 2 <= j < i ==> i % j != 0)); +*/ +void primes(int *is_prime, int n) { + for (int i = 0; i < n; ++i) is_prime[i] = 1; + for (int i = 2; i * i < n; ++i) { + if (is_prime[i] == 0) continue; + for (int j = i; i * j < n; ++j) { + is_prime[i * j] = 0; + } + } +} + +int main(void) { + int *is_prime; + is_prime = malloc(MAX_SIZE * sizeof(int)); + + int n = owi_i32(); + owi_assume(n >= 2); + owi_assume(n <= MAX_SIZE); + + primes(is_prime, n); + return 0; +} diff --git a/example/c/primes2.c b/example/c/primes2.c new file mode 100644 index 000000000..b4c1f7eea --- /dev/null +++ b/example/c/primes2.c @@ -0,0 +1,33 @@ +#define MAX_SIZE 100 + +#include +#include + +/*@ requires 2 <= n <= MAX_SIZE; + requires \valid(is_prime + (0 .. (n - 1))); + ensures \forall integer i; 0 <= i < n ==> + (is_prime[i] == 1 <==> + (i >= 2 && \forall integer j; 2 <= j < i ==> i % j != 0)); +*/ +void primes(int *is_prime, int n) { + for (int i = 0; i < n; ++i) is_prime[i] = 1; + is_prime[0] = is_prime[1] = 0; + for (int i = 2; i * i < n; ++i) { + if (is_prime[i] == 0) continue; + for (int j = i; i * j < n; ++j) { + is_prime[i * j] = 0; + } + } +} + +int main(void) { + int *is_prime; + is_prime = malloc(MAX_SIZE * sizeof(int)); + + int n = owi_i32(); + owi_assume(n >= 2); + owi_assume(n <= MAX_SIZE); + + primes(is_prime, n); + return 0; +}