15 150 fall 2020 lecture 6
play

15-150 Fall 2020 Lecture 6 Stephen Brookes Most of the time I don't - PowerPoint PPT Presentation

15-150 Fall 2020 Lecture 6 Stephen Brookes Most of the time I don't have much fun . The rest of the time I don't have any fun at all. today Sorting an integer list Using specifications to guide program design Helper functions should


  1. comments isort (y::R) calls isort R • The proof was “by structural induction on L” • Every list value L is either [ ] (nil) or y::R, where R is a “smaller” list value • We could just as well have said “by induction on length of L” • [ ] has length 0 • 0 ≤ length R < length(y::R)

  2. perm facts y::(a perm of R) is a perm of (y::R) A perm of a perm of L is a perm of L In the correctness proof we used some obvious facts about permutations.

  3. corollaries

  4. corollaries isort is a total function from int list to int list

  5. corollaries isort is a total function from int list to int list When e evaluates to L, isort e evaluates to the sorted version of L

  6. a variation fun isort [ ] = [ ] | isort (x::R) = ins (x, isort R) fun isort ’ [ ] = [ ] | isort ’ [x] = [x] | isort ’ (x::R) = ins (x, isort ’ R)

  7. a variation fun isort [ ] = [ ] | isort (x::R) = ins (x, isort R) is this clause fun isort ’ [ ] = [ ] redundant | isort ’ [x] = [x] | isort ’ (x::R) = ins (x, isort ’ R)

  8. variation isort ’ : int list -> int list fun isort ’ [ ] = [ ] | isort ’ [x] = [x] | isort ’ (x::R) = ins (x, isort ’ R) If in doubt, test, then prove

  9. variation isort ’ : int list -> int list fun isort ’ [ ] = [ ] | isort ’ [x] = [x] | isort ’ (x::R) = ins (x, isort ’ R) If in doubt, test, then prove

  10. variation isort ’ : int list -> int list fun isort ’ [ ] = [ ] | isort ’ [x] = [x] | isort ’ (x::R) = ins (x, isort ’ R) If in doubt, test, then prove

  11. equivalent • isort and isort ’ are extensionally equivalent: For all L : int list, isort L = isort ’ L. • Proof? See lecture notes… OR: Re-do the isort proof for isort ’ (easy) Hence they satisfy the same spec, so For all L : int list, isort L = isort ’ L = the sorted perm of L

  12. equivalent • isort and isort ’ are extensionally equivalent: For all L : int list, isort L = isort ’ L. • Proof? See lecture notes… OR: Re-do the isort proof for isort ’ (easy) Hence they satisfy the same spec, so For all L : int list, isort L = isort ’ L = the sorted perm of L No need for extra clause but it doesn’t do any harm

  13. work • Let W ins (n) be the work for ins(x, L) when x, L are values and L has length n • Let W isort (n) be the work for isort(L) when L is a list of length n

  14. work • Let W ins (n) be the work for ins(x, L) when x, L are values and L has length n W ins (n) is O(n) • Let W isort (n) be the work for isort(L) when L is a list of length n

  15. work • Let W ins (n) be the work for ins(x, L) when x, L are values and L has length n W ins (n) is O(n) • Let W isort (n) be the work for isort(L) when L is a list of length n W isort (0) = 1 W isort (n) = 1 + W ins (n-1) + W isort (n-1) for n > 0

  16. work • Let W ins (n) be the work for ins(x, L) when x, L are values and L has length n W ins (n) is O(n) • Let W isort (n) be the work for isort(L) when L is a list of length n

  17. work • Let W ins (n) be the work for ins(x, L) when x, L are values and L has length n W ins (n) is O(n) • Let W isort (n) be the work for isort(L) when L is a list of length n W isort (0) = 1 W isort (n) = O(n) + W isort (n-1) for n > 0

  18. work • Let W ins (n) be the work for ins(x, L) when x, L are values and L has length n W ins (n) is O(n) • Let W isort (n) be the work for isort(L) when L is a list of length n W isort (0) = 1 W isort (n) = O(n) + W isort (n-1) for n > 0 W isort (n) is O(n 2 )

  19. work WE CAN DO BETTER! • Let W ins (n) be the work for ins(x, L) THIS IS SLOW! when x, L are values and L has length n W ins (n) is O(n) • Let W isort (n) be the work for isort(L) when L is a list of length n W isort (0) = 1 W isort (n) = O(n) + W isort (n-1) for n > 0 W isort (n) is O(n 2 )

  20. mergesort Conceptually, a merge sort works as follows: 1. Divide the unsorted list into n sublists, each containing 1 element. 2. Repeatedly Merge sublists to produce new sublists until there is only 1 sublist left.

  21. mergesort Conceptually, a merge sort works as follows: 1. Divide the unsorted list into n sublists, each containing 1 element. 2. Repeatedly Merge sublists to produce new sublists until there is only 1 sublist left. Wrong! Wrong! Wrong!

  22. mergesort Conceptually, a merge sort works as follows: 1. Divide the unsorted list into n sublists, each containing 1 element. 2. Repeatedly Merge sublists to produce new sublists until there is only 1 sublist left. Wrong! Wrong! Wrong! Doesn’t say “recursive”...

  23. mergesort Conceptually, a merge sort works as follows: 1. Divide the unsorted list into n sublists, … what’s n? each containing 1 element. 2. Repeatedly Merge sublists to produce new sublists until there is only 1 sublist left. Wrong! Wrong! Wrong! Doesn’t say “recursive”...

  24. mergesort Conceptually, a merge sort works as follows: 1. Divide the unsorted list into n sublists, … what’s n? each containing 1 element. … repeatedly???? 2. Repeatedly Merge sublists to produce new sublists until there is only 1 sublist left. Wrong! Wrong! Wrong! Doesn’t say “recursive”...

  25. mergesort Conceptually, a merge sort works as follows: 1. Divide the unsorted list into n sublists, … what’s n? each containing 1 element. … repeatedly???? 2. Repeatedly Merge sublists to produce new sublists until there is only 1 sublist left. … and then? Wrong! Wrong! Wrong! Doesn’t say “recursive”...

  26. mergesort Conceptually, a merge sort works as follows: 1. Divide the unsorted list into n sublists, … what’s n? each containing 1 element. … repeatedly???? 2. Repeatedly Merge sublists to produce new sublists until there is only 1 sublist left. … and then? What’s the output? How does it relate to the input? Wrong! Wrong! Wrong! Doesn’t say “recursive”...

  27. mergesort A recursive divide-and-conquer algorithm • If list has length 0 or 1, do nothing. • Otherwise, split the list into two shorter lists, sort these two lists, merge the (sorted) results

  28. implementation • First, let’s design helper functions split : int list -> int list * int list merge : int list * int list -> int list

  29. implementation • First, let’s design helper functions split : int list -> int list * int list merge : int list * int list -> int list (what specs should we use?)

  30. implementation • First, let’s design helper functions split : int list -> int list * int list merge : int list * int list -> int list (what specs should we use?) split splits a list into two sublists merge combines two sorted lists into one

  31. implementation • First, let’s design helper functions split : int list -> int list * int list merge : int list * int list -> int list (what specs should we use?) split splits a list into two sublists merge combines two sorted lists into one (a bit imprecise, but we’ll fix that…)

  32. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L.

  33. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L. write as length(A) ≈ length(B)

  34. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L.

  35. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L. fun split [ ] = ([ ], [ ])

  36. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L. fun split [ ] = ([ ], [ ]) | split [x] = ([x], [ ])

  37. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L. fun split [ ] = ([ ], [ ]) | split [x] = ([x], [ ]) | split (x::y::L) =

  38. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L. fun split [ ] = ([ ], [ ]) | split [x] = ([x], [ ]) | split (x::y::L) = let val (A, B) = split L in

  39. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L. fun split [ ] = ([ ], [ ]) | split [x] = ([x], [ ]) | split (x::y::L) = let val (A, B) = split L in (x::A, y::B) end

  40. split split : int list -> int list * int list ENSURES split(L) = a pair of lists (A, B) such that length(A) and length(B) differ by at most 1, and A@B is a permutation of L. fun split [ ] = ([ ], [ ]) | split [x] = ([x], [ ]) | split (x::y::L) = let val (A, B) = split L in (x::A, y::B) end note the use of list patterns and pair patterns

  41. split equations For all values x, y : int and L : int list, split [ ] = ([ ], [ ]) split [x] = ([x], [ ]) split (x::y::L) = let val (A, B) = split L in (x::A, y::B) end

  42. split equations For all values x, y : int and L : int list, split [ ] = ([ ], [ ]) split [x] = ([x], [ ]) split (x::y::L) =

  43. split equations For all values x, y : int and L : int list, split [ ] = ([ ], [ ]) split [x] = ([x], [ ]) (x::A, y::B), split (x::y::L) = where (A, B) = split L

  44. split equations For all values x, y : int and L : int list, split [ ] = ([ ], [ ]) split [x] = ([x], [ ]) (x::A, y::B), split (x::y::L) = where (A, B) = split L Can be used to calculate split R for any value R : int list

  45. split equations For all values x, y : int and L : int list, split [ ] = ([ ], [ ]) split [x] = ([x], [ ]) (x::A, y::B), split (x::y::L) = where (A, B) = split L Can be used to calculate split R for any value R : int list split [4,2,1,3] = ([4,1], [2,3])

  46. split equations For all values x, y : int and L : int list, split [ ] = ([ ], [ ]) split [x] = ([x], [ ]) (x::A, y::B), split (x::y::L) = where (A, B) = split L Can be used to calculate split R for any value R : int list split [4,2,1,3] = ([4,1], [2,3]) split [4,2,1] = ([4,1], [2])

  47. For all L:int list, split(L) = a pair of lists (A, B) such that length(A) ≈ length(B) and A@B is a permutation of L. • Proof : by (strong) induction on length of L • Base cases : L = [ ], [x] EASY • Inductive case : L=x::(y::R) R is shorter than L Assume Induction Hypothesis: split(R) = a pair (A ’ , B ’ ) such that length(A ’ ) ≈ length(B ’ ) and A ’ @B ’ is a perm of R. Show that split(x::y::R) = a pair (A, B) such that length(A) ≈ length(B) and A@B is a perm of x::(y::R).

  48. For all L:int list, split(L) = a pair of lists (A, B) such that length(A) ≈ length(B) and A@B is a permutation of L. • Proof : by (strong) induction on length of L • Base cases : L = [ ], [x] split [ ] = ([ ], [ ]) EASY split [x] = ([x], [ ]) • Inductive case : L=x::(y::R) R is shorter than L Assume Induction Hypothesis: split(R) = a pair (A ’ , B ’ ) such that length(A ’ ) ≈ length(B ’ ) and A ’ @B ’ is a perm of R. Show that split(x::y::R) = a pair (A, B) such that length(A) ≈ length(B) and A@B is a perm of x::(y::R).

  49. For all L:int list, split(L) = a pair of lists (A, B) such that length(A) ≈ length(B) and A@B is a permutation of L. • Proof : by (strong) induction on length of L • Base cases : L = [ ], [x] split [ ] = ([ ], [ ]) EASY split [x] = ([x], [ ]) • Inductive case : L=x::(y::R) R is shorter than L Assume Induction Hypothesis: split(R) = a pair (A ’ , B ’ ) such that length(A ’ ) ≈ length(B ’ ) and A ’ @B ’ is a perm of R. Show that split(x::y::R) = a pair (A, B) such that length(A) ≈ length(B) and A@B is a perm of x::(y::R). split (x::y::R) = (x::A ’ , y::B ’ ) length(x::A ’ ) ≈ length(y::B ’ ) (x::A ’ )@(y::B ’ ) is a perm of x::(y::R)

  50. comments • We used strong induction on length of L Reason: split(x::y::R) calls split(R) and length of R is two less than length of x::y::R. • If length L = n > 1 and split(L) = (A, B), A and B are shorter than L If n is even > 1, length A = length B = n div 2 < n. If n is odd > 1, length A = (n div 2) + 1 < n, length B = n div 2 < n.

  51. merge merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B

  52. merge merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B fun merge (A, [ ]) = A | merge ([ ], B) = B

  53. merge merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B fun merge (A, [ ]) = A | merge ([ ], B) = B | merge (x::L, y::R) = case compare(x, y) of

  54. merge merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B fun merge (A, [ ]) = A | merge ([ ], B) = B | merge (x::L, y::R) = case compare(x, y) of LESS => x :: merge(L, y::R)

  55. merge merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B fun merge (A, [ ]) = A | merge ([ ], B) = B | merge (x::L, y::R) = case compare(x, y) of LESS => x :: merge(L, y::R) | EQUAL => x :: y :: merge(L, R)

  56. merge merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B fun merge (A, [ ]) = A | merge ([ ], B) = B | merge (x::L, y::R) = case compare(x, y) of LESS => x :: merge(L, y::R) | EQUAL => x :: y :: merge(L, R) | GREATER => y :: merge(x::L, R)

  57. merge merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B fun merge (A, [ ]) = A | merge ([ ], B) = B | merge (x::L, y::R) = case compare(x, y) of LESS => x :: merge(L, y::R) | EQUAL => x :: y :: merge(L, R) | GREATER => y :: merge(x::L, R) We need a 3-way branch, so cased comparison is better than nested if-then-else

  58. merge equations For all values x, y : int and A, B : int list, merge (A, [ ]) = A merge ([ ], B) = B merge (x::A, y::B) = case compare(x, y) of LESS => x :: merge(A, y::B) | EQUAL => x :: y :: merge(A, B) | GREATER => y :: merge(x::A, B)

  59. merge equations For all values x, y : int and A, B : int list, merge (A, [ ]) = A merge ([ ], B) = B

  60. merge equations For all values x, y : int and A, B : int list, merge (A, [ ]) = A merge ([ ], B) = B if x<y merge (x::A, y::B) = x :: merge(A, y::B) if x=y = x :: y :: merge(A, B) if x>y = y :: merge(x::A, B)

  61. merge equations For all values x, y : int and A, B : int list, merge (A, [ ]) = A merge ([ ], B) = B if x<y merge (x::A, y::B) = x :: merge(A, y::B) if x=y = x :: y :: merge(A, B) if x>y = y :: merge(x::A, B) Can be used to evaluate merge(L, R) for all values L, R : int list

  62. merge equations For all values x, y : int and A, B : int list, merge (A, [ ]) = A merge ([ ], B) = B if x<y merge (x::A, y::B) = x :: merge(A, y::B) if x=y = x :: y :: merge(A, B) if x>y = y :: merge(x::A, B) Can be used to evaluate merge(L, R) for all values L, R : int list merge([1,4], [2,3]) = [1,2,3,4]

  63. correctness? fun merge (A, [ ]) = A | merge ([ ], B) = B | merge (x::L, y::R) = case compare(x, y) of LESS => x :: merge(L, y::R) | EQUAL => x :: y :: merge(L, R) | GREATER => y :: merge(x::L, R) How do we prove this function satisfies the spec? • Induction, but on on what ? - in base cases, at least one list is empty - in recursive calls, one or both is shorter

  64. correctness? fun merge (A, [ ]) = A | merge ([ ], B) = B | merge (x::L, y::R) = case compare(x, y) of LESS => x :: merge(L, y::R) | EQUAL => x :: y :: merge(L, R) | GREATER => y :: merge(x::L, R) How do we prove this function satisfies the spec? • Induction, but on on what ? The product of list lengths! - in base cases, at least one list is empty - in recursive calls, one or both is shorter

  65. correctness For all sorted lists A and B, merge(A, B) = a sorted permutation of A@B. Proof : strong induction on product of lengths of A, B. • Base cases : (A, [ ]) and ([ ], B). (i) Show: if A is sorted, merge(A, [ ]) = a sorted perm of A@[ ]. (ii) Show: if B is sorted, merge([ ], B) = a sorted perm of [ ]@B. • Inductive case : (x::A, y::B) Assume IH: for all pairs of sorted lists (A ’ , B ’ ) with smaller product of lengths than (x::A, y::B), merge(A ’ , B ’ ) = a sorted perm of A ’ @B ’ . Show: if x::A and y::B are sorted, then merge(x::A, y::B) = a sorted perm of (x::A)@(y::B). Exercise: fill in the details!

  66. msort • We proved that split and merge are correct split : int list -> int list * int list ENSURES split L = a pair of lists (A, B) such that length(A) ≈ length(B) and A@B is a perm of L merge : int list * int list -> int list REQUIRES A and B are sorted lists ENSURES merge(A, B) = a sorted perm of A@B • Now let’s use them to define msort msort : int list -> int list ENSURES msort L = a sorted perm of L

  67. msort msort : int list -> int list ENSURES msort(L) = a sorted perm of L

  68. msort msort : int list -> int list ENSURES msort(L) = a sorted perm of L fun msort [ ] = [ ]

Recommend


More recommend