
method Range(l: int, r: int) returns (a:array<int>)
requires l <= r
ensures a.Length == r - l 
ensures forall i :: 0 <= i < a.Length ==> a[i] == l + i
{
    a := new int[r - l];
    var i := 0;
    while (i < a.Length)
    decreases (a.Length - i)
    invariant 0 <= i <= a.Length
    invariant forall k :: 0 <= k < i ==> a[k] == l + k
    {
        a[i] := l + i;
        i := i + 1;
    }
}

method Max(a: array<int>) returns (m : int)
requires a.Length > 0
ensures forall i :: 0 <= i < a.Length ==> m >= a[i]
{
    m := a[0];
    var i := 1;
    while i < a.Length
    invariant 0 <= i <= a.Length
    invariant forall k :: 0 <= k < i ==> m >= a[k]
    {
        if a[i] > m {
            m := a[i];
        }
        i := i + 1;
    }
}

method Example(n:int) returns (m : int)
requires n >= 1
ensures m >= n - 1
{ 
    var l := Range(-n, n);
    m := Max(l);
    assert forall i :: 0 <= i < l.Length ==> m >= l[i];
    // This line below is just an assertion, but is necessary
    // for verification to succeed. That's because the
    // mention of l[2*n - 1] is a "hint" to Dafny/Z3 that
    // helps pick an "i" for the quantifier above.
    // The assertion above itself is not necessary, and is
    // added for illustration alone.
    assert l[2*n - 1] == n - 1;
}

// Example of using a `modifies` clause to annotate read/write

method Abs(x: int) returns (y : int)
ensures y >= 0
ensures y == x || y == -x
{ 
    if x < 0 {
        return -x;
    } else {
        return x;
    }
}

method AbsAll(a : array<int>)
modifies a
ensures forall i :: 0 <= i < a.Length ==> a[i] >= 0
{
    var i := 0;
    while i < a.Length
    invariant 0 <= i <= a.Length
    invariant forall k :: 0 <= k < i ==> a[k] >= 0
    {
        a[i] := Abs(a[i]);
        i := i + 1;
    }
}