2013-09-25 10:51:00 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** Maximum subarray problem
|
2013-09-25 10:51:00 +02:00
|
|
|
|
|
|
|
|
Given an array of integers, find the contiguous subarray with the
|
2013-09-25 17:27:41 +02:00
|
|
|
largest sum. Subarrays of length 0 are allowed (which means that an
|
|
|
|
|
array with negative values only has a maximal sum of 0).
|
|
|
|
|
|
|
|
|
|
Authors: Jean-Christophe Filliâtre (CNRS)
|
|
|
|
|
Guillaume Melquiond (Inria)
|
2013-10-19 21:48:02 +02:00
|
|
|
Andrei Paskevich (U-PSUD)
|
2024-02-11 19:11:47 +01:00
|
|
|
*)
|
2013-09-25 10:51:00 +02:00
|
|
|
|
|
|
|
|
module Spec
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
2013-09-25 10:51:00 +02:00
|
|
|
use export array.Array
|
|
|
|
|
|
2013-09-25 17:27:41 +02:00
|
|
|
use export array.ArraySum
|
|
|
|
|
(* provides [sum a l h] = the sum of a[l..h[ and suitable lemmas *)
|
|
|
|
|
|
|
|
|
|
(* s is no smaller than sums of subarrays a[l..h[ with 0 <= l < maxlo *)
|
2013-09-25 11:08:34 +02:00
|
|
|
predicate maxsublo (a: array int) (maxlo: int) (s: int) =
|
2024-02-11 19:11:47 +01:00
|
|
|
forall l h. 0 <= l < maxlo -> l <= h <= length a -> sum a l h <= s
|
2013-09-25 11:08:34 +02:00
|
|
|
|
2013-09-25 17:27:41 +02:00
|
|
|
(* s is no smaller than sums of subarrays of a *)
|
2013-09-25 11:08:34 +02:00
|
|
|
predicate maxsub (a: array int) (s: int) =
|
2024-02-11 19:11:47 +01:00
|
|
|
forall l h. 0 <= l <= h <= length a -> sum a l h <= s
|
2013-09-25 10:51:00 +02:00
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** In all codes below, reference ms stands for the maximal sum found so far
|
2013-09-25 17:27:41 +02:00
|
|
|
and ghost references lo and hi hold the bounds for this sum *)
|
|
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** Naive solution, in O(N^3) *)
|
2013-09-25 10:51:00 +02:00
|
|
|
module Algo1
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
|
|
|
|
use ref.Refint
|
|
|
|
|
use Spec
|
2013-09-25 10:51:00 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
let maximum_subarray (a: array int) (ghost ref lo hi: int): int
|
|
|
|
|
ensures { 0 <= lo <= hi <= length a && result = sum a lo hi }
|
2013-09-25 11:08:34 +02:00
|
|
|
ensures { maxsub a result }
|
2024-02-11 19:11:47 +01:00
|
|
|
= lo <- 0;
|
|
|
|
|
hi <- 0;
|
2013-09-25 10:51:00 +02:00
|
|
|
let n = length a in
|
2024-02-11 19:11:47 +01:00
|
|
|
let ref ms = 0 in
|
2013-09-25 10:51:00 +02:00
|
|
|
for l = 0 to n-1 do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { 0 <= lo <= l && lo <= hi <= n && ms = sum a lo hi }
|
|
|
|
|
invariant { maxsublo a l ms }
|
2013-09-25 11:08:34 +02:00
|
|
|
for h = l to n do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { 0 <= lo <= l && lo <= hi <= n && ms = sum a lo hi }
|
|
|
|
|
invariant { maxsublo a l ms }
|
|
|
|
|
invariant { forall h'. l <= h' < h -> sum a l h' <= ms }
|
2013-09-25 17:27:41 +02:00
|
|
|
(* compute the sum of a[l..h[ *)
|
2024-02-11 19:11:47 +01:00
|
|
|
let ref s = 0 in
|
2013-09-25 11:08:34 +02:00
|
|
|
for i = l to h-1 do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { s = sum a l i }
|
|
|
|
|
invariant { 0 <= lo <= l && lo <= hi <= n && ms = sum a lo hi }
|
2013-09-25 10:51:00 +02:00
|
|
|
s += a[i]
|
|
|
|
|
done;
|
2024-02-11 19:11:47 +01:00
|
|
|
assert { s = sum a l h };
|
|
|
|
|
if s > ms then begin ms <- s; lo <- l; hi <- h end
|
2013-09-25 10:51:00 +02:00
|
|
|
done
|
|
|
|
|
done;
|
2024-02-11 19:11:47 +01:00
|
|
|
ms
|
2013-09-25 10:51:00 +02:00
|
|
|
|
2013-09-25 11:08:34 +02:00
|
|
|
end
|
|
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** Slightly less naive solution, in O(N^2)
|
2013-09-25 17:27:41 +02:00
|
|
|
Do not recompute the sum, simply update it *)
|
2013-09-25 11:16:57 +02:00
|
|
|
|
|
|
|
|
module Algo2
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
|
|
|
|
use ref.Refint
|
|
|
|
|
use Spec
|
2013-09-25 11:16:57 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
let maximum_subarray (a: array int) (ghost ref lo hi: int): int
|
|
|
|
|
ensures { 0 <= lo <= hi <= length a && result = sum a lo hi }
|
2013-09-25 11:16:57 +02:00
|
|
|
ensures { maxsub a result }
|
2024-02-11 19:11:47 +01:00
|
|
|
= lo <- 0;
|
|
|
|
|
hi <- 0;
|
2013-09-25 11:16:57 +02:00
|
|
|
let n = length a in
|
2024-02-11 19:11:47 +01:00
|
|
|
let ref ms = 0 in
|
2013-09-25 11:16:57 +02:00
|
|
|
for l = 0 to n-1 do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { 0 <= lo <= l && lo <= hi <= n && 0 <= ms = sum a lo hi }
|
|
|
|
|
invariant { maxsublo a l ms }
|
|
|
|
|
let ref s = 0 in
|
2013-09-25 11:16:57 +02:00
|
|
|
for h = l+1 to n do
|
|
|
|
|
invariant
|
2024-02-11 19:11:47 +01:00
|
|
|
{ 0 <= lo <= l && lo <= hi <= n && 0 <= ms = sum a lo hi }
|
|
|
|
|
invariant { maxsublo a l ms }
|
|
|
|
|
invariant { forall h'. l <= h' < h -> sum a l h' <= ms }
|
|
|
|
|
invariant { s = sum a l (h-1) }
|
2013-09-25 17:27:41 +02:00
|
|
|
s += a[h-1]; (* update the sum *)
|
2024-02-11 19:11:47 +01:00
|
|
|
assert { s = sum a l h };
|
|
|
|
|
if s > ms then begin ms <- s; lo <- l; hi <- h end
|
2013-09-25 11:16:57 +02:00
|
|
|
done
|
|
|
|
|
done;
|
2024-02-11 19:11:47 +01:00
|
|
|
ms
|
2013-09-25 11:16:57 +02:00
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** Divide-and-conqueer solution, in O(N log N) *)
|
2013-09-25 11:16:57 +02:00
|
|
|
|
2013-09-25 14:41:23 +02:00
|
|
|
module Algo3
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
|
|
|
|
use ref.Refint
|
|
|
|
|
use int.ComputerDivision
|
|
|
|
|
use Spec
|
2013-09-25 14:41:23 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
let rec maximum_subarray_rec (a: array int) (l h: int) (ghost ref lo hi: int)
|
2013-09-25 14:41:23 +02:00
|
|
|
: int
|
|
|
|
|
requires { 0 <= l <= h <= length a }
|
2024-02-11 19:11:47 +01:00
|
|
|
ensures { l <= lo <= hi <= h && result = sum a lo hi }
|
|
|
|
|
ensures { forall l' h'. l <= l' <= h' <= h -> sum a l' h' <= result }
|
2013-09-25 14:41:23 +02:00
|
|
|
variant { h - l }
|
|
|
|
|
= if h = l then begin
|
|
|
|
|
(* base case: no element at all *)
|
2024-02-11 19:11:47 +01:00
|
|
|
lo <- l; hi <- h; 0
|
2013-09-25 14:41:23 +02:00
|
|
|
end else begin
|
|
|
|
|
(* at least one element *)
|
|
|
|
|
let mid = l + div (h - l) 2 in
|
|
|
|
|
(* first consider all sums that include a[mid] *)
|
2024-02-11 19:11:47 +01:00
|
|
|
lo <- mid; hi <- mid;
|
|
|
|
|
let ref ms = 0 in
|
|
|
|
|
let ref s = ms in
|
2013-09-25 14:41:23 +02:00
|
|
|
for i = mid-1 downto l do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { l <= lo <= mid = hi && ms = sum a lo hi }
|
|
|
|
|
invariant { forall l'. i < l' <= mid -> sum a l' mid <= ms }
|
|
|
|
|
invariant { s = sum a (i+1) mid }
|
2013-09-25 14:41:23 +02:00
|
|
|
s += a[i];
|
2024-02-11 19:11:47 +01:00
|
|
|
assert { s = sum a i mid };
|
|
|
|
|
if s > ms then begin ms <- s; lo <- i end
|
2013-09-25 14:41:23 +02:00
|
|
|
done;
|
2024-02-11 19:11:47 +01:00
|
|
|
assert { forall l'. l <= l' <= mid ->
|
|
|
|
|
sum a l' mid <= sum a lo mid };
|
|
|
|
|
s <- ms;
|
2013-09-25 16:55:42 +02:00
|
|
|
for i = mid to h-1 do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { l <= lo <= mid <= hi <= h && ms = sum a lo hi }
|
|
|
|
|
invariant { forall l' h'. l <= l' <= mid <= h' <= i ->
|
|
|
|
|
sum a l' h' <= ms }
|
|
|
|
|
invariant { s = sum a lo i }
|
2013-09-25 14:41:23 +02:00
|
|
|
s += a[i];
|
2024-02-11 19:11:47 +01:00
|
|
|
assert { s = sum a lo (i+1) };
|
|
|
|
|
assert { s = sum a lo mid + sum a mid (i+1) };
|
|
|
|
|
if s > ms then begin ms <- s; hi <- (i+1) end
|
2013-09-25 14:41:23 +02:00
|
|
|
done;
|
2013-09-25 15:04:27 +02:00
|
|
|
(* then consider sums in a[l..mid[ and a[mid+1..h[, recursively *)
|
2013-09-25 16:55:42 +02:00
|
|
|
begin
|
2024-02-11 19:11:47 +01:00
|
|
|
let ghost ref lo' = 0 in
|
|
|
|
|
let ghost ref hi' = 0 in
|
2013-09-25 14:41:23 +02:00
|
|
|
let left = maximum_subarray_rec a l mid lo' hi' in
|
2024-02-11 19:11:47 +01:00
|
|
|
if left > ms then begin ms <- left; lo <- lo'; hi <- hi' end
|
2013-09-25 14:41:23 +02:00
|
|
|
end;
|
2013-09-25 16:55:42 +02:00
|
|
|
begin
|
2024-02-11 19:11:47 +01:00
|
|
|
let ghost ref lo' = 0 in
|
|
|
|
|
let ghost ref hi' = 0 in
|
2013-09-25 14:41:23 +02:00
|
|
|
let right = maximum_subarray_rec a (mid+1) h lo' hi' in
|
2024-02-11 19:11:47 +01:00
|
|
|
if right > ms then begin ms <- right; lo <- lo'; hi <- hi' end
|
2013-09-25 14:41:23 +02:00
|
|
|
end;
|
2024-02-11 19:11:47 +01:00
|
|
|
ms
|
2013-09-25 14:41:23 +02:00
|
|
|
end
|
|
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
let maximum_subarray (a: array int) (ghost ref lo hi: int): int
|
|
|
|
|
ensures { 0 <= lo <= hi <= length a && result = sum a lo hi }
|
2013-09-25 14:41:23 +02:00
|
|
|
ensures { maxsub a result }
|
|
|
|
|
= maximum_subarray_rec a 0 (length a) lo hi
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** Optimal solution, in O(N)
|
|
|
|
|
Known as Kadane's algorithm
|
|
|
|
|
|
|
|
|
|
The key idea is to maintain, in addition to the best sum found so far,
|
|
|
|
|
the best sum that ends at the current point.
|
|
|
|
|
|
|
|
|
|
i
|
|
|
|
|
[ 1 | 7 | -3 | 4 | -7 | 1 | 2 | ...
|
|
|
|
|
<--------------> |
|
|
|
|
|
max sum so far is 9 <----->
|
|
|
|
|
max sum ending at i is 3
|
|
|
|
|
|
|
|
|
|
Then, for each new value a[i], we
|
|
|
|
|
1. update the sum ending at i (in particular, setting it to 0 if a[i]<0);
|
|
|
|
|
2. update the maximal sum.
|
|
|
|
|
*)
|
2013-09-25 14:41:23 +02:00
|
|
|
|
|
|
|
|
module Algo4
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
|
|
|
|
use ref.Refint
|
|
|
|
|
use Spec
|
2013-09-25 14:41:23 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
let maximum_subarray (a: array int) (ghost ref lo hi: int): int
|
|
|
|
|
ensures { 0 <= lo <= hi <= length a && result = sum a lo hi }
|
2013-09-25 14:41:23 +02:00
|
|
|
ensures { maxsub a result }
|
2024-02-11 19:11:47 +01:00
|
|
|
= lo <- 0;
|
|
|
|
|
hi <- 0;
|
2013-09-25 14:41:23 +02:00
|
|
|
let n = length a in
|
2024-02-11 19:11:47 +01:00
|
|
|
let ref ms = 0 in
|
|
|
|
|
let ghost ref l = 0 in
|
|
|
|
|
let ref s = 0 in
|
2013-09-25 14:41:23 +02:00
|
|
|
for i = 0 to n-1 do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { 0 <= lo <= hi <= i && 0 <= ms = sum a lo hi }
|
|
|
|
|
invariant { forall l' h'. 0 <= l' <= h' <= i -> sum a l' h' <= ms }
|
|
|
|
|
invariant { 0 <= l <= i && s = sum a l i }
|
|
|
|
|
invariant { forall l'. 0 <= l' < i -> sum a l' i <= s }
|
|
|
|
|
if s < 0 then begin s <- a[i]; l <- i end else s += a[i];
|
|
|
|
|
if s > ms then begin ms <- s; lo <- l; hi <- (i+1) end
|
2013-09-25 14:41:23 +02:00
|
|
|
done;
|
2024-02-11 19:11:47 +01:00
|
|
|
ms
|
2013-09-25 14:41:23 +02:00
|
|
|
|
|
|
|
|
end
|
2013-10-19 21:48:02 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** A slightly different implementation of Kadane's algorithm *)
|
2013-10-19 21:48:02 +02:00
|
|
|
|
|
|
|
|
module Algo5
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
|
|
|
|
use ref.Refint
|
2013-10-19 21:48:02 +02:00
|
|
|
use export array.Array
|
|
|
|
|
use export array.ArraySum
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
|
[| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |]
|
|
|
|
|
......|###### maxsum #######|..............
|
|
|
|
|
............................. |## curmax ##
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
let maximum_subarray (a: array int): int
|
2024-02-11 19:11:47 +01:00
|
|
|
ensures { forall l h. 0 <= l <= h <= length a -> sum a l h <= result }
|
|
|
|
|
ensures { exists l h. 0 <= l <= h <= length a /\ sum a l h = result }
|
2013-10-19 21:48:02 +02:00
|
|
|
=
|
2024-02-11 19:11:47 +01:00
|
|
|
let ref maxsum = 0 in
|
|
|
|
|
let ref curmax = 0 in
|
|
|
|
|
let ghost ref lo = 0 in
|
|
|
|
|
let ghost ref hi = 0 in
|
|
|
|
|
let ghost ref cl = 0 in
|
2013-10-19 21:48:02 +02:00
|
|
|
for i = 0 to a.length - 1 do
|
2024-02-11 19:11:47 +01:00
|
|
|
invariant { forall l. 0 <= l <= i -> sum a l i <= curmax }
|
|
|
|
|
invariant { 0 <= cl <= i /\ sum a cl i = curmax }
|
|
|
|
|
invariant { forall l h. 0 <= l <= h <= i -> sum a l h <= maxsum }
|
|
|
|
|
invariant { 0 <= lo <= hi <= i /\ sum a lo hi = maxsum }
|
2013-10-19 21:48:02 +02:00
|
|
|
curmax += a[i];
|
2024-02-11 19:11:47 +01:00
|
|
|
if curmax < 0 then begin curmax <- 0; cl <- i+1 end;
|
|
|
|
|
if curmax > maxsum then begin maxsum <- curmax; lo <- cl; hi <- i+1 end
|
2013-10-19 21:48:02 +02:00
|
|
|
done;
|
2024-02-11 19:11:47 +01:00
|
|
|
maxsum
|
2013-10-19 21:48:02 +02:00
|
|
|
|
|
|
|
|
end
|
2017-06-06 11:02:14 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
(** Kadane's algorithm with 63-bit integers
|
2017-06-06 11:02:14 +02:00
|
|
|
|
|
|
|
|
Interestingly, we only have to require all sums to be no greater
|
|
|
|
|
than max_int. There is no need to require the sums to be no
|
|
|
|
|
smaller than min_int, since whenever the sum becomes negative it is
|
|
|
|
|
replaced by the next element. *)
|
|
|
|
|
|
|
|
|
|
module BoundedIntegers
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use int.Int
|
|
|
|
|
use mach.int.Int63
|
|
|
|
|
use mach.int.Refint63
|
|
|
|
|
use seq.Seq
|
|
|
|
|
use mach.array.Array63
|
|
|
|
|
use int.Sum
|
2017-06-06 11:02:14 +02:00
|
|
|
|
|
|
|
|
function sum (a: array int63) (lo hi: int) : int =
|
2017-06-06 14:02:05 +02:00
|
|
|
Sum.sum (fun i -> (a[i] : int)) lo hi
|
2017-06-06 11:02:14 +02:00
|
|
|
|
2024-02-11 19:11:47 +01:00
|
|
|
let maximum_subarray (a: array int63) (ghost ref lo hi: int): int63
|
2018-01-12 18:03:45 +01:00
|
|
|
requires { [@no overflow] forall l h. 0 <= l <= h <= length a ->
|
2017-06-06 11:02:14 +02:00
|
|
|
sum a l h <= max_int }
|
2024-02-11 19:11:47 +01:00
|
|
|
ensures { 0 <= lo <= hi <= length a && result = sum a lo hi }
|
|
|
|
|
ensures { forall l h. 0 <= l <= h <= length a -> result >= sum a lo hi }
|
|
|
|
|
= lo <- 0;
|
|
|
|
|
hi <- 0;
|
2017-06-06 11:02:14 +02:00
|
|
|
let n = length a in
|
2024-02-11 19:11:47 +01:00
|
|
|
let ref ms = zero in
|
|
|
|
|
let ghost ref l = 0 in
|
|
|
|
|
let ref s = zero in
|
|
|
|
|
let ref i = zero in
|
|
|
|
|
while i < n do
|
|
|
|
|
invariant { 0 <= lo <= hi <= i <= n && 0 <= ms = sum a lo hi }
|
|
|
|
|
invariant { forall l' h'. 0 <= l' <= h' <= i -> sum a l' h' <= ms }
|
|
|
|
|
invariant { 0 <= l <= i && s = sum a l i }
|
|
|
|
|
invariant { forall l'. 0 <= l' < i -> sum a l' i <= s }
|
|
|
|
|
variant { n - i }
|
|
|
|
|
if s < zero then begin s <- a[i]; l <- to_int i end
|
|
|
|
|
else begin assert { sum a l (i + 1) <= max_int }; s += a[i] end;
|
|
|
|
|
if s > ms then begin
|
|
|
|
|
ms <- s; lo <- l; hi <- to_int i + 1 end;
|
2017-06-06 11:02:14 +02:00
|
|
|
incr i
|
|
|
|
|
done;
|
2024-02-11 19:11:47 +01:00
|
|
|
ms
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
(** Variant where we seek for the maximal product instead of the
|
|
|
|
|
maximal sum.
|
|
|
|
|
|
|
|
|
|
This is an exercise in Jeff Erickson's book "Algorithms", and the
|
|
|
|
|
author reports that most solutions he could find online were
|
|
|
|
|
incorrect. Indeed, this happens to be subtle to get right.
|
|
|
|
|
|
|
|
|
|
The idea is to maintain *two* maximal products ending at position i,
|
|
|
|
|
one positive and one negative.
|
|
|
|
|
|
|
|
|
|
maximum so far is 10
|
|
|
|
|
<----> i
|
|
|
|
|
3 0 5 2 -1 2 4 1 | ...
|
|
|
|
|
<---------->
|
|
|
|
|
maximum positive product so far is 6
|
|
|
|
|
<-------------------------->
|
|
|
|
|
maximum negative product so far is -60
|
|
|
|
|
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
module MaxProd
|
|
|
|
|
|
|
|
|
|
use int.Int
|
|
|
|
|
use ref.Refint
|
|
|
|
|
use export array.Array
|
|
|
|
|
|
|
|
|
|
(** the product of a[lo..hi[ *)
|
|
|
|
|
let rec function prod (a: array int) (lo hi: int) : int
|
|
|
|
|
requires { 0 <= lo <= hi <= length a }
|
|
|
|
|
variant { hi-lo }
|
|
|
|
|
= if lo = hi then 1 else prod a lo (hi-1) * a[hi-1]
|
|
|
|
|
|
|
|
|
|
let maximum_subarray (a: array int): int
|
|
|
|
|
ensures { forall l h. 0 <= l <= h <= length a -> prod a l h <= result }
|
|
|
|
|
ensures { exists l h. 0 <= l <= h <= length a /\ prod a l h = result }
|
|
|
|
|
=
|
|
|
|
|
let ref maxprd = 1 in
|
|
|
|
|
let ref curmaxp = 1 in
|
|
|
|
|
let ref curmaxn = 0 in
|
|
|
|
|
let ghost ref lo = 0 in
|
|
|
|
|
let ghost ref hi = 0 in
|
|
|
|
|
let ghost ref clp = 0 in
|
|
|
|
|
let ghost ref cln = 0 in
|
|
|
|
|
for i = 0 to a.length - 1 do
|
|
|
|
|
invariant { 0 <= clp <= i /\ prod a clp i = curmaxp >= 1 }
|
|
|
|
|
invariant { forall l. 0 <= l <= i -> 0 <= prod a l i ->
|
|
|
|
|
prod a l i <= curmaxp }
|
|
|
|
|
invariant { curmaxn <= 0 }
|
|
|
|
|
invariant { curmaxn < 0 -> 0 <= cln <= i /\ prod a cln i = curmaxn < 0 }
|
|
|
|
|
invariant { curmaxn < 0 -> forall l. 0 <= l <= i -> prod a l i < 0 ->
|
|
|
|
|
curmaxn <= prod a l i }
|
|
|
|
|
invariant { curmaxn = 0 -> forall l. 0 <= l <= i -> prod a l i >= 0 }
|
|
|
|
|
invariant { forall l h. 0 <= l <= h <= i -> prod a l h <= maxprd }
|
|
|
|
|
invariant { 0 <= lo <= hi <= i /\ prod a lo hi = maxprd >= 1 }
|
|
|
|
|
if a[i] = 0 then (
|
|
|
|
|
curmaxp <- 1; clp <- i+1; curmaxn <- 0; cln <- i+1 )
|
|
|
|
|
else if a[i] > 0 then (
|
|
|
|
|
curmaxp <- curmaxp * a[i];
|
|
|
|
|
curmaxn <- curmaxn * a[i]; )
|
|
|
|
|
else (* a[i] < 0 *)
|
|
|
|
|
if curmaxn < 0 then (
|
|
|
|
|
curmaxp, curmaxn <- curmaxn * a[i], curmaxp * a[i];
|
|
|
|
|
clp, cln <- cln, clp )
|
|
|
|
|
else ( (* curmaxn = 0 i.e. no negative product *)
|
|
|
|
|
curmaxp, curmaxn <- 1, curmaxp * a[i];
|
|
|
|
|
clp, cln <- i+1, clp; )
|
|
|
|
|
;
|
|
|
|
|
if curmaxp > maxprd then (
|
|
|
|
|
maxprd <- curmaxp; lo <- clp; hi <- i+1
|
|
|
|
|
)
|
|
|
|
|
done;
|
|
|
|
|
maxprd
|
2017-06-06 11:02:14 +02:00
|
|
|
|
|
|
|
|
end
|