File: zeros.mlw

package info (click to toggle)
why3 1.8.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 45,028 kB
  • sloc: xml: 185,443; ml: 111,224; ansic: 3,998; sh: 2,578; makefile: 2,568; java: 865; python: 720; javascript: 290; lisp: 205; pascal: 173
file content (112 lines) | stat: -rw-r--r-- 2,743 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

(** Setting all the elements of an array to zero *)

module SetZeros

  use int.Int
  use array.Array

  let set_zeros (a : array int) =
    ensures { forall j: int. 0 <= j < a.length -> a[j] = 0 }
    for i = 0 to a.length - 1 do
      invariant { forall j: int. 0 <= j < i -> a[j] = 0 }
      a[i] <- 0
    done

  let harness () =
    let a0 = make 42 1 in
    set_zeros a0;
    assert { length a0 = 42 };
    assert { a0[12] = 0 }

end

(** Checking that an array contains only zeros *)

module AllZeros

  use int.Int
  use array.Array
  use ref.Refint

  predicate all_zeros (a: array int) (hi: int) =
    forall i: int. 0 <= i < hi -> a[i] = 0

  (** with a for loop (a bit naive, since it always scans the whole array) *)

  let all_zeros1 (a: array int) : bool
    ensures { result <-> all_zeros a a.length }
  =
    let res = ref True in
    for i = 0 to length a - 1 do
      invariant { !res <-> all_zeros a i }
      if a[i] <> 0 then res := False
    done;
    !res

  (** with a while loop, stopping as early as possible *)

  let all_zeros2 (a: array int) : bool
    ensures { result <-> all_zeros a a.length }
  =
    let res = ref True in
    let i = ref 0 in
    while !res && !i < length a do
      invariant { 0 <= !i <= a.length }
      invariant { !res <-> all_zeros a !i }
      variant   { a.length - !i }
      res := (a[!i] = 0);
      incr i
    done;
    !res

  (** no need for a Boolean variable, actually *)

  let all_zeros3 (a: array int) : bool
    ensures { result <-> all_zeros a a.length }
  =
    let i = ref 0 in
    while !i < length a && a[!i] = 0 do
      invariant { 0 <= !i <= a.length }
      invariant { all_zeros a !i }
      variant   { a.length - !i }
      incr i
    done;
    !i = length a

  (** with a recursive function *)

  let all_zeros4 (a: array int) : bool
    ensures { result <-> all_zeros a a.length }
  =
    let rec check_from (i: int) : bool
      requires { 0 <= i <= a.length }
      requires { all_zeros a i }
      variant  { a.length - i }
      ensures  { result <-> all_zeros a a.length }
    = i = length a || a[i] = 0 && check_from (i+1)
    in
    check_from 0

  (** divide-and-conqueer *)

  predicate zero_interval (a: array int) (lo hi: int) =
    forall i: int. lo <= i < hi -> a[i] = 0

  use int.ComputerDivision

  let all_zeros5 (a: array int) : bool
    ensures { result <-> all_zeros a a.length }
  =
    let rec check_between (lo hi: int) : bool
      requires { 0 <= lo <= hi <= a.length }
      variant  { hi - lo }
      ensures  { result <-> zero_interval a lo hi }
    =
      hi <= lo ||
      let mid = lo + div (hi - lo) 2 in
      a[mid] = 0 && check_between lo mid && check_between (mid+1) hi
    in
    check_between 0 (Array.length a)

end