Functional Data Structures - University of Cambridge · 2020. 4. 15. · Functional Data Structures...

260
Functional Data Structures Tobias Nipkow February 20, 2021 Abstract A collection of verified functional data structures. The emphasis is on conciseness of algorithms and succinctness of proofs, more in the style of a textbook than a library of efficient algorithms. For more details see [13]. Contents 1 Sorting 4 2 Creating Almost Complete Trees 13 3 Three-Way Comparison 19 4 Lists Sorted wrt < 20 5 List Insertion and Deletion 21 6 Specifications of Set ADT 24 7 Unbalanced Tree Implementation of Set 26 8 Association List Update and Deletion 29 9 Specifications of Map ADT 32 10 Unbalanced Tree Implementation of Map 34 11 Augmented Tree (Tree2) 36 12 Function isin for Tree2 37 13 Interval Trees 37 14 AVL Tree Implementation of Sets 44 1

Transcript of Functional Data Structures - University of Cambridge · 2020. 4. 15. · Functional Data Structures...

  • Functional Data Structures

    Tobias Nipkow

    February 20, 2021

    Abstract

    A collection of verified functional data structures. The emphasis ison conciseness of algorithms and succinctness of proofs, more in thestyle of a textbook than a library of efficient algorithms.

    For more details see [13].

    Contents

    1 Sorting 4

    2 Creating Almost Complete Trees 13

    3 Three-Way Comparison 19

    4 Lists Sorted wrt < 20

    5 List Insertion and Deletion 21

    6 Specifications of Set ADT 24

    7 Unbalanced Tree Implementation of Set 26

    8 Association List Update and Deletion 29

    9 Specifications of Map ADT 32

    10 Unbalanced Tree Implementation of Map 34

    11 Augmented Tree (Tree2) 36

    12 Function isin for Tree2 37

    13 Interval Trees 37

    14 AVL Tree Implementation of Sets 44

    1

  • 15 Function lookup for Tree2 54

    16 AVL Tree Implementation of Maps 55

    17 AVL Tree with Balance Factors (1) 59

    18 AVL Tree with Balance Factors (2) 63

    19 Height-Balanced Trees 68

    20 Red-Black Trees 77

    21 Red-Black Tree Implementation of Sets 78

    22 Alternative Deletion in Red-Black Trees 85

    23 Red-Black Tree Implementation of Maps 89

    24 2-3 Trees 91

    25 2-3 Tree Implementation of Sets 92

    26 2-3 Tree Implementation of Maps 101

    27 2-3 Tree from List 105

    28 2-3-4 Trees 108

    29 2-3-4 Tree Implementation of Sets 109

    30 2-3-4 Tree Implementation of Maps 122

    31 1-2 Brother Tree Implementation of Sets 126

    32 1-2 Brother Tree Implementation of Maps 139

    33 AA Tree Implementation of Sets 144

    34 AA Tree Implementation of Maps 156

    35 Join-Based Implementation of Sets 161

    36 Join-Based Implementation of Sets via RBTs 169

    37 Braun Trees 176

    38 Arrays via Braun Trees 180

    2

  • 39 Tries via Functions 195

    40 Tries via Search Trees 197

    41 Binary Tries and Patricia Tries 200

    42 Queue Specification 206

    43 Queue Implementation via 2 Lists 207

    44 Priority Queue Specifications 209

    45 Heaps 210

    46 Leftist Heap 212

    47 Binomial Heap 217

    48 Time functions for various standard library operations 232

    49 The Median-of-Medians Selection Algorithm 233

    50 Bibliographic Notes 258

    3

  • 1 Sorting

    theory SortingimportsComplex MainHOL−Library .Multiset

    begin

    hide const List .insort

    declare Let def [simp]

    1.1 Insertion Sort

    fun insort :: ′a::linorder ⇒ ′a list ⇒ ′a list whereinsort x [] = [x ] |insort x (y#ys) =(if x ≤ y then x#y#ys else y#(insort x ys))

    fun isort :: ′a::linorder list ⇒ ′a list whereisort [] = [] |isort (x#xs) = insort x (isort xs)

    1.1.1 Functional Correctness

    lemma mset insort : mset (insort x xs) = {#x#} + mset xsapply(induction xs)apply autodone

    lemma mset isort : mset (isort xs) = mset xsapply(induction xs)apply simpapply (simp add : mset insort)done

    lemma set insort : set (insort x xs) = {x} ∪ set xsby(simp add : mset insort flip: set mset mset)

    lemma sorted insort : sorted (insort a xs) = sorted xsapply(induction xs)apply(auto simp add : set insort)done

    lemma sorted isort : sorted (isort xs)

    4

  • apply(induction xs)apply(auto simp: sorted insort)done

    1.1.2 Time Complexity

    We count the number of function calls.

    insort x [] = [x ] insort x (y#ys) = (if x ≤ y then x#y#ys else y#(insortx ys))

    fun T insort :: ′a::linorder ⇒ ′a list ⇒ nat whereT insort x [] = 1 |T insort x (y#ys) =(if x ≤ y then 0 else T insort x ys) + 1

    isort [] = [] isort (x#xs) = insort x (isort xs)

    fun T isort :: ′a::linorder list ⇒ nat whereT isort [] = 1 |T isort (x#xs) = T isort xs + T insort x (isort xs) + 1

    lemma T insort length: T insort x xs ≤ length xs + 1apply(induction xs)apply autodone

    lemma length insort : length (insort x xs) = length xs + 1apply(induction xs)apply autodone

    lemma length isort : length (isort xs) = length xsapply(induction xs)apply (auto simp: length insort)done

    lemma T isort length: T isort xs ≤ (length xs + 1 ) ˆ 2proof(induction xs)case Nil show ?case by simp

    nextcase (Cons x xs)have T isort (x#xs) = T isort xs + T insort x (isort xs) + 1 by simpalso have . . . ≤ (length xs + 1 ) ˆ 2 + T insort x (isort xs) + 1using Cons.IH by simp

    5

  • also have . . . ≤ (length xs + 1 ) ˆ 2 + length xs + 1 + 1using T insort length[of x isort xs] by (simp add : length isort)

    also have . . . ≤ (length(x#xs) + 1 ) ˆ 2by (simp add : power2 eq square)

    finally show ?case .qed

    1.2 Merge Sort

    fun merge :: ′a::linorder list ⇒ ′a list ⇒ ′a list wheremerge [] ys = ys |merge xs [] = xs |merge (x#xs) (y#ys) = (if x ≤ y then x # merge xs (y#ys) else y #merge (x#xs) ys)

    fun msort :: ′a::linorder list ⇒ ′a list wheremsort xs = (let n = length xs inif n ≤ 1 then xselse merge (msort (take (n div 2 ) xs)) (msort (drop (n div 2 ) xs)))

    declare msort .simps [simp del ]

    1.2.1 Functional Correctness

    lemma mset merge: mset(merge xs ys) = mset xs + mset ysby(induction xs ys rule: merge.induct) auto

    lemma mset msort : mset (msort xs) = mset xsproof(induction xs rule: msort .induct)case (1 xs)let ?n = length xslet ?ys = take (?n div 2 ) xslet ?zs = drop (?n div 2 ) xsshow ?caseproof casesassume ?n ≤ 1thus ?thesis by(simp add : msort .simps[of xs])

    nextassume ¬ ?n ≤ 1hence mset (msort xs) = mset (msort ?ys) + mset (msort ?zs)by(simp add : msort .simps[of xs] mset merge)

    also have . . . = mset ?ys + mset ?zsusing 〈¬ ?n ≤ 1 〉 by(simp add : 1 .IH )

    also have . . . = mset (?ys @ ?zs) by (simp del : append take drop id)

    6

  • also have . . . = mset xs by simpfinally show ?thesis .

    qedqed

    Via the previous lemma or directly:

    lemma set merge: set(merge xs ys) = set xs ∪ set ysby (metis mset merge set mset mset set mset union)

    lemma set(merge xs ys) = set xs ∪ set ysby(induction xs ys rule: merge.induct) (auto)

    lemma sorted merge: sorted (merge xs ys) ←→ (sorted xs ∧ sorted ys)by(induction xs ys rule: merge.induct) (auto simp: set merge)

    lemma sorted msort : sorted (msort xs)proof(induction xs rule: msort .induct)case (1 xs)let ?n = length xsshow ?caseproof casesassume ?n ≤ 1thus ?thesis by(simp add : msort .simps[of xs] sorted01 )

    nextassume ¬ ?n ≤ 1thus ?thesis using 1 .IHby(simp add : sorted merge msort .simps[of xs])

    qedqed

    1.2.2 Time Complexity

    We only count the number of comparisons between list elements.

    fun C merge :: ′a::linorder list ⇒ ′a list ⇒ nat whereC merge [] ys = 0 |C merge xs [] = 0 |C merge (x#xs) (y#ys) = 1 + (if x ≤ y then C merge xs (y#ys) elseC merge (x#xs) ys)

    lemma C merge ub: C merge xs ys ≤ length xs + length ysby (induction xs ys rule: C merge.induct) auto

    fun C msort :: ′a::linorder list ⇒ nat whereC msort xs =

    7

  • (let n = length xs;ys = take (n div 2 ) xs;zs = drop (n div 2 ) xs

    in if n ≤ 1 then 0else C msort ys + C msort zs + C merge (msort ys) (msort zs))

    declare C msort .simps [simp del ]

    lemma length merge: length(merge xs ys) = length xs + length ysapply (induction xs ys rule: merge.induct)apply autodone

    lemma length msort : length(msort xs) = length xsproof (induction xs rule: msort .induct)case (1 xs)show ?caseby (auto simp: msort .simps [of xs] 1 length merge)

    qed

    Why structured proof? To have the name ”xs” to specialize msort.simpswith xs to ensure that msort.simps cannot be used recursively. Also workswithout this precaution, but that is just luck.

    lemma C msort le: length xs = 2ˆk =⇒ C msort xs ≤ k ∗ 2ˆkproof(induction k arbitrary : xs)case 0 thus ?case by (simp add : C msort .simps)

    nextcase (Suc k)let ?n = length xslet ?ys = take (?n div 2 ) xslet ?zs = drop (?n div 2 ) xsshow ?caseproof (cases ?n ≤ 1 )case Truethus ?thesis by(simp add : C msort .simps)

    nextcase Falsehave C msort(xs) =C msort ?ys + C msort ?zs + C merge (msort ?ys) (msort ?zs)by (simp add : C msort .simps msort .simps)

    also have . . . ≤ C msort ?ys + C msort ?zs + length ?ys + length ?zsusing C merge ub[of msort ?ys msort ?zs] length msort [of ?ys] length msort [of

    ?zs]by arith

    8

  • also have . . . ≤ k ∗ 2ˆk + C msort ?zs + length ?ys + length ?zsusing Suc.IH [of ?ys] Suc.prems by simp

    also have . . . ≤ k ∗ 2ˆk + k ∗ 2ˆk + length ?ys + length ?zsusing Suc.IH [of ?zs] Suc.prems by simp

    also have . . . = 2 ∗ k ∗ 2ˆk + 2 ∗ 2 ˆ kusing Suc.prems by simp

    finally show ?thesis by simpqed

    qed

    lemma C msort log : length xs = 2ˆk =⇒ C msort xs ≤ length xs ∗ log 2(length xs)using C msort le[of xs k ] apply (simp add : log nat power algebra simps)by (metis (mono tags) numeral power eq of nat cancel iff of nat le iff of nat mult)

    1.3 Bottom-Up Merge Sort

    fun merge adj :: ( ′a::linorder) list list ⇒ ′a list list wheremerge adj [] = [] |merge adj [xs] = [xs] |merge adj (xs # ys # zss) = merge xs ys # merge adj zss

    For the termination proof of merge all below.

    lemma length merge adjacent [simp]: length (merge adj xs) = (length xs +1 ) div 2by (induction xs rule: merge adj .induct) auto

    fun merge all :: ( ′a::linorder) list list ⇒ ′a list wheremerge all [] = [] |merge all [xs] = xs |merge all xss = merge all (merge adj xss)

    definition msort bu :: ( ′a::linorder) list ⇒ ′a list wheremsort bu xs = merge all (map (λx . [x ]) xs)

    1.3.1 Functional Correctness

    abbreviation mset mset :: ′a list list ⇒ ′a multiset wheremset mset xss ≡

    ∑# (image mset mset (mset xss))

    lemma mset merge adj :mset mset (merge adj xss) = mset mset xss

    by(induction xss rule: merge adj .induct) (auto simp: mset merge)

    9

  • lemma mset merge all :mset (merge all xss) = mset mset xss

    by(induction xss rule: merge all .induct) (auto simp: mset merge mset merge adj )

    lemma mset msort bu: mset (msort bu xs) = mset xsby(simp add : msort bu def mset merge all multiset .map comp comp def )

    lemma sorted merge adj :∀ xs ∈ set xss. sorted xs =⇒ ∀ xs ∈ set (merge adj xss). sorted xs

    by(induction xss rule: merge adj .induct) (auto simp: sorted merge)

    lemma sorted merge all :∀ xs ∈ set xss. sorted xs =⇒ sorted (merge all xss)

    apply(induction xss rule: merge all .induct)using [[simp depth limit=3 ]] by (auto simp add : sorted merge adj )

    lemma sorted msort bu: sorted (msort bu xs)by(simp add : msort bu def sorted merge all)

    1.3.2 Time Complexity

    fun C merge adj :: ( ′a::linorder) list list ⇒ nat whereC merge adj [] = 0 |C merge adj [xs] = 0 |C merge adj (xs # ys # zss) = C merge xs ys + C merge adj zss

    fun C merge all :: ( ′a::linorder) list list ⇒ nat whereC merge all [] = 0 |C merge all [xs] = 0 |C merge all xss = C merge adj xss + C merge all (merge adj xss)

    definition C msort bu :: ( ′a::linorder) list ⇒ nat whereC msort bu xs = C merge all (map (λx . [x ]) xs)

    lemma length merge adj :[[ even(length xss); ∀ xs ∈ set xss. length xs = m ]]=⇒ ∀ xs ∈ set (merge adj xss). length xs = 2∗m

    by(induction xss rule: merge adj .induct) (auto simp: length merge)

    lemma C merge adj : ∀ xs ∈ set xss. length xs = m =⇒ C merge adj xss ≤m ∗ length xssproof(induction xss rule: C merge adj .induct)case 1 thus ?case by simp

    next

    10

  • case 2 thus ?case by simpnextcase (3 x y) thus ?case using C merge ub[of x y ] by (simp add : alge-

    bra simps)qed

    lemma C merge all : [[ ∀ xs ∈ set xss. length xs = m; length xss = 2ˆk ]]=⇒ C merge all xss ≤ m ∗ k ∗ 2ˆk

    proof (induction xss arbitrary : k m rule: C merge all .induct)case 1 thus ?case by simp

    nextcase 2 thus ?case by simp

    nextcase (3 xs ys xss)let ?xss = xs # ys # xsslet ?xss2 = merge adj ?xssobtain k ′ where k ′: k = Suc k ′ using 3 .prems(2 )by (metis length Cons nat .inject nat power eq Suc 0 iff nat .exhaust)

    have even (length ?xss) using 3 .prems(2 ) k ′ by autofrom length merge adj [OF this 3 .prems(1 )]have ∗: ∀ x ∈ set(merge adj ?xss). length x = 2∗m .have ∗∗: length ?xss2 = 2 ˆ k ′ using 3 .prems(2 ) k ′ by autohave C merge all ?xss = C merge adj ?xss + C merge all ?xss2 by simpalso have . . . ≤ m ∗ 2ˆk + C merge all ?xss2

    using 3 .prems(2 ) C merge adj [OF 3 .prems(1 )] by (auto simp: alge-bra simps)also have . . . ≤ m ∗ 2ˆk + (2∗m) ∗ k ′ ∗ 2ˆk ′using 3 .IH [OF ∗ ∗∗] by simp

    also have . . . = m ∗ k ∗ 2ˆkusing k ′ by (simp add : algebra simps)

    finally show ?case .qed

    corollary C msort bu: length xs = 2 ˆ k =⇒ C msort bu xs ≤ k ∗ 2 ˆ kusing C merge all [of map (λx . [x ]) xs 1 ] by (simp add : C msort bu def )

    1.4 Quicksort

    fun quicksort :: ( ′a::linorder) list ⇒ ′a list wherequicksort [] = [] |quicksort (x#xs) = quicksort (filter (λy . y < x ) xs) @ [x ] @ quicksort (filter(λy . x ≤ y) xs)

    lemma mset quicksort : mset (quicksort xs) = mset xs

    11

  • apply (induction xs rule: quicksort .induct)apply (auto simp: not le)done

    lemma set quicksort : set (quicksort xs) = set xsby(rule mset eq setD [OF mset quicksort ])

    lemma sorted quicksort : sorted (quicksort xs)apply (induction xs rule: quicksort .induct)apply (auto simp add : sorted append set quicksort)done

    1.5 Insertion Sort w.r.t. Keys and Stability

    Note that insort key is already defined in theory HOL.List. Thus some ofthe lemmas are already present as well.

    fun isort key :: ( ′a ⇒ ′k ::linorder) ⇒ ′a list ⇒ ′a list whereisort key f [] = [] |isort key f (x # xs) = insort key f x (isort key f xs)

    1.5.1 Standard functional correctness

    lemma mset insort key : mset (insort key f x xs) = {#x#} + mset xsby(induction xs) simp all

    lemma mset isort key : mset (isort key f xs) = mset xsby(induction xs) (simp all add : mset insort key)

    lemma set isort key : set (isort key f xs) = set xsby (rule mset eq setD [OF mset isort key ])

    lemma sorted insort key : sorted (map f (insort key f a xs)) = sorted (mapf xs)by(induction xs)(auto simp: set insort key)

    lemma sorted isort key : sorted (map f (isort key f xs))by(induction xs)(simp all add : sorted insort key)

    1.5.2 Stability

    lemma insort is Cons: ∀ x∈set xs. f a ≤ f x =⇒ insort key f a xs = a #xsby (cases xs) auto

    12

  • lemma filter insort key neg :¬ P x =⇒ filter P (insort key f x xs) = filter P xs

    by (induction xs) simp all

    lemma filter insort key pos:sorted (map f xs) =⇒ P x =⇒ filter P (insort key f x xs) = insort key f

    x (filter P xs)by (induction xs) (auto, subst insort is Cons, auto)

    lemma sort key stable: filter (λy . f y = k) (isort key f xs) = filter (λy . f y= k) xsproof (induction xs)case Nil thus ?case by simp

    nextcase (Cons a xs)thus ?caseproof (cases f a = k)case False thus ?thesis by (simp add : Cons.IH filter insort key neg)

    nextcase Truehave filter (λy . f y = k) (isort key f (a # xs))= filter (λy . f y = k) (insort key f a (isort key f xs)) by simp

    also have . . . = insort key f a (filter (λy . f y = k) (isort key f xs))by (simp add : True filter insort key pos sorted isort key)

    also have . . . = insort key f a (filter (λy . f y = k) xs) by (simp add :Cons.IH )

    also have . . . = a # (filter (λy . f y = k) xs) by(simp add : Trueinsort is Cons)

    also have . . . = filter (λy . f y = k) (a # xs) by (simp add : True)finally show ?thesis .

    qedqed

    end

    2 Creating Almost Complete Trees

    theory BalanceimportsHOL−Library .Tree Real

    begin

    fun bal :: nat ⇒ ′a list ⇒ ′a tree ∗ ′a list where

    13

  • bal n xs = (if n=0 then (Leaf ,xs) else(let m = n div 2 ;

    (l , ys) = bal m xs;(r , zs) = bal (n−1−m) (tl ys)

    in (Node l (hd ys) r , zs)))

    declare bal .simps[simp del ]declare Let def [simp]

    definition bal list :: nat ⇒ ′a list ⇒ ′a tree wherebal list n xs = fst (bal n xs)

    definition balance list :: ′a list ⇒ ′a tree wherebalance list xs = bal list (length xs) xs

    definition bal tree :: nat ⇒ ′a tree ⇒ ′a tree wherebal tree n t = bal list n (inorder t)

    definition balance tree :: ′a tree ⇒ ′a tree wherebalance tree t = bal tree (size t) t

    lemma bal simps:bal 0 xs = (Leaf , xs)n > 0 =⇒bal n xs =(let m = n div 2 ;

    (l , ys) = bal m xs;(r , zs) = bal (n−1−m) (tl ys)

    in (Node l (hd ys) r , zs))by(simp all add : bal .simps)

    lemma bal inorder :[[ n ≤ length xs; bal n xs = (t ,zs) ]]=⇒ xs = inorder t @ zs ∧ size t = n

    proof(induction n arbitrary : xs t zs rule: less induct)case (less n) show ?caseproof casesassume n = 0 thus ?thesis using less.prems by (simp add : bal simps)

    nextassume [arith]: n 6= 0let ?m = n div 2 let ?m ′ = n − 1 − ?mfrom less.prems(2 ) obtain l r ys whereb1 : bal ?m xs = (l ,ys) andb2 : bal ?m ′ (tl ys) = (r ,zs) and

    14

  • t : t = 〈l , hd ys, r〉by(auto simp: bal simps split : prod .splits)

    have IH1 : xs = inorder l @ ys ∧ size l = ?musing b1 less.prems(1 ) by(intro less.IH ) auto

    have IH2 : tl ys = inorder r @ zs ∧ size r = ?m ′using b2 IH1 less.prems(1 ) by(intro less.IH ) autoshow ?thesis using t IH1 IH2 less.prems(1 ) hd Cons tl [of ys] by

    fastforceqed

    qed

    corollary inorder bal list [simp]:n ≤ length xs =⇒ inorder(bal list n xs) = take n xs

    unfolding bal list defby (metis (mono tags) prod .collapse[of bal n xs] append eq conv conj bal inorderlength inorder)

    corollary inorder balance list [simp]: inorder(balance list xs) = xsby(simp add : balance list def )

    corollary inorder bal tree:n ≤ size t =⇒ inorder(bal tree n t) = take n (inorder t)

    by(simp add : bal tree def )

    corollary inorder balance tree[simp]: inorder(balance tree t) = inorder tby(simp add : balance tree def inorder bal tree)

    The length/size lemmas below do not require the precondition n ≤ lengthxs (or n ≤ size t) that they come with. They could take advantage of the factthat bal xs n yields a result even if length xs < n. In that case the result willcontain one or more occurrences of hd []. However, this is counter-intuitiveand does not reflect the execution in an eager functional language.

    lemma bal length: [[ n ≤ length xs; bal n xs = (t ,zs) ]] =⇒ length zs =length xs − nusing bal inorder by fastforce

    corollary size bal list [simp]: n ≤ length xs =⇒ size(bal list n xs) = nunfolding bal list def using bal inorder prod .exhaust sel by blast

    corollary size balance list [simp]: size(balance list xs) = length xsby (simp add : balance list def )

    corollary size bal tree[simp]: n ≤ size t =⇒ size(bal tree n t) = nby(simp add : bal tree def )

    15

  • corollary size balance tree[simp]: size(balance tree t) = size tby(simp add : balance tree def )

    lemma min height bal :[[ n ≤ length xs; bal n xs = (t ,zs) ]] =⇒ min height t = nat(blog 2 (n +

    1 )c)proof(induction n arbitrary : xs t zs rule: less induct)case (less n)show ?caseproof casesassume n = 0 thus ?thesis using less.prems(2 ) by (simp add : bal simps)nextassume [arith]: n 6= 0let ?m = n div 2 let ?m ′ = n − 1 − ?mfrom less.prems obtain l r ys whereb1 : bal ?m xs = (l ,ys) andb2 : bal ?m ′ (tl ys) = (r ,zs) andt : t = 〈l , hd ys, r〉by(auto simp: bal simps split : prod .splits)

    let ?hl = nat (floor(log 2 (?m + 1 )))let ?hr = nat (floor(log 2 (?m ′ + 1 )))have IH1 : min height l = ?hl using less.IH [OF b1 ] less.prems(1 )

    by simphave IH2 : min height r = ?hrusing less.prems(1 ) bal length[OF b1 ] b2 by(intro less.IH ) auto

    have (n+1 ) div 2 ≥ 1 by arithhence 0 : log 2 ((n+1 ) div 2 ) ≥ 0 by simphave ?m ′ ≤ ?m by arithhence le: ?hr ≤ ?hl by(simp add : nat mono floor mono)have min height t = min ?hl ?hr + 1 by (simp add : t IH1 IH2 )also have . . . = ?hr + 1 using le by (simp add : min absorb2 )also have ?m ′ + 1 = (n+1 ) div 2 by linarithalso have nat (floor(log 2 ((n+1 ) div 2 ))) + 1

    = nat (floor(log 2 ((n+1 ) div 2 ) + 1 ))using 0 by linarith

    also have . . . = nat (floor(log 2 (n + 1 )))using floor log2 div2 [of n+1 ] by (simp add : log mult)

    finally show ?thesis .qed

    qed

    lemma height bal :[[ n ≤ length xs; bal n xs = (t ,zs) ]] =⇒ height t = nat dlog 2 (n + 1 )e

    16

  • proof(induction n arbitrary : xs t zs rule: less induct)case (less n) show ?caseproof casesassume n = 0 thus ?thesisusing less.prems by (simp add : bal simps)

    nextassume [arith]: n 6= 0let ?m = n div 2 let ?m ′ = n − 1 − ?mfrom less.prems obtain l r ys whereb1 : bal ?m xs = (l ,ys) andb2 : bal ?m ′ (tl ys) = (r ,zs) andt : t = 〈l , hd ys, r〉by(auto simp: bal simps split : prod .splits)

    let ?hl = nat dlog 2 (?m + 1 )elet ?hr = nat dlog 2 (?m ′ + 1 )ehave IH1 : height l = ?hl using less.IH [OF b1 ] less.prems(1 ) by

    simphave IH2 : height r = ?hrusing b2 bal length[OF b1 ] less.prems(1 ) by(intro less.IH ) auto

    have 0 : log 2 (?m + 1 ) ≥ 0 by simphave ?m ′ ≤ ?m by arithhence le: ?hr ≤ ?hlby(simp add : nat mono ceiling mono del : nat ceiling le eq)

    have height t = max ?hl ?hr + 1 by (simp add : t IH1 IH2 )also have . . . = ?hl + 1 using le by (simp add : max absorb1 )also have . . . = nat dlog 2 (?m + 1 ) + 1 e using 0 by linarithalso have . . . = nat dlog 2 (n + 1 )eusing ceiling log2 div2 [of n+1 ] by (simp)

    finally show ?thesis .qed

    qed

    lemma acomplete bal :assumes n ≤ length xs bal n xs = (t ,ys) shows acomplete t

    unfolding acomplete defusing height bal [OF assms] min height bal [OF assms]by linarith

    lemma height bal list :n ≤ length xs =⇒ height (bal list n xs) = nat dlog 2 (n + 1 )e

    unfolding bal list def by (metis height bal prod .collapse)

    lemma height balance list :height (balance list xs) = nat dlog 2 (length xs + 1 )e

    17

  • by (simp add : balance list def height bal list)

    corollary height bal tree:n ≤ size t =⇒ height (bal tree n t) = natdlog 2 (n + 1 )e

    unfolding bal list def bal tree defby (metis bal list def height bal list length inorder)

    corollary height balance tree:height (balance tree t) = natdlog 2 (size t + 1 )e

    by (simp add : bal tree def balance tree def height bal list)

    corollary acomplete bal list [simp]: n ≤ length xs =⇒ acomplete (bal list nxs)unfolding bal list def by (metis acomplete bal prod .collapse)

    corollary acomplete balance list [simp]: acomplete (balance list xs)by (simp add : balance list def )

    corollary acomplete bal tree[simp]: n ≤ size t =⇒ acomplete (bal tree n t)by (simp add : bal tree def )

    corollary acomplete balance tree[simp]: acomplete (balance tree t)by (simp add : balance tree def )

    lemma wbalanced bal : [[ n ≤ length xs; bal n xs = (t ,ys) ]] =⇒ wbalanced tproof(induction n arbitrary : xs t ys rule: less induct)case (less n)show ?caseproof casesassume n = 0thus ?thesis using less.prems(2 ) by(simp add : bal simps)

    nextassume [arith]: n 6= 0with less.prems obtain l ys r zs whererec1 : bal (n div 2 ) xs = (l , ys) andrec2 : bal (n − 1 − n div 2 ) (tl ys) = (r , zs) andt : t = 〈l , hd ys, r〉by(auto simp add : bal simps split : prod .splits)

    have l : wbalanced l using less.IH [OF rec1 ] less.prems(1 ) by linarithhave wbalanced rusing rec1 rec2 bal length[OF rec1 ] less.prems(1 ) by(intro less.IH )

    autowith l t bal length[OF rec1 ] less.prems(1 ) bal inorder [OF rec1 ]

    bal inorder [OF rec2 ]

    18

  • show ?thesis by autoqed

    qed

    An alternative proof via wbalanced ?t =⇒ acomplete ?t :lemma [[ n ≤ length xs; bal n xs = (t ,ys) ]] =⇒ acomplete tby(rule acomplete if wbalanced [OF wbalanced bal ])

    lemma wbalanced bal list [simp]: n ≤ length xs =⇒ wbalanced (bal list n xs)by(simp add : bal list def ) (metis prod .collapse wbalanced bal)

    lemma wbalanced balance list [simp]: wbalanced (balance list xs)by(simp add : balance list def )

    lemma wbalanced bal tree[simp]: n ≤ size t =⇒ wbalanced (bal tree n t)by(simp add : bal tree def )

    lemma wbalanced balance tree: wbalanced (balance tree t)by (simp add : balance tree def )

    hide const (open) bal

    end

    3 Three-Way Comparison

    theory Cmpimports Mainbegin

    datatype cmp val = LT | EQ | GT

    definition cmp :: ′a:: linorder ⇒ ′a ⇒ cmp val wherecmp x y = (if x < y then LT else if x=y then EQ else GT )

    lemmaLT [simp]: cmp x y = LT ←→ x < y

    and EQ [simp]: cmp x y = EQ ←→ x = yand GT [simp]: cmp x y = GT ←→ x > yby (auto simp: cmp def )

    lemma case cmp if [simp]: (case c of EQ ⇒ e | LT ⇒ l | GT ⇒ g) =(if c = LT then l else if c = GT then g else e)

    by(simp split : cmp val .split)

    19

  • end

    4 Lists Sorted wrt <

    theory Sorted Lessimports Less Falsebegin

    hide const sorted

    Is a list sorted without duplicates, i.e., wrt

  • lemma sorted mid iff ′: NO MATCH [] ys =⇒sorted(xs @ y # ys) = (sorted(xs @ [y ]) ∧ sorted(y # ys))

    by(rule sorted mid iff )

    lemmas sorted lems = sorted mid iff ′ sorted mid iff2 sorted cons ′ sorted snoc ′

    Splay trees need two additional sorted lemmas:

    lemma sorted snoc le:ASSUMPTION (sorted(xs @ [x ])) =⇒ x ≤ y =⇒ sorted (xs @ [y ])

    by (auto simp add : sorted wrt append ASSUMPTION def )

    lemma sorted Cons le:ASSUMPTION (sorted(x # xs)) =⇒ y ≤ x =⇒ sorted (y # xs)

    by (auto simp add : sorted wrt Cons ASSUMPTION def )

    end

    5 List Insertion and Deletion

    theory List Ins Delimports Sorted Lessbegin

    5.1 Elements in a list

    lemma sorted Cons iff :sorted(x # xs) = ((∀ y ∈ set xs. x < y) ∧ sorted xs)

    by(simp add : sorted wrt Cons)

    lemma sorted snoc iff :sorted(xs @ [x ]) = (sorted xs ∧ (∀ y ∈ set xs. y < x ))

    by(simp add : sorted wrt append)

    lemmas isin simps = sorted mid iff ′ sorted Cons iff sorted snoc iff

    5.2 Inserting into an ordered list without duplicates:

    fun ins list :: ′a::linorder ⇒ ′a list ⇒ ′a list whereins list x [] = [x ] |ins list x (a#xs) =(if x < a then x#a#xs else if x=a then a#xs else a # ins list x xs)

    21

  • lemma set ins list : set (ins list x xs) = set xs ∪ {x}by(induction xs) auto

    lemma sorted ins list : sorted xs =⇒ sorted(ins list x xs)by(induction xs rule: induct list012 ) auto

    lemma ins list sorted : sorted (xs @ [a]) =⇒ins list x (xs @ a # ys) =(if x < a then ins list x xs @ (a#ys) else xs @ ins list x (a#ys))

    by(induction xs) (auto simp: sorted lems)

    In principle, sorted (?xs @ [?a]) =⇒ ins list ?x (?xs @ ?a # ?ys) = (if?x < ?a then ins list ?x ?xs @ ?a # ?ys else ?xs @ ins list ?x (?a # ?ys))suffices, but the following two corollaries speed up proofs.

    corollary ins list sorted1 : sorted (xs @ [a]) =⇒ a ≤ x =⇒ins list x (xs @ a # ys) = xs @ ins list x (a#ys)

    by(auto simp add : ins list sorted)

    corollary ins list sorted2 : sorted (xs @ [a]) =⇒ x < a =⇒ins list x (xs @ a # ys) = ins list x xs @ (a#ys)

    by(auto simp: ins list sorted)

    lemmas ins list simps = sorted lems ins list sorted1 ins list sorted2

    Splay trees need two additional ins list lemmas:

    lemma ins list Cons: sorted (x # xs) =⇒ ins list x xs = x # xsby (induction xs) auto

    lemma ins list snoc: sorted (xs @ [x ]) =⇒ ins list x xs = xs @ [x ]by(induction xs) (auto simp add : sorted mid iff2 )

    5.3 Delete one occurrence of an element from a list:

    fun del list :: ′a ⇒ ′a list ⇒ ′a list wheredel list x [] = [] |del list x (a#xs) = (if x=a then xs else a # del list x xs)

    lemma del list idem: x /∈ set xs =⇒ del list x xs = xsby (induct xs) simp all

    lemma set del list :sorted xs =⇒ set (del list x xs) = set xs − {x}

    by(induct xs) (auto simp: sorted Cons iff )

    22

  • lemma sorted del list : sorted xs =⇒ sorted(del list x xs)apply(induction xs rule: induct list012 )apply autoby (meson order .strict trans sorted Cons iff )

    lemma del list sorted : sorted (xs @ a # ys) =⇒del list x (xs @ a # ys) = (if x < a then del list x xs @ a # ys else xs @

    del list x (a # ys))by(induction xs)(fastforce simp: sorted lems sorted Cons iff intro!: del list idem)+

    In principle, sorted (?xs @ ?a # ?ys) =⇒ del list ?x (?xs @ ?a # ?ys)= (if ?x < ?a then del list ?x ?xs @ ?a # ?ys else ?xs @ del list ?x (?a #?ys)) suffices, but the following corollaries speed up proofs.

    corollary del list sorted1 : sorted (xs @ a # ys) =⇒ a ≤ x =⇒del list x (xs @ a # ys) = xs @ del list x (a # ys)

    by (auto simp: del list sorted)

    corollary del list sorted2 : sorted (xs @ a # ys) =⇒ x < a =⇒del list x (xs @ a # ys) = del list x xs @ a # ys

    by (auto simp: del list sorted)

    corollary del list sorted3 :sorted (xs @ a # ys @ b # zs) =⇒ x < b =⇒del list x (xs @ a # ys @ b # zs) = del list x (xs @ a # ys) @ b # zs

    by (auto simp: del list sorted sorted lems)

    corollary del list sorted4 :sorted (xs @ a # ys @ b # zs @ c # us) =⇒ x < c =⇒del list x (xs @ a # ys @ b # zs @ c # us) = del list x (xs @ a # ys @

    b # zs) @ c # usby (auto simp: del list sorted sorted lems)

    corollary del list sorted5 :sorted (xs @ a # ys @ b # zs @ c # us @ d # vs) =⇒ x < d =⇒del list x (xs @ a # ys @ b # zs @ c # us @ d # vs) =del list x (xs @ a # ys @ b # zs @ c # us) @ d # vs

    by (auto simp: del list sorted sorted lems)

    lemmas del list simps = sorted lemsdel list sorted1del list sorted2del list sorted3del list sorted4

    23

  • del list sorted5

    Splay trees need two additional del list lemmas:

    lemma del list notin Cons: sorted (x # xs) =⇒ del list x xs = xsby(induction xs)(fastforce simp: sorted Cons iff )+

    lemma del list sorted app:sorted(xs @ [x ]) =⇒ del list x (xs @ ys) = xs @ del list x ys

    by (induction xs) (auto simp: sorted mid iff2 )

    end

    6 Specifications of Set ADT

    theory Set Specsimports List Ins Delbegin

    The basic set interface with traditional set-based specification:

    locale Set =fixes empty :: ′sfixes insert :: ′a ⇒ ′s ⇒ ′sfixes delete :: ′a ⇒ ′s ⇒ ′sfixes isin :: ′s ⇒ ′a ⇒ boolfixes set :: ′s ⇒ ′a setfixes invar :: ′s ⇒ boolassumes set empty : set empty = {}assumes set isin: invar s =⇒ isin s x = (x ∈ set s)assumes set insert : invar s =⇒ set(insert x s) = set s ∪ {x}assumes set delete: invar s =⇒ set(delete x s) = set s − {x}assumes invar empty : invar emptyassumes invar insert : invar s =⇒ invar(insert x s)assumes invar delete: invar s =⇒ invar(delete x s)

    lemmas (in Set) set specs =set empty set isin set insert set delete invar empty invar insert invar delete

    The basic set interface with inorder -based specification:

    locale Set by Ordered =fixes empty :: ′tfixes insert :: ′a::linorder ⇒ ′t ⇒ ′tfixes delete :: ′a ⇒ ′t ⇒ ′tfixes isin :: ′t ⇒ ′a ⇒ boolfixes inorder :: ′t ⇒ ′a list

    24

  • fixes inv :: ′t ⇒ boolassumes inorder empty : inorder empty = []assumes isin: inv t ∧ sorted(inorder t) =⇒isin t x = (x ∈ set (inorder t))

    assumes inorder insert : inv t ∧ sorted(inorder t) =⇒inorder(insert x t) = ins list x (inorder t)

    assumes inorder delete: inv t ∧ sorted(inorder t) =⇒inorder(delete x t) = del list x (inorder t)

    assumes inorder inv empty : inv emptyassumes inorder inv insert : inv t ∧ sorted(inorder t) =⇒ inv(insert x t)assumes inorder inv delete: inv t ∧ sorted(inorder t) =⇒ inv(delete x t)

    begin

    It implements the traditional specification:

    definition set :: ′t ⇒ ′a set whereset = List .set o inorder

    definition invar :: ′t ⇒ bool whereinvar t = (inv t ∧ sorted (inorder t))

    sublocale Setempty insert delete isin set invar

    proof(standard , goal cases)case 1 show ?case by (auto simp: inorder empty set def )

    nextcase 2 thus ?case by(simp add : isin invar def set def )

    nextcase 3 thus ?case by(simp add : inorder insert set ins list set def in-

    var def )nextcase (4 s x ) thus ?caseby (auto simp: inorder delete set del list invar def set def )

    nextcase 5 thus ?case by(simp add : inorder empty inorder inv empty in-

    var def )nextcase 6 thus ?case by(simp add : inorder insert inorder inv insert sorted ins list

    invar def )nextcase 7 thus ?case by (auto simp: inorder delete inorder inv delete sorted del list

    invar def )qed

    25

  • end

    Set2 = Set with binary operations:

    locale Set2 = Setwhere insert = insert for insert :: ′a ⇒ ′s ⇒ ′s +

    fixes union :: ′s ⇒ ′s ⇒ ′sfixes inter :: ′s ⇒ ′s ⇒ ′sfixes diff :: ′s ⇒ ′s ⇒ ′sassumes set union: [[ invar s1 ; invar s2 ]] =⇒ set(union s1 s2 ) = set s1∪ set s2assumes set inter : [[ invar s1 ; invar s2 ]] =⇒ set(inter s1 s2 ) = set s1 ∩set s2assumes set diff : [[ invar s1 ; invar s2 ]] =⇒ set(diff s1 s2 ) = set s1 −set s2assumes invar union: [[ invar s1 ; invar s2 ]] =⇒ invar(union s1 s2 )assumes invar inter : [[ invar s1 ; invar s2 ]] =⇒ invar(inter s1 s2 )assumes invar diff : [[ invar s1 ; invar s2 ]] =⇒ invar(diff s1 s2 )

    end

    7 Unbalanced Tree Implementation of Set

    theory Tree SetimportsHOL−Library .TreeCmpSet Specs

    begin

    definition empty :: ′a tree whereempty = Leaf

    fun isin :: ′a::linorder tree ⇒ ′a ⇒ bool whereisin Leaf x = False |isin (Node l a r) x =(case cmp x a of

    LT ⇒ isin l x |EQ ⇒ True |GT ⇒ isin r x )

    hide const (open) insert

    fun insert :: ′a::linorder ⇒ ′a tree ⇒ ′a tree whereinsert x Leaf = Node Leaf x Leaf |

    26

  • insert x (Node l a r) =(case cmp x a of

    LT ⇒ Node (insert x l) a r |EQ ⇒ Node l a r |GT ⇒ Node l a (insert x r))

    Deletion by replacing:

    fun split min :: ′a tree ⇒ ′a ∗ ′a tree wheresplit min (Node l a r) =(if l = Leaf then (a,r) else let (x ,l ′) = split min l in (x , Node l ′ a r))

    fun delete :: ′a::linorder ⇒ ′a tree ⇒ ′a tree wheredelete x Leaf = Leaf |delete x (Node l a r) =(case cmp x a of

    LT ⇒ Node (delete x l) a r |GT ⇒ Node l a (delete x r) |EQ ⇒ if r = Leaf then l else let (a ′,r ′) = split min r in Node l a ′ r ′)

    Deletion by joining:

    fun join :: ( ′a::linorder)tree ⇒ ′a tree ⇒ ′a tree wherejoin t Leaf = t |join Leaf t = t |join (Node t1 a t2 ) (Node t3 b t4 ) =(case join t2 t3 of

    Leaf ⇒ Node t1 a (Node Leaf b t4 ) |Node u2 x u3 ⇒ Node (Node t1 a u2 ) x (Node u3 b t4 ))

    fun delete2 :: ′a::linorder ⇒ ′a tree ⇒ ′a tree wheredelete2 x Leaf = Leaf |delete2 x (Node l a r) =(case cmp x a of

    LT ⇒ Node (delete2 x l) a r |GT ⇒ Node l a (delete2 x r) |EQ ⇒ join l r)

    7.1 Functional Correctness Proofs

    lemma isin set : sorted(inorder t) =⇒ isin t x = (x ∈ set (inorder t))by (induction t) (auto simp: isin simps)

    lemma inorder insert :sorted(inorder t) =⇒ inorder(insert x t) = ins list x (inorder t)

    by(induction t) (auto simp: ins list simps)

    27

  • lemma split minD :split min t = (x ,t ′) =⇒ t 6= Leaf =⇒ x # inorder t ′ = inorder t

    by(induction t arbitrary : t ′ rule: split min.induct)(auto simp: sorted lems split : prod .splits if splits)

    lemma inorder delete:sorted(inorder t) =⇒ inorder(delete x t) = del list x (inorder t)

    by(induction t) (auto simp: del list simps split minD split : prod .splits)

    interpretation S : Set by Orderedwhere empty = empty and isin = isin and insert = insert and delete =deleteand inorder = inorder and inv = λ . Trueproof (standard , goal cases)case 1 show ?case by (simp add : empty def )

    nextcase 2 thus ?case by(simp add : isin set)

    nextcase 3 thus ?case by(simp add : inorder insert)

    nextcase 4 thus ?case by(simp add : inorder delete)

    qed (rule TrueI )+

    lemma inorder join:inorder(join l r) = inorder l @ inorder r

    by(induction l r rule: join.induct) (auto split : tree.split)

    lemma inorder delete2 :sorted(inorder t) =⇒ inorder(delete2 x t) = del list x (inorder t)

    by(induction t) (auto simp: inorder join del list simps)

    interpretation S2 : Set by Orderedwhere empty = empty and isin = isin and insert = insert and delete =delete2and inorder = inorder and inv = λ . Trueproof (standard , goal cases)case 1 show ?case by (simp add : empty def )

    nextcase 2 thus ?case by(simp add : isin set)

    nextcase 3 thus ?case by(simp add : inorder insert)

    next

    28

  • case 4 thus ?case by(simp add : inorder delete2 )qed (rule TrueI )+

    end

    8 Association List Update and Deletion

    theory AList Upd Delimports Sorted Lessbegin

    abbreviation sorted1 ps ≡ sorted(map fst ps)

    Define own map of function to avoid pulling in an unknown amount oflemmas implicitly (via the simpset).

    hide const (open) map of

    fun map of :: ( ′a∗ ′b)list ⇒ ′a ⇒ ′b option wheremap of [] = (λx . None) |map of ((a,b)#ps) = (λx . if x=a then Some b else map of ps x )

    Updating an association list:

    fun upd list :: ′a::linorder ⇒ ′b ⇒ ( ′a∗ ′b) list ⇒ ( ′a∗ ′b) list whereupd list x y [] = [(x ,y)] |upd list x y ((a,b)#ps) =(if x < a then (x ,y)#(a,b)#ps elseif x = a then (x ,y)#ps else (a,b) # upd list x y ps)

    fun del list :: ′a::linorder ⇒ ( ′a∗ ′b)list ⇒ ( ′a∗ ′b)list wheredel list x [] = [] |del list x ((a,b)#ps) = (if x = a then ps else (a,b) # del list x ps)

    8.1 Lemmas for map of

    lemma map of ins list : map of (upd list x y ps) = (map of ps)(x := Somey)by(induction ps) auto

    lemma map of append : map of (ps @ qs) x =(case map of ps x of None ⇒ map of qs x | Some y ⇒ Some y)

    by(induction ps)(auto)

    lemma map of None: sorted (x # map fst ps) =⇒ map of ps x = Noneby (induction ps) (fastforce simp: sorted lems sorted wrt Cons)+

    29

  • lemma map of None2 : sorted (map fst ps @ [x ]) =⇒ map of ps x = Noneby (induction ps) (auto simp: sorted lems)

    lemma map of del list : sorted1 ps =⇒map of (del list x ps) = (map of ps)(x := None)

    by(induction ps) (auto simp: map of None sorted lems fun eq iff )

    lemma map of sorted Cons: sorted (a # map fst ps) =⇒ x < a =⇒map of ps x = None

    by (simp add : map of None sorted Cons le)

    lemma map of sorted snoc: sorted (map fst ps @ [a]) =⇒ a ≤ x =⇒map of ps x = None

    by (simp add : map of None2 sorted snoc le)

    lemmas map of sorteds = map of sorted Cons map of sorted snoclemmas map of simps = sorted lems map of append map of sorteds

    8.2 Lemmas for upd list

    lemma sorted upd list : sorted1 ps =⇒ sorted1 (upd list x y ps)apply(induction ps)apply simpapply(case tac ps)apply autodone

    lemma upd list sorted : sorted1 (ps @ [(a,b)]) =⇒upd list x y (ps @ (a,b) # qs) =(if x < a then upd list x y ps @ (a,b) # qselse ps @ upd list x y ((a,b) # qs))

    by(induction ps) (auto simp: sorted lems)

    In principle, sorted1 (?ps @ [(?a, ?b)]) =⇒ upd list ?x ?y (?ps @ (?a,?b) # ?qs) = (if ?x < ?a then upd list ?x ?y ?ps @ (?a, ?b) # ?qs else ?ps@ upd list ?x ?y ((?a, ?b) # ?qs)) suffices, but the following two corollariesspeed up proofs.

    corollary upd list sorted1 : [[ sorted (map fst ps @ [a]); x < a ]] =⇒upd list x y (ps @ (a,b) # qs) = upd list x y ps @ (a,b) # qs

    by (auto simp: upd list sorted)

    corollary upd list sorted2 : [[ sorted (map fst ps @ [a]); a ≤ x ]] =⇒upd list x y (ps @ (a,b) # qs) = ps @ upd list x y ((a,b) # qs)

    30

  • by (auto simp: upd list sorted)

    lemmas upd list simps = sorted lems upd list sorted1 upd list sorted2

    Splay trees need two additional upd list lemmas:

    lemma upd list Cons:sorted1 ((x ,y) # xs) =⇒ upd list x y xs = (x ,y) # xs

    by (induction xs) auto

    lemma upd list snoc:sorted1 (xs @ [(x ,y)]) =⇒ upd list x y xs = xs @ [(x ,y)]

    by(induction xs) (auto simp add : sorted mid iff2 )

    8.3 Lemmas for del list

    lemma sorted del list : sorted1 ps =⇒ sorted1 (del list x ps)apply(induction ps)apply simpapply(case tac ps)apply (auto simp: sorted Cons le)done

    lemma del list idem: x /∈ set(map fst xs) =⇒ del list x xs = xsby (induct xs) auto

    lemma del list sorted : sorted1 (ps @ (a,b) # qs) =⇒del list x (ps @ (a,b) # qs) =(if x < a then del list x ps @ (a,b) # qselse ps @ del list x ((a,b) # qs))

    by(induction ps)(fastforce simp: sorted lems sorted wrt Cons intro!: del list idem)+

    In principle, sorted1 (?ps @ (?a, ?b) # ?qs) =⇒ del list ?x (?ps @ (?a,?b) # ?qs) = (if ?x < ?a then del list ?x ?ps @ (?a, ?b) # ?qs else ?ps @del list ?x ((?a, ?b) # ?qs)) suffices, but the following corollaries speed upproofs.

    corollary del list sorted1 : sorted1 (xs @ (a,b) # ys) =⇒ a ≤ x =⇒del list x (xs @ (a,b) # ys) = xs @ del list x ((a,b) # ys)

    by (auto simp: del list sorted)

    lemma del list sorted2 : sorted1 (xs @ (a,b) # ys) =⇒ x < a =⇒del list x (xs @ (a,b) # ys) = del list x xs @ (a,b) # ys

    by (auto simp: del list sorted)

    31

  • lemma del list sorted3 :sorted1 (xs @ (a,a ′) # ys @ (b,b ′) # zs) =⇒ x < b =⇒del list x (xs @ (a,a ′) # ys @ (b,b ′) # zs) = del list x (xs @ (a,a ′) # ys)

    @ (b,b ′) # zsby (auto simp: del list sorted sorted lems)

    lemma del list sorted4 :sorted1 (xs @ (a,a ′) # ys @ (b,b ′) # zs @ (c,c ′) # us) =⇒ x < c =⇒del list x (xs @ (a,a ′) # ys @ (b,b ′) # zs @ (c,c ′) # us) = del list x (xs

    @ (a,a ′) # ys @ (b,b ′) # zs) @ (c,c ′) # usby (auto simp: del list sorted sorted lems)

    lemma del list sorted5 :sorted1 (xs @ (a,a ′) # ys @ (b,b ′) # zs @ (c,c ′) # us @ (d ,d ′) # vs)

    =⇒ x < d =⇒del list x (xs @ (a,a ′) # ys @ (b,b ′) # zs @ (c,c ′) # us @ (d ,d ′) # vs)

    =del list x (xs @ (a,a ′) # ys @ (b,b ′) # zs @ (c,c ′) # us) @ (d ,d ′) # vs

    by (auto simp: del list sorted sorted lems)

    lemmas del list simps = sorted lemsdel list sorted1del list sorted2del list sorted3del list sorted4del list sorted5

    Splay trees need two additional del list lemmas:

    lemma del list notin Cons: sorted (x # map fst xs) =⇒ del list x xs = xsby(induction xs)(fastforce simp: sorted wrt Cons)+

    lemma del list sorted app:sorted(map fst xs @ [x ]) =⇒ del list x (xs @ ys) = xs @ del list x ys

    by (induction xs) (auto simp: sorted mid iff2 )

    end

    9 Specifications of Map ADT

    theory Map Specsimports AList Upd Delbegin

    The basic map interface with traditional set-based specification:

    32

  • locale Map =fixes empty :: ′mfixes update :: ′a ⇒ ′b ⇒ ′m ⇒ ′mfixes delete :: ′a ⇒ ′m ⇒ ′mfixes lookup :: ′m ⇒ ′a ⇒ ′b optionfixes invar :: ′m ⇒ boolassumes map empty : lookup empty = (λ . None)and map update: invar m =⇒ lookup(update a b m) = (lookup m)(a :=Some b)and map delete: invar m =⇒ lookup(delete a m) = (lookup m)(a := None)and invar empty : invar emptyand invar update: invar m =⇒ invar(update a b m)and invar delete: invar m =⇒ invar(delete a m)

    lemmas (in Map) map specs =map empty map update map delete invar empty invar update invar delete

    The basic map interface with inorder -based specification:

    locale Map by Ordered =fixes empty :: ′tfixes update :: ′a::linorder ⇒ ′b ⇒ ′t ⇒ ′tfixes delete :: ′a ⇒ ′t ⇒ ′tfixes lookup :: ′t ⇒ ′a ⇒ ′b optionfixes inorder :: ′t ⇒ ( ′a ∗ ′b) listfixes inv :: ′t ⇒ boolassumes inorder empty : inorder empty = []and inorder lookup: inv t ∧ sorted1 (inorder t) =⇒lookup t a = map of (inorder t) a

    and inorder update: inv t ∧ sorted1 (inorder t) =⇒inorder(update a b t) = upd list a b (inorder t)

    and inorder delete: inv t ∧ sorted1 (inorder t) =⇒inorder(delete a t) = del list a (inorder t)

    and inorder inv empty : inv emptyand inorder inv update: inv t ∧ sorted1 (inorder t) =⇒ inv(update a b t)and inorder inv delete: inv t ∧ sorted1 (inorder t) =⇒ inv(delete a t)

    begin

    It implements the traditional specification:

    definition invar :: ′t ⇒ bool whereinvar t == inv t ∧ sorted1 (inorder t)

    sublocale Mapempty update delete lookup invar

    33

  • proof(standard , goal cases)case 1 show ?case by (auto simp: inorder lookup inorder empty in-

    order inv empty)nextcase 2 thus ?caseby(simp add : fun eq iff inorder update inorder inv update map of ins list

    inorder lookupsorted upd list invar def )

    nextcase 3 thus ?caseby(simp add : fun eq iff inorder delete inorder inv delete map of del list

    inorder lookupsorted del list invar def )

    nextcase 4 thus ?case by(simp add : inorder empty inorder inv empty in-

    var def )nextcase 5 thus ?case by(simp add : inorder update inorder inv update sorted upd list

    invar def )nextcase 6 thus ?case by (auto simp: inorder delete inorder inv delete sorted del list

    invar def )qed

    end

    end

    10 Unbalanced Tree Implementation of Map

    theory Tree MapimportsTree SetMap Specs

    begin

    fun lookup :: ( ′a::linorder∗ ′b) tree ⇒ ′a ⇒ ′b option wherelookup Leaf x = None |lookup (Node l (a,b) r) x =(case cmp x a of LT ⇒ lookup l x | GT ⇒ lookup r x | EQ ⇒ Some b)

    fun update :: ′a::linorder ⇒ ′b ⇒ ( ′a∗ ′b) tree ⇒ ( ′a∗ ′b) tree whereupdate x y Leaf = Node Leaf (x ,y) Leaf |

    34

  • update x y (Node l (a,b) r) = (case cmp x a ofLT ⇒ Node (update x y l) (a,b) r |EQ ⇒ Node l (x ,y) r |GT ⇒ Node l (a,b) (update x y r))

    fun delete :: ′a::linorder ⇒ ( ′a∗ ′b) tree ⇒ ( ′a∗ ′b) tree wheredelete x Leaf = Leaf |delete x (Node l (a,b) r) = (case cmp x a ofLT ⇒ Node (delete x l) (a,b) r |GT ⇒ Node l (a,b) (delete x r) |EQ ⇒ if r = Leaf then l else let (ab ′,r ′) = split min r in Node l ab ′ r ′)

    10.1 Functional Correctness Proofs

    lemma lookup map of :sorted1 (inorder t) =⇒ lookup t x = map of (inorder t) x

    by (induction t) (auto simp: map of simps split : option.split)

    lemma inorder update:sorted1 (inorder t) =⇒ inorder(update a b t) = upd list a b (inorder t)

    by(induction t) (auto simp: upd list simps)

    lemma inorder delete:sorted1 (inorder t) =⇒ inorder(delete x t) = del list x (inorder t)

    by(induction t) (auto simp: del list simps split minD split : prod .splits)

    interpretation M : Map by Orderedwhere empty = empty and lookup = lookup and update = update anddelete = deleteand inorder = inorder and inv = λ . Trueproof (standard , goal cases)case 1 show ?case by (simp add : empty def )

    nextcase 2 thus ?case by(simp add : lookup map of )

    nextcase 3 thus ?case by(simp add : inorder update)

    nextcase 4 thus ?case by(simp add : inorder delete)

    qed auto

    end

    35

  • 11 Augmented Tree (Tree2)

    theory Tree2imports HOL−Library .Treebegin

    This theory provides the basic infrastructure for the type ( ′a × ′b) treeof augmented trees where ′a is the key and ′b some additional information.

    IMPORTANT: Inductions and cases analyses on augmented trees needto use the following two rules explicitly. They generate nodes of the form〈l , (a, b), r〉 rather than 〈l , a, r〉 for trees of type ′a tree.

    lemmas tree2 induct = tree.induct [where ′a = ′a ∗ ′b, split format(complete)]

    lemmas tree2 cases = tree.exhaust [where ′a = ′a ∗ ′b, split format(complete)]

    fun inorder :: ( ′a∗ ′b)tree ⇒ ′a list whereinorder Leaf = [] |inorder (Node l (a, ) r) = inorder l @ a # inorder r

    fun set tree :: ( ′a∗ ′b) tree ⇒ ′a set whereset tree Leaf = {} |set tree (Node l (a, ) r) = {a} ∪ set tree l ∪ set tree r

    fun bst :: ( ′a::linorder∗ ′b) tree ⇒ bool wherebst Leaf = True |bst (Node l (a, ) r) = ((∀ x ∈ set tree l . x < a) ∧ (∀ x ∈ set tree r . a <x ) ∧ bst l ∧ bst r)

    lemma finite set tree[simp]: finite(set tree t)by(induction t) auto

    lemma eq set tree empty [simp]: set tree t = {} ←→ t = Leafby (cases t) auto

    lemma set inorder [simp]: set (inorder t) = set tree tby (induction t) auto

    lemma length inorder [simp]: length (inorder t) = size tby (induction t) auto

    end

    36

  • 12 Function isin for Tree2

    theory Isin2importsTree2CmpSet Specs

    begin

    fun isin :: ( ′a::linorder∗ ′b) tree ⇒ ′a ⇒ bool whereisin Leaf x = False |isin (Node l (a, ) r) x =(case cmp x a of

    LT ⇒ isin l x |EQ ⇒ True |GT ⇒ isin r x )

    lemma isin set inorder : sorted(inorder t) =⇒ isin t x = (x ∈ set(inordert))by (induction t rule: tree2 induct) (auto simp: isin simps)

    lemma isin set tree: bst t =⇒ isin t x ←→ x ∈ set tree tby(induction t rule: tree2 induct) auto

    end

    13 Interval Trees

    theory Interval TreeimportsHOL−Data Structures.CmpHOL−Data Structures.List Ins DelHOL−Data Structures.Isin2HOL−Data Structures.Set Specs

    begin

    13.1 Intervals

    The following definition of intervals uses the typedef command to definethe type of non-empty intervals as a subset of the type of pairs p where fstp ≤ snd p:

    typedef (overloaded) ′a::linorder ivl ={p :: ′a × ′a. fst p ≤ snd p} by auto

    37

  • More precisely, ′a ivl is isomorphic with that subset via the functionRep ivl. Hence the basic interval properties are not immediate but needsimple proofs:

    definition low :: ′a::linorder ivl ⇒ ′a wherelow p = fst (Rep ivl p)

    definition high :: ′a::linorder ivl ⇒ ′a wherehigh p = snd (Rep ivl p)

    lemma ivl is interval : low p ≤ high pby (metis Rep ivl high def low def mem Collect eq)

    lemma ivl inj : low p = low q =⇒ high p = high q =⇒ p = qby (metis Rep ivl inverse high def low def prod eqI )

    Now we can forget how exactly intervals were defined.

    instantiation ivl :: (linorder) linorder begin

    definition ivl less: (x < y) = (low x < low y | (low x = low y ∧ high x <high y))definition ivl less eq : (x ≤ y) = (low x < low y | (low x = low y ∧ high x≤ high y))

    instance prooffix x y z :: ′a ivlshow a: (x < y) = (x ≤ y ∧ ¬ y ≤ x )using ivl less ivl less eq by force

    show b: x ≤ xby (simp add : ivl less eq)

    show c: x ≤ y =⇒ y ≤ z =⇒ x ≤ zby (smt ivl less eq dual order .trans less trans)

    show d : x ≤ y =⇒ y ≤ x =⇒ x = yusing ivl less eq a ivl inj ivl less by fastforce

    show e: x ≤ y ∨ y ≤ xby (meson ivl less eq leI not less iff gr or eq)

    qed end

    definition overlap :: ( ′a::linorder) ivl ⇒ ′a ivl ⇒ bool whereoverlap x y ←→ (high x ≥ low y ∧ high y ≥ low x )

    definition has overlap :: ( ′a::linorder) ivl set ⇒ ′a ivl ⇒ bool wherehas overlap S y ←→ (∃ x∈S . overlap x y)

    38

  • 13.2 Interval Trees

    type synonym ′a ivl tree = ( ′a ivl ∗ ′a) tree

    fun max hi :: ( ′a::order bot) ivl tree ⇒ ′a wheremax hi Leaf = bot |max hi (Node ( ,m) ) = m

    definition max3 :: ( ′a::linorder) ivl ⇒ ′a ⇒ ′a ⇒ ′a wheremax3 a m n = max (high a) (max m n)

    fun inv max hi :: ( ′a::{linorder ,order bot}) ivl tree ⇒ bool whereinv max hi Leaf ←→ True |inv max hi (Node l (a, m) r) ←→ (m = max3 a (max hi l) (max hi r) ∧inv max hi l ∧ inv max hi r)

    lemma max hi is max :inv max hi t =⇒ a ∈ set tree t =⇒ high a ≤ max hi t

    by (induct t , auto simp add : max3 def max def )

    lemma max hi exists:inv max hi t =⇒ t 6= Leaf =⇒ ∃ a∈set tree t . high a = max hi t

    proof (induction t rule: tree2 induct)case Leafthen show ?case by auto

    nextcase N : (Node l v m r)then show ?caseproof (cases l rule: tree2 cases)case Leafthen show ?thesis

    using N .prems(1 ) N .IH (2 ) by (cases r , auto simp add : max3 defmax def le bot)nextcase Nl : Nodethen show ?thesisproof (cases r rule: tree2 cases)case Leafthen show ?thesisusing N .prems(1 ) N .IH (1 ) Nl by (auto simp add : max3 def max def

    le bot)nextcase Nr : Nodeobtain p1 where p1 : p1 ∈ set tree l high p1 = max hi l

    39

  • using N .IH (1 ) N .prems(1 ) Nl by autoobtain p2 where p2 : p2 ∈ set tree r high p2 = max hi rusing N .IH (2 ) N .prems(1 ) Nr by auto

    then show ?thesisusing p1 p2 N .prems(1 ) by (auto simp add : max3 def max def )

    qedqed

    qed

    13.3 Insertion and Deletion

    definition node where[simp]: node l a r = Node l (a, max3 a (max hi l) (max hi r)) r

    fun insert :: ′a::{linorder ,order bot} ivl ⇒ ′a ivl tree ⇒ ′a ivl tree whereinsert x Leaf = Node Leaf (x , high x ) Leaf |insert x (Node l (a, m) r) =(case cmp x a of

    EQ ⇒ Node l (a, m) r |LT ⇒ node (insert x l) a r |GT ⇒ node l a (insert x r))

    lemma inorder insert :sorted (inorder t) =⇒ inorder (insert x t) = ins list x (inorder t)

    by (induct t rule: tree2 induct) (auto simp: ins list simps)

    lemma inv max hi insert :inv max hi t =⇒ inv max hi (insert x t)

    by (induct t rule: tree2 induct) (auto simp add : max3 def )

    fun split min :: ′a::{linorder ,order bot} ivl tree ⇒ ′a ivl × ′a ivl tree wheresplit min (Node l (a, m) r) =(if l = Leaf then (a, r)else let (x ,l ′) = split min l in (x , node l ′ a r))

    fun delete :: ′a::{linorder ,order bot} ivl ⇒ ′a ivl tree ⇒ ′a ivl tree wheredelete x Leaf = Leaf |delete x (Node l (a, m) r) =(case cmp x a of

    LT ⇒ node (delete x l) a r |GT ⇒ node l a (delete x r) |EQ ⇒ if r = Leaf then l else

    let (a ′, r ′) = split min r in node l a ′ r ′)

    40

  • lemma split minD :split min t = (x ,t ′) =⇒ t 6= Leaf =⇒ x # inorder t ′ = inorder t

    by (induct t arbitrary : t ′ rule: split min.induct)(auto simp: sorted lems split : prod .splits if splits)

    lemma inorder delete:sorted (inorder t) =⇒ inorder (delete x t) = del list x (inorder t)

    by (induct t)(auto simp: del list simps split minD Let def split : prod .splits)

    lemma inv max hi split min:[[ t 6= Leaf ; inv max hi t ]] =⇒ inv max hi (snd (split min t))

    by (induct t) (auto split : prod .splits)

    lemma inv max hi delete:inv max hi t =⇒ inv max hi (delete x t)

    apply (induct t)apply simpusing inv max hi split min by (fastforce simp add : Let def split : prod .splits)

    13.4 Search

    Does interval x overlap with any interval in the tree?

    fun search :: ′a::{linorder ,order bot} ivl tree ⇒ ′a ivl ⇒ bool wheresearch Leaf x = False |search (Node l (a, m) r) x =(if overlap x a then Trueelse if l 6= Leaf ∧ max hi l ≥ low x then search l xelse search r x )

    lemma search correct :inv max hi t =⇒ sorted (inorder t) =⇒ search t x = has overlap (set tree

    t) xproof (induction t rule: tree2 induct)case Leafthen show ?case by (auto simp add : has overlap def )

    nextcase (Node l a m r)have search l : search l x = has overlap (set tree l) xusing Node.IH (1 ) Node.prems by (auto simp: sorted wrt append)

    have search r : search r x = has overlap (set tree r) xusing Node.IH (2 ) Node.prems by (auto simp: sorted wrt append)

    show ?caseproof (cases overlap a x )

    41

  • case Truethus ?thesis by (auto simp: overlap def has overlap def )

    nextcase a disjoint : Falsethen show ?thesisproof casesassume [simp]: l = Leafhave search eval : search (Node l (a, m) r) x = search r xusing a disjoint overlap def by auto

    show ?thesisunfolding search eval search rby (auto simp add : has overlap def a disjoint)

    nextassume l 6= Leafthen show ?thesisproof (cases max hi l ≥ low x )case max hi l ge: Truehave inv max hi lusing Node.prems(1 ) by auto

    then obtain p where p: p ∈ set tree l high p = max hi lusing 〈l 6= Leaf 〉 max hi exists by auto

    have search eval : search (Node l (a, m) r) x = search l xusing a disjoint 〈l 6= Leaf 〉 max hi l ge by (auto simp: overlap def )show ?thesisproof (cases low p ≤ high x )case Truehave overlap p xunfolding overlap def using True p(2 ) max hi l ge by auto

    then show ?thesisunfolding search eval search lusing p(1 ) by(auto simp: has overlap def overlap def )

    nextcase Falsehave ¬overlap x rp if asm: rp ∈ set tree r for rpproof −have low p ≤ low rpusing asm p(1 ) Node(4 ) by(fastforce simp: sorted wrt append

    ivl less)then show ?thesisusing False by (auto simp: overlap def )

    qedthen show ?thesisunfolding search eval search lusing a disjoint by (auto simp: has overlap def overlap def )

    42

  • qednextcase Falsehave search eval : search (Node l (a, m) r) x = search r xusing a disjoint False by (auto simp: overlap def )

    have ¬overlap x lp if asm: lp ∈ set tree l for lpusing asm False Node.prems(1 ) max hi is maxby (fastforce simp: overlap def )

    then show ?thesisunfolding search eval search rusing a disjoint by (auto simp: has overlap def overlap def )

    qedqed

    qedqed

    definition empty :: ′a ivl tree whereempty = Leaf

    13.5 Specification

    locale Interval Set = Set +fixes has overlap :: ′t ⇒ ′a::linorder ivl ⇒ boolassumes set overlap: invar s =⇒ has overlap s x = Interval Tree.has overlap

    (set s) x

    fun invar :: ( ′a::{linorder ,order bot}) ivl tree ⇒ bool whereinvar t = (inv max hi t ∧ sorted(inorder t))

    interpretation S : Interval Setwhere empty = Leaf and insert = insert and delete = deleteand has overlap = search and isin = isin and set = set treeand invar = invar

    proof (standard , goal cases)case 1then show ?case by auto

    nextcase 2then show ?case by (simp add : isin set inorder)

    nextcase 3then show ?case by(simp add : inorder insert set ins list flip: set inorder)

    nextcase 4

    43

  • then show ?case by(simp add : inorder delete set del list flip: set inorder)nextcase 5then show ?case by auto

    nextcase 6then show ?case by (simp add : inorder insert inv max hi insert sorted ins list)

    nextcase 7then show ?case by (simp add : inorder delete inv max hi delete sorted del list)

    nextcase 8then show ?case by (simp add : search correct)

    qed

    end

    14 AVL Tree Implementation of Sets

    theory AVL Set CodeimportsCmpIsin2

    begin

    14.1 Code

    type synonym ′a tree ht = ( ′a∗nat) tree

    definition empty :: ′a tree ht whereempty = Leaf

    fun ht :: ′a tree ht ⇒ nat whereht Leaf = 0 |ht (Node l (a,n) r) = n

    definition node :: ′a tree ht ⇒ ′a ⇒ ′a tree ht ⇒ ′a tree ht wherenode l a r = Node l (a, max (ht l) (ht r) + 1 ) r

    definition balL :: ′a tree ht ⇒ ′a ⇒ ′a tree ht ⇒ ′a tree ht wherebalL AB c C =(if ht AB = ht C + 2 then

    case AB ofNode A (a, ) B ⇒

    44

  • if ht A ≥ ht B then node A a (node B c C )elsecase B ofNode B1 (b, ) B2 ⇒ node (node A a B1) b (node B2 c C )

    else node AB c C )

    definition balR :: ′a tree ht ⇒ ′a ⇒ ′a tree ht ⇒ ′a tree ht wherebalR A a BC =

    (if ht BC = ht A + 2 thencase BC ofNode B (c, ) C ⇒if ht B ≤ ht C then node (node A a B) c Celsecase B ofNode B1 (b, ) B2 ⇒ node (node A a B1) b (node B2 c C )

    else node A a BC )

    fun insert :: ′a::linorder ⇒ ′a tree ht ⇒ ′a tree ht whereinsert x Leaf = Node Leaf (x , 1 ) Leaf |insert x (Node l (a, n) r) = (case cmp x a of

    EQ ⇒ Node l (a, n) r |LT ⇒ balL (insert x l) a r |GT ⇒ balR l a (insert x r))

    fun split max :: ′a tree ht ⇒ ′a tree ht ∗ ′a wheresplit max (Node l (a, ) r) =(if r = Leaf then (l ,a) else let (r ′,a ′) = split max r in (balL l a r ′, a ′))

    lemmas split max induct = split max .induct [case names Node Leaf ]

    fun delete :: ′a::linorder ⇒ ′a tree ht ⇒ ′a tree ht wheredelete Leaf = Leaf |delete x (Node l (a, n) r) =(case cmp x a of

    EQ ⇒ if l = Leaf then relse let (l ′, a ′) = split max l in balR l ′ a ′ r |

    LT ⇒ balR (delete x l) a r |GT ⇒ balL l a (delete x r))

    14.2 Functional Correctness Proofs

    Very different from the AFP/AVL proofs

    45

  • 14.2.1 Proofs for insert

    lemma inorder balL:inorder (balL l a r) = inorder l @ a # inorder r

    by (auto simp: node def balL def split :tree.splits)

    lemma inorder balR:inorder (balR l a r) = inorder l @ a # inorder r

    by (auto simp: node def balR def split :tree.splits)

    theorem inorder insert :sorted(inorder t) =⇒ inorder(insert x t) = ins list x (inorder t)

    by (induct t)(auto simp: ins list simps inorder balL inorder balR)

    14.2.2 Proofs for delete

    lemma inorder split maxD :[[ split max t = (t ′,a); t 6= Leaf ]] =⇒inorder t ′ @ [a] = inorder t

    by(induction t arbitrary : t ′ rule: split max .induct)(auto simp: inorder balL split : if splits prod .splits tree.split)

    theorem inorder delete:sorted(inorder t) =⇒ inorder (delete x t) = del list x (inorder t)

    by(induction t)(auto simp: del list simps inorder balL inorder balR inorder split maxD

    split : prod .splits)

    end

    14.3 Invariant

    theory AVL SetimportsAVL Set CodeHOL−Number Theory .Fib

    begin

    fun avl :: ′a tree ht ⇒ bool whereavl Leaf = True |avl (Node l (a,n) r) =(abs(int(height l) − int(height r)) ≤ 1 ∧n = max (height l) (height r) + 1 ∧ avl l ∧ avl r)

    46

  • 14.3.1 Insertion maintains AVL balance

    declare Let def [simp]

    lemma ht height [simp]: avl t =⇒ ht t = height tby (cases t rule: tree2 cases) simp all

    First, a fast but relatively manual proof with many lemmas:

    lemma height balL:[[ avl l ; avl r ; height l = height r + 2 ]] =⇒height (balL l a r) ∈ {height r + 2 , height r + 3}

    by (auto simp:node def balL def split :tree.split)

    lemma height balR:[[ avl l ; avl r ; height r = height l + 2 ]] =⇒height (balR l a r) : {height l + 2 , height l + 3}

    by(auto simp add :node def balR def split :tree.split)

    lemma height node[simp]: height(node l a r) = max (height l) (height r)+ 1by (simp add : node def )

    lemma height balL2 :[[ avl l ; avl r ; height l 6= height r + 2 ]] =⇒height (balL l a r) = 1 + max (height l) (height r)

    by (simp all add : balL def )

    lemma height balR2 :[[ avl l ; avl r ; height r 6= height l + 2 ]] =⇒height (balR l a r) = 1 + max (height l) (height r)

    by (simp all add : balR def )

    lemma avl balL:[[ avl l ; avl r ; height r − 1 ≤ height l ∧ height l ≤ height r + 2 ]] =⇒

    avl(balL l a r)by(auto simp: balL def node def split !: if split tree.split)

    lemma avl balR:[[ avl l ; avl r ; height l − 1 ≤ height r ∧ height r ≤ height l + 2 ]] =⇒

    avl(balR l a r)by(auto simp: balR def node def split !: if split tree.split)

    Insertion maintains the AVL property. Requires simultaneous proof.

    theorem avl insert :avl t =⇒ avl(insert x t)

    47

  • avl t =⇒ height (insert x t) ∈ {height t , height t + 1}proof (induction t rule: tree2 induct)case (Node l a r)case 1show ?caseproof(cases x = a)case True with 1 show ?thesis by simp

    nextcase Falseshow ?thesisproof(cases x

  • case Falseshow ?thesisproof(cases height (insert x r) = height l + 2 )case False with 2 Node(3 ,4 ) 〈¬x < a〉 show ?thesis by (auto simp:

    height balR2 )nextcase Truehence (height (balR l a (insert x r)) = height l + 2 ) ∨(height (balR l a (insert x r)) = height l + 3 ) (is ?A ∨ ?B)using 2 Node(3 ) height balR[OF True] by simp

    thus ?thesisproofassume ?A with 2 〈¬x < a〉 show ?thesis by (auto)

    nextassume ?B with 2 Node(4 ) True 〈¬x < a〉 show ?thesis by (simp)

    arithqed

    qedqed

    qedqed simp all

    Now an automatic proof without lemmas:

    theorem avl insert auto: avl t =⇒avl(insert x t) ∧ height (insert x t) ∈ {height t , height t + 1}

    apply (induction t rule: tree2 induct)

    apply (auto simp: balL def balR def node def max absorb2 split !: if splittree.split)done

    14.3.2 Deletion maintains AVL balance

    lemma avl split max :[[ avl t ; t 6= Leaf ]] =⇒avl (fst (split max t)) ∧height t ∈ {height(fst (split max t)), height(fst (split max t)) + 1}

    by(induct t rule: split max induct)(auto simp: balL def node def max absorb2 split !: prod .split if split tree.split)

    Deletion maintains the AVL property:

    theorem avl delete:avl t =⇒ avl(delete x t)avl t =⇒ height t ∈ {height (delete x t), height (delete x t) + 1}

    49

  • proof (induct t rule: tree2 induct)case (Node l a n r)case 1show ?caseproof(cases x = a)case True thus ?thesisusing 1 avl split max [of l ] by (auto intro!: avl balR split : prod .split)

    nextcase False thus ?thesisusing Node 1 by (auto intro!: avl balL avl balR)

    qedcase 2show ?caseproof(cases x = a)case True thus ?thesis using 2 avl split max [of l ]by(auto simp: balR def max absorb2 split !: if splits prod .split tree.split)

    nextcase Falseshow ?thesisproof(cases x

  • qedqed simp all

    A more automatic proof. Complete automation as for insertion seemshard due to resource requirements.

    theorem avl delete auto:avl t =⇒ avl(delete x t)avl t =⇒ height t ∈ {height (delete x t), height (delete x t) + 1}

    proof (induct t rule: tree2 induct)case (Node l a n r)case 1thus ?caseusing Node avl split max [of l ] by (auto intro!: avl balL avl balR split :

    prod .split)case 2show ?caseusing 2 Node avl split max [of l ]by auto

    (auto simp: balL def balR def max absorb1 max absorb2 split !:tree.splits prod .splits if splits)qed simp all

    14.4 Overall correctness

    interpretation S : Set by Orderedwhere empty = empty and isin = isin and insert = insert and delete =deleteand inorder = inorder and inv = avlproof (standard , goal cases)case 1 show ?case by (simp add : empty def )

    nextcase 2 thus ?case by(simp add : isin set inorder)

    nextcase 3 thus ?case by(simp add : inorder insert)

    nextcase 4 thus ?case by(simp add : inorder delete)

    nextcase 5 thus ?case by (simp add : empty def )

    nextcase 6 thus ?case by (simp add : avl insert(1 ))

    nextcase 7 thus ?case by (simp add : avl delete(1 ))

    qed

    51

  • 14.5 Height-Size Relation

    Any AVL tree of height n has at least fib (n+2 ) leaves:

    theorem avl fib bound :avl t =⇒ fib(height t + 2 ) ≤ size1 t

    proof (induction rule: tree2 induct)case (Node l a h r)have 1 : height l + 1 ≤ height r + 2 and 2 : height r + 1 ≤ height l + 2using Node.prems by auto

    have fib (max (height l) (height r) + 3 ) ≤ size1 l + size1 rproof casesassume height l ≥ height rhence fib (max (height l) (height r) + 3 ) = fib (height l + 3 )by(simp add : max absorb1 )

    also have . . . = fib (height l + 2 ) + fib (height l + 1 )by (simp add : numeral eq Suc)

    also have . . . ≤ size1 l + fib (height l + 1 )using Node by (simp)

    also have . . . ≤ size1 r + size1 lusing Node fib mono[OF 1 ] by auto

    also have . . . = size1 (Node l (a,h) r)by simp

    finally show ?thesisby (simp)

    nextassume ¬ height l ≥ height rhence fib (max (height l) (height r) + 3 ) = fib (height r + 3 )by(simp add : max absorb1 )

    also have . . . = fib (height r + 2 ) + fib (height r + 1 )by (simp add : numeral eq Suc)

    also have . . . ≤ size1 r + fib (height r + 1 )using Node by (simp)

    also have . . . ≤ size1 r + size1 lusing Node fib mono[OF 2 ] by auto

    also have . . . = size1 (Node l (a,h) r)by simp

    finally show ?thesisby (simp)

    qedalso have . . . = size1 (Node l (a,h) r)by simp

    finally show ?case by (simp del : fib.simps add : numeral eq Suc)qed auto

    52

  • lemma avl fib bound auto: avl t =⇒ fib (height t + 2 ) ≤ size1 tproof (induction t rule: tree2 induct)case Leaf thus ?case by (simp)

    nextcase (Node l a h r)have 1 : height l + 1 ≤ height r + 2 and 2 : height r + 1 ≤ height l + 2using Node.prems by auto

    have left : height l ≥ height r =⇒ ?case (is ?asm =⇒ )using Node fib mono[OF 1 ] by (simp add : max .absorb1 )

    have right : height l ≤ height r =⇒ ?caseusing Node fib mono[OF 2 ] by (simp add : max .absorb2 )

    show ?case using left right using Node.prems by simp linarithqed

    An exponential lower bound for fib:

    lemma fib lowerbound :defines ϕ ≡ (1 + sqrt 5 ) / 2shows real (fib(n+2 )) ≥ ϕ ˆ n

    proof (induction n rule: fib.induct)case 1then show ?case by simp

    nextcase 2then show ?case by (simp add : ϕ def real le lsqrt)

    nextcase (3 n)have ϕ ˆ Suc (Suc n) = ϕ ˆ 2 ∗ ϕ ˆ nby (simp add : field simps power2 eq square)

    also have . . . = (ϕ + 1 ) ∗ ϕ ˆ nby (simp all add : ϕ def power2 eq square field simps)

    also have . . . = ϕ ˆ Suc n + ϕ ˆ nby (simp add : field simps)

    also have . . . ≤ real (fib (Suc n + 2 )) + real (fib (n + 2 ))by (intro add mono 3 .IH )

    finally show ?case by simpqed

    The size of an AVL tree is (at least) exponential in its height:

    lemma avl size lowerbound :defines ϕ ≡ (1 + sqrt 5 ) / 2assumes avl tshows ϕ ˆ (height t) ≤ size1 t

    proof −have ϕ ˆ height t ≤ fib (height t + 2 )

    53

  • unfolding ϕ def by(rule fib lowerbound)also have . . . ≤ size1 tusing avl fib bound [of t ] assms by simp

    finally show ?thesis .qed

    The height of an AVL tree is most 1 / log 2 ϕ ≈ 1 .44 times worse thanlog 2 (real (size1 t)):

    lemma avl height upperbound :defines ϕ ≡ (1 + sqrt 5 ) / 2assumes avl tshows height t ≤ (1/log 2 ϕ) ∗ log 2 (size1 t)

    proof −have ϕ > 0 ϕ > 1 by(auto simp: ϕ def pos add strict)hence height t = log ϕ (ϕ ˆ height t) by(simp add : log nat power)also have . . . ≤ log ϕ (size1 t)using avl size lowerbound [OF assms(2 ), folded ϕ def ] 〈1 < ϕ〉

    by (simp add : le log of power)also have . . . = (1/log 2 ϕ) ∗ log 2 (size1 t)by(simp add : log base change[of 2 ϕ])

    finally show ?thesis .qed

    end

    15 Function lookup for Tree2

    theory Lookup2importsTree2CmpMap Specs

    begin

    fun lookup :: (( ′a::linorder ∗ ′b) ∗ ′c) tree ⇒ ′a ⇒ ′b option wherelookup Leaf x = None |lookup (Node l ((a,b), ) r) x =(case cmp x a of LT ⇒ lookup l x | GT ⇒ lookup r x | EQ ⇒ Some b)

    lemma lookup map of :sorted1 (inorder t) =⇒ lookup t x = map of (inorder t) x

    by(induction t rule: tree2 induct) (auto simp: map of simps split : option.split)

    end

    54

  • 16 AVL Tree Implementation of Maps

    theory AVL MapimportsAVL SetLookup2

    begin

    fun update :: ′a::linorder ⇒ ′b ⇒ ( ′a∗ ′b) tree ht ⇒ ( ′a∗ ′b) tree ht whereupdate x y Leaf = Node Leaf ((x ,y), 1 ) Leaf |update x y (Node l ((a,b), h) r) = (case cmp x a of

    EQ ⇒ Node l ((x ,y), h) r |LT ⇒ balL (update x y l) (a,b) r |GT ⇒ balR l (a,b) (update x y r))

    fun delete :: ′a::linorder ⇒ ( ′a∗ ′b) tree ht ⇒ ( ′a∗ ′b) tree ht wheredelete Leaf = Leaf |delete x (Node l ((a,b), h) r) = (case cmp x a of

    EQ ⇒ if l = Leaf then relse let (l ′, ab ′) = split max l in balR l ′ ab ′ r |

    LT ⇒ balR (delete x l) (a,b) r |GT ⇒ balL l (a,b) (delete x r))

    16.1 Functional Correctness

    theorem inorder update:sorted1 (inorder t) =⇒ inorder(update x y t) = upd list x y (inorder t)

    by (induct t) (auto simp: upd list simps inorder balL inorder balR)

    theorem inorder delete:sorted1 (inorder t) =⇒ inorder (delete x t) = del list x (inorder t)

    by(induction t)(auto simp: del list simps inorder balL inorder balR

    inorder split maxD split : prod .splits)

    16.2 AVL invariants

    16.2.1 Insertion maintains AVL balance

    theorem avl update:assumes avl tshows avl(update x y t)

    (height (update x y t) = height t ∨ height (update x y t) = height t+ 1 )

    55

  • using assmsproof (induction x y t rule: update.induct)case eq2 : (2 x y l a b h r)case 1show ?caseproof(cases x = a)case True with eq2 1 show ?thesis by simp

    nextcase Falsewith eq2 1 show ?thesisproof(cases x

  • show ?thesisproof(cases height (update x y r) = height l + 2 )

    case False with eq2 2 〈¬x < a〉 show ?thesis by (auto simp:height balR2 )

    nextcase Truehence (height (balR l (a,b) (update x y r)) = height l + 2 ) ∨(height (balR l (a,b) (update x y r)) = height l + 3 ) (is ?A ∨ ?B)using eq2 2 〈¬x < a〉 〈x 6= a〉 height balR[OF True] by simp

    thus ?thesisproofassume ?A with 2 〈¬x < a〉 show ?thesis by (auto)

    nextassume ?B with True 1 eq2 (4 ) 〈¬x < a〉 show ?thesis by (simp)

    arithqed

    qedqed

    qedqed simp all

    16.2.2 Deletion maintains AVL balance

    theorem avl delete:assumes avl tshows avl(delete x t) and height t = (height (delete x t)) ∨ height t =

    height (delete x t) + 1using assmsproof (induct t rule: tree2 induct)case (Node l ab h r)obtain a b where [simp]: ab = (a,b) by fastforcecase 1show ?caseproof(cases x = a)case True with Node 1 show ?thesisusing avl split max [of l ] by (auto intro!: avl balR split : prod .split)

    nextcase Falseshow ?thesisproof(cases x

  • qedcase 2show ?caseproof(cases x = a)case True then show ?thesis using 1 avl split max [of l ]by(auto simp: balR def max absorb2 split !: if splits prod .split tree.split)

    nextcase Falseshow ?thesisproof(cases x

  • nextcase 3 thus ?case by(simp add : inorder update)

    nextcase 4 thus ?case by(simp add : inorder delete)

    nextcase 5 show ?case by (simp add : empty def )

    nextcase 6 thus ?case by(simp add : avl update(1 ))

    nextcase 7 thus ?case by(simp add : avl delete(1 ))

    qed

    end

    17 AVL Tree with Balance Factors (1)

    theory AVL Bal SetimportsCmpIsin2

    begin

    This version detects height increase/decrease from above via the changein balance factors.

    datatype bal = Lh | Bal | Rh

    type synonym ′a tree bal = ( ′a ∗ bal) tree

    Invariant:

    fun avl :: ′a tree bal ⇒ bool whereavl Leaf = True |avl (Node l (a,b) r) =((case b ofBal ⇒ height r = height l |Lh ⇒ height l = height r + 1 |Rh ⇒ height r = height l + 1 )∧ avl l ∧ avl r)

    17.1 Code

    fun is bal whereis bal (Node l (a,b) r) = (b = Bal)

    fun incr where

    59

  • incr t t ′ = (t = Leaf ∨ is bal t ∧ ¬ is bal t ′)

    fun rot2 whererot2 A a B c C = (case B of(Node B1 (b, bb) B2) ⇒let b1 = if bb = Rh then Lh else Bal ;

    b2 = if bb = Lh then Rh else Balin Node (Node A (a,b1) B1) (b,Bal) (Node B2 (c,b2) C ))

    fun balL :: ′a tree bal ⇒ ′a ⇒ bal ⇒ ′a tree bal ⇒ ′a tree bal wherebalL AB c bc C = (case bc of

    Bal ⇒ Node AB (c,Lh) C |Rh ⇒ Node AB (c,Bal) C |Lh ⇒ (case AB ofNode A (a,Lh) B ⇒ Node A (a,Bal) (Node B (c,Bal) C ) |Node A (a,Bal) B ⇒ Node A (a,Rh) (Node B (c,Lh) C ) |Node A (a,Rh) B ⇒ rot2 A a B c C ))

    fun balR :: ′a tree bal ⇒ ′a ⇒ bal ⇒ ′a tree bal ⇒ ′a tree bal wherebalR A a ba BC = (case ba of

    Bal ⇒ Node A (a,Rh) BC |Lh ⇒ Node A (a,Bal) BC |Rh ⇒ (case BC ofNode B (c,Rh) C ⇒ Node (Node A (a,Bal) B) (c,Bal) C |Node B (c,Bal) C ⇒ Node (Node A (a,Rh) B) (c,Lh) C |Node B (c,Lh) C ⇒ rot2 A a B c C ))

    fun insert :: ′a::linorder ⇒ ′a tree bal ⇒ ′a tree bal whereinsert x Leaf = Node Leaf (x , Bal) Leaf |insert x (Node l (a, b) r) = (case cmp x a of

    EQ ⇒ Node l (a, b) r |LT ⇒ let l ′ = insert x l in if incr l l ′ then balL l ′ a b r else Node l ′ (a,b)

    r |GT ⇒ let r ′ = insert x r in if incr r r ′ then balR l a b r ′ else Node l

    (a,b) r ′)

    fun decr wheredecr t t ′ = (t 6= Leaf ∧ (t ′ = Leaf ∨ ¬ is bal t ∧ is bal t ′))

    fun split max :: ′a tree bal ⇒ ′a tree bal ∗ ′a wheresplit max (Node l (a, ba) r) =(if r = Leaf then (l ,a)else let (r ′,a ′) = split max r ;

    t ′ = if decr r r ′ then balL l a ba r ′ else Node l (a,ba) r ′

    60

  • in (t ′, a ′))

    fun delete :: ′a::linorder ⇒ ′a tree bal ⇒ ′a tree bal wheredelete Leaf = Leaf |delete x (Node l (a, ba) r) =(case cmp x a of

    EQ ⇒ if l = Leaf then relse let (l ′, a ′) = split max l in

    if decr l l ′ then balR l ′ a ′ ba r else Node l ′ (a ′,ba) r |LT ⇒ let l ′ = delete x l in if decr l l ′ then balR l ′ a ba r else Node l ′

    (a,ba) r |GT ⇒ let r ′ = delete x r in if decr r r ′ then balL l a ba r ′ else Node l

    (a,ba) r ′)

    17.2 Proofs

    lemmas split max induct = split max .induct [case names Node Leaf ]

    lemmas splits = if splits tree.splits bal .splits

    declare Let def [simp]

    17.2.1 Proofs about insertion

    lemma avl insert : avl t =⇒avl(insert x t) ∧height(insert x t) = height t + (if incr t (insert x t) then 1 else 0 )

    apply(induction x t rule: insert .induct)apply(auto split !: splits)done

    The following two auxiliary lemma merely simplify the proof of in-order insert.

    lemma [simp]: [] 6= ins list x xsby(cases xs) auto

    lemma [simp]: avl t =⇒ insert x t 6= 〈l , (a, Rh), 〈〉〉 ∧ insert x t 6= 〈〈〉, (a,Lh), r〉by(drule avl insert [of x ]) (auto split : splits)

    theorem inorder insert :[[ avl t ; sorted(inorder t) ]] =⇒ inorder(insert x t) = ins list x (inorder

    t)apply(induction t)apply (auto simp: ins list simps split !: splits)

    61

  • done

    17.2.2 Proofs about deletion

    lemma inorder balR:[[ ba = Rh −→ r 6= Leaf ; avl r ]]=⇒ inorder (balR l a ba r) = inorder l @ a # inorder r

    by (auto split : splits)

    lemma inorder balL:[[ ba = Lh −→ l 6= Leaf ; avl l ]]=⇒ inorder (balL l a ba r) = inorder l @ a # inorder r

    by (auto split : splits)

    lemma height 1 iff : avl t =⇒ height t = Suc 0 ←→ (∃ x . t = Node Leaf(x ,Bal) Leaf )by(cases t) (auto split : splits prod .splits)

    lemma avl split max :[[ split max t = (t ′,a); avl t ; t 6= Leaf ]] =⇒avl t ′ ∧ height t = height t ′ + (if decr t t ′ then 1 else 0 )

    apply(induction t arbitrary : t ′ a rule: split max induct)apply(auto simp: max absorb1 max absorb2 height 1 iff split !: splits prod .splits)done

    lemma avl delete: avl t =⇒avl (delete x t) ∧height t = height (delete x t) + (if decr t (delete x t) then 1 else 0 )

    apply(induction x t rule: delete.induct)apply(auto simp: max absorb1 max absorb2 height 1 iff dest : avl split maxsplit !: splits prod .splits)done

    lemma inorder split maxD :[[ split max t = (t ′,a); t 6= Leaf ; avl t ]] =⇒inorder t ′ @ [a] = inorder t

    apply(induction t arbitrary : t ′ rule: split max .induct)apply(fastforce split !: splits prod .splits)apply simpdone

    lemma neq Leaf if height neq 0 : height t 6= 0 =⇒ t 6= Leafby auto

    62

  • lemma split max Leaf : [[ t 6= Leaf ; avl t ]] =⇒ split max t = (〈〉, x ) ←→ t= Node Leaf (x ,Bal) Leafby(cases t) (auto split : splits prod .splits)

    theorem inorder delete:[[ avl t ; sorted(inorder t) ]] =⇒ inorder (delete x t) = del list x (inorder

    t)apply(induction t rule: tree2 induct)apply(auto simp: del list simps inorder balR inorder balL avl delete inorder split maxD

    split max Leaf neq Leaf if height neq 0simp del : balL.simps balR.simps split !: splits prod .splits)

    done

    17.2.3 Set Implementation

    interpretation S : Set by Orderedwhere empty = Leaf and isin = isinand insert = insertand delete = deleteand inorder = inorder and inv = avl

    proof (standard , goal cases)case 1 show ?case by (simp)

    nextcase 2 thus ?case by(simp add : isin set inorder)

    nextcase 3 thus ?case by(simp add : inorder insert)

    nextcase 4 thus ?case by(simp add : inorder delete)

    nextcase 5 thus ?case by (simp)

    nextcase 6 thus ?case by (simp add : avl insert)

    nextcase 7 thus ?case by (simp add : avl delete)

    qed

    end

    18 AVL Tree with Balance Factors (2)

    theory AVL Bal2 SetimportsCmpIsin2

    63

  • begin

    This version passes a flag (Same/Diff ) back up to signal if the heightchanged.

    datatype bal = Lh | Bal | Rh

    type synonym ′a tree bal = ( ′a ∗ bal) tree

    Invariant:

    fun avl :: ′a tree bal ⇒ bool whereavl Leaf = True |avl (Node l (a,b) r) =((case b ofBal ⇒ height r = height l |Lh ⇒ height l = height r + 1 |Rh ⇒ height r = height l + 1 )∧ avl l ∧ avl r)

    18.1 Code

    datatype ′a alt = Same ′a | Diff ′a

    type synonym ′a tree bal2 = ′a tree bal alt

    fun tree :: ′a alt ⇒ ′a wheretree(Same t) = t |tree(Diff t) = t

    fun rot2 whererot2 A a B c C = (case B of(Node B1 (b, bb) B2) ⇒let b1 = if bb = Rh then Lh else Bal ;

    b2 = if bb = Lh then Rh else Balin Node (Node A (a,b1) B1) (b,Bal) (Node B2 (c,b2) C ))

    fun balL :: ′a tree bal2 ⇒ ′a ⇒ bal ⇒ ′a tree bal ⇒ ′a tree bal2 wherebalL AB ′ c bc C = (case AB ′ of

    Same AB ⇒ Same (Node AB (c,bc) C ) |Diff AB ⇒ (case bc ofBal ⇒ Diff (Node AB (c,Lh) C ) |Rh ⇒ Same (Node AB (c,Bal) C ) |Lh ⇒ (case AB ofNode A (a,Lh) B ⇒ Same(Node A (a,Bal) (Node B (c,Bal) C )) |Node A (a,Rh) B ⇒ Same(rot2 A a B c C ))))

    64

  • fun balR :: ′a tree bal ⇒ ′a ⇒ bal ⇒ ′a tree bal2 ⇒ ′a tree bal2 wherebalR A a ba BC ′ = (case BC ′ of

    Same BC ⇒ Same (Node A (a,ba) BC ) |Diff BC ⇒ (case ba ofBal ⇒ Diff (Node A (a,Rh) BC ) |Lh ⇒ Same (Node A (a,Bal) BC ) |Rh ⇒ (case BC ofNode B (c,Rh) C ⇒ Same(Node (Node A (a,Bal) B) (c,Bal) C ) |Node B (c,Lh) C ⇒ Same(rot2 A a B c C ))))

    fun ins :: ′a::linorder ⇒ ′a tree bal ⇒ ′a tree bal2 whereins x Leaf = Diff (Node Leaf (x , Bal) Leaf ) |ins x (Node l (a, b) r) = (case cmp x a of

    EQ ⇒ Same(Node l (a, b) r) |LT ⇒ balL (ins x l) a b r |GT ⇒ balR l a b (ins x r))

    definition insert :: ′a::linorder ⇒ ′a tree bal ⇒ ′a tree bal whereinsert x t = tree(ins x t)

    fun baldR :: ′a tree bal ⇒ ′a ⇒ bal ⇒ ′a tree bal2 ⇒ ′a tree bal2 wherebaldR AB c bc C ′ = (case C ′ of

    Same C ⇒ Same (Node AB (c,bc) C ) |Diff C ⇒ (case bc ofBal ⇒ Same (Node AB (c,Lh) C ) |Rh ⇒ Diff (Node AB (c,Bal) C ) |Lh ⇒ (case AB ofNode A (a,Lh) B ⇒ Diff (Node A (a,Bal) (Node B (c,Bal) C )) |Node A (a,Bal) B ⇒ Same(Node A (a,Rh) (Node B (c,Lh) C )) |Node A (a,Rh) B ⇒ Diff (rot2 A a B c C ))))

    fun baldL :: ′a tree bal2 ⇒ ′a ⇒ bal ⇒ ′a tree bal ⇒ ′a tree bal2 wherebaldL A ′ a ba BC = (case A ′ of

    Same A ⇒ Same (Node A (a,ba) BC ) |Diff A ⇒ (case ba ofBal ⇒ Same (Node A (a,Rh) BC ) |Lh ⇒ Diff (Node A (a,Bal) BC ) |Rh ⇒ (case BC ofNode B (c,Rh) C ⇒ Diff (Node (Node A (a,Bal) B) (c,Bal) C ) |Node B (c,Bal) C ⇒ Same(Node (Node A (a,Rh) B) (c,Lh) C ) |Node B (c,Lh) C ⇒ Diff (rot2 A a B c C ))))

    fun split max :: ′a tree bal ⇒ ′a tree bal2 ∗ ′a where

    65

  • split max (Node l (a, ba) r) =(if r = Leaf then (Diff l ,a) else let (r ′,a ′) = split max r in (baldR l a ba

    r ′, a ′))

    fun del :: ′a::linorder ⇒ ′a tree bal ⇒ ′a tree bal2 wheredel Leaf = Same Leaf |del x (Node l (a, ba) r) =(case cmp x a of

    EQ ⇒ if l = Leaf then Diff relse let (l ′, a ′) = split max l in baldL l ′ a ′ ba r |

    LT ⇒ baldL (del x l) a ba r |GT ⇒ baldR l a ba (del x r))

    definition delete :: ′a::linorder ⇒ ′a tree bal ⇒ ′a tree bal wheredelete x t = tree(del x t)

    lemmas split max induct = split max .induct [case names Node Leaf ]

    lemmas splits = if splits tree.splits alt .splits bal .splits

    18.2 Proofs

    18.2.1 Proofs about insertion

    lemma avl ins case: avl t =⇒ case ins x t ofSame t ′⇒ avl t ′ ∧ height t ′ = height t |Diff t ′⇒ avl t ′ ∧ height t ′ = height t + 1 ∧

    (∀ l a r . t ′ = Node l (a,Bal) r −→ a = x ∧ l = Leaf ∧ r = Leaf )apply(induction x t rule: ins.induct)apply(auto simp: max absorb1 split !: splits)done

    corollary avl insert : avl t =⇒ avl(insert x t)using avl ins case[of t x ] by (simp add : insert def split : splits)

    lemma ins Diff [simp]: avl t =⇒ins x t 6= Diff Leaf ∧(ins x t = Diff (Node l (a,Bal) r) ←→ t = Leaf ∧ a = x ∧ l=Leaf ∧

    r=Leaf ) ∧ins x t 6= Diff (Node l (a,Rh) Leaf ) ∧ins x t 6= Diff (Node Leaf (a,Lh) r)

    by(drule avl ins case[of x ]) (auto split : splits)

    66

  • theorem inorder ins:[[ avl t ; sorted(inorder t) ]] =⇒ inorder(tree(ins x t)) = ins list x (inorder

    t)apply(induction t)apply (auto simp: ins list simps split !: splits)done

    18.2.2 Proofs about deletion

    lemma inorder baldL:[[ ba = Rh −→ r 6= Leaf ; avl r ]]=⇒ inorder (tree(baldL l a ba r)) = inorder (tree l) @ a # inorder r

    by (auto split : splits)

    lemma inorder baldR:[[ ba = Lh −→ l 6= Leaf ; avl l ]]=⇒ inorder (tree(baldR l a ba r)) = inorder l @ a # inorder (tree r)

    by (auto split : splits)

    lemma avl split max :[[ split max t = (t ′,a); avl t ; t 6= Leaf ]] =⇒ case t ′ ofSame t ′⇒ avl t ′ ∧ height t = height t ′ |Diff t ′⇒ avl t ′ ∧ height t = height t ′ + 1

    apply(induction t arbitrary : t ′ a rule: split max induct)apply(fastforce simp: max absorb1 max absorb2 split !: splits prod .splits)apply simpdone

    lemma avl del case: avl t =⇒ case del x t ofSame t ′⇒ avl t ′ ∧ height t = height t ′ |Diff t ′⇒ avl t ′ ∧ height t = height t ′ + 1

    apply(induction x t rule: del .induct)apply(auto simp: max absorb1 max absorb2 dest : avl split max split !: splitsprod .splits)done

    corollary avl delete: avl t =⇒ avl(delete x t)using avl del case[of t x ] by(simp add : delete def split : splits)

    lemma inorder split maxD :[[ split max t = (t ′,a); t 6= Leaf ; avl t ]] =⇒inorder (tree t ′) @ [a] = inorder t

    apply(induction t arbitrary : t ′ rule: split max .induct)

    67

  • apply(fastforce split !: splits prod .splits)apply simpdone

    lemma neq Leaf if height neq 0 [simp]: height t 6= 0 =⇒ t 6= Leafby auto

    theorem inorder del :[[ avl t ; sorted(inorder t) ]] =⇒ inorder (tree(del x t)) = del list x (inorder

    t)apply(induction t rule: tree2 induct)apply(auto simp: del list simps inorder baldL inorder baldR avl delete in-order split maxD

    simp del : baldR.simps baldL.simps split !: splits prod .splits)done

    18.2.3 Set Implementation

    interpretation S : Set by Orderedwhere empty = Leaf and isin = isinand insert = insertand delete = deleteand inorder = inorder and inv = avl

    proof (standard , goal cases)case 1 show ?case by (simp)

    nextcase 2 thus ?case by(simp add : isin set inorder)

    nextcase 3 thus ?case by(simp add : inorder ins insert def )

    nextcase 4 thus ?case by(simp add : inorder del delete def )

    nextcase 5 thus ?case by (simp)

    nextcase 6 thus ?case by (simp add : avl insert)

    nextcase 7 thus ?case by (simp add : avl delete)

    qed

    end

    19 Height-Balanced Trees

    theory Height Balanced Tree

    68

  • importsCmpIsin2

    begin

    Height-balanced trees (HBTs) can be seen as a generalization of AVLtrees. The code and the proofs were obtained by small modifications of theAVL theories. This is an implementation of sets via HBTs.

    type synonym ′a tree ht = ( ′a∗nat) tree

    definition empty :: ′a tree ht whereempty = Leaf

    The maximal amount by which the height of two siblings may differ:

    locale HBT =fixes m :: natassumes [arith]: m > 0begin

    I