File: subsequence.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 (45 lines) | stat: -rw-r--r-- 1,420 bytes parent folder | download | duplicates (2)
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

(** {1 Subsequences}

  A subsequence is a sequence that can be derived from another
  sequence by deleting some or no elements without changing the order
  of the remaining elements (Wikipedia).

  Checking whether a word is a subsequence of another word can be done in
  linear time (in the length of the second word) and is a nice example of
  an optimal greedy algorithm.

  Author: Jean-Christophe Filliâtre (CNRS)

*)

use int.Int
use map.Map
use seq.Seq

type char
type word = seq char

predicate subsequence (v u: word) (f: int -> int) =
  (* f maps v's characters to u's characters *)
  (forall i. 0 <= i < length v -> 0 <= f i < length u /\ v[i] = u[f i]) /\
  (* in a strictly increasing way *)
  (forall i j. 0 <= i < j < length v -> f i < f j)

val eq (x y: char) : bool ensures { result <-> x = y }

let is_subsequence (v u: word) : bool
  ensures { result <-> exists f. subsequence v u f }
= let rec aux (i j: int) (ghost f: int -> int) : bool
    requires { 0 <= i <= length v }
    requires { 0 <= j <= length u }
    requires { subsequence v[0..i] u[0..j] f }
    requires { forall f. subsequence v u f -> i < length v -> f i >= j }
    variant  { length u - j }
    ensures  { result <-> exists f. subsequence v u f }
  = i = length v ||
    j < length u && if eq v[i] u[j] then aux (i+1) (j+1) (Map.set f i j)
                                    else aux     i (j+1) f
  in
  aux 0 0 (fun i -> i)