Skip to content
REFERENCE / ZLIB × LEAN

LZ77Copy.lean

Source snapshot · 110b0eec09542cb0 · Source at the matching commit ↗

Lean source with line numbers. Follow a line number to locate a statement, or an import to read its dependency.

1import ZlibF.Math.LZ77CopySpec
2
3/-!
4# Bytewise array copies implement the independent LZ77 operation
5
6The proof follows one byte at a time. The source of an overlapping copy
7is read from the updated array, exactly as copyBack reads growing output.
8-/
9
10set_option autoImplicit false
11
12namespace ZlibF.Math.LZ77Copy
13open C ZlibF.Spec Zlib.Inffast.Proofs
14
15private theorem written_length (bytes : Array UInt8) (offset count : Nat)
16    (hc : count ≤ offset) (hb : offset ≤ bytes.size) :
17    (writtenBytes bytes offset count).length = count := by
18  simp only [writtenBytes, List.length_take, List.length_drop, Array.length_toList]
19  omega
20
21private theorem written_get (bytes : Array UInt8) (offset count i : Nat) :
22    (writtenBytes bytes offset count)[i]? =
23      if i < count then bytes[offset - count + i]? else none := by
24  simp only [writtenBytes, List.getElem?_take, List.getElem?_drop, Array.getElem?_toList]
25
26private theorem written_set_append (bytes : Array UInt8) (offset count : Nat)
27    (value : UInt8) (hc : count ≤ offset) (hb : offset < bytes.size) :
28    writtenBytes (bytes.set! offset value) (offset + 1) (count + 1) =
29      writtenBytes bytes offset count ++ [value] := by
30  apply List.ext_getElem?
31  intro i
32  rw [written_get, List.getElem?_append, written_length bytes offset count hc (by omega)]
33  have hstart : offset + 1 - (count + 1) = offset - count := by omega
34  rw [hstart]
35  by_cases hi : i < count
36  · have hne : offset ≠ offset - count + i := by omega
37    simp [hi, show i < count + 1 by omega, written_get, Array.set!_eq_setIfInBounds,
38      Array.getElem?_setIfInBounds, hne]
39  · by_cases he : i = count
40    · subst i
41      have hs : offset - count + count = offset := by omega
42      simp [show ¬ count < count by omega, show count < count + 1 by omega, hs,
43        Array.set!_eq_setIfInBounds, Array.getElem?_setIfInBounds, hb]
44    · have hn : ¬ i < count + 1 := by omega
45      have hz : i - count ≠ 0 := by omega
46      simp [hi, hn, List.getElem?_singleton, hz]
47
48private theorem output_source (dict : List UInt8) (bytes : Array UInt8)
49    (offset count dist : Nat) (hc : count ≤ offset) (hb : offset ≤ bytes.size)
50    (hd : 0 < dist) (hcount : dist ≤ count) :
51    (dict ++ writtenBytes bytes offset count).getD
52      ((dict ++ writtenBytes bytes offset count).length - dist) 0 =
53        bytes.getD (offset - dist) 0 := by
54  rw [List.length_append, written_length bytes offset count hc hb]
55  have hidx : dict.length + count - dist = dict.length + (count - dist) := by omega
56  have hright : dict.length ≤ dict.length + (count - dist) := by omega
57  have hsmall : count - dist < count := by omega
58  have hsource : offset - count + (count - dist) = offset - dist := by omega
59  simp only [List.getD_eq_getElem?_getD, hidx,
60    List.getElem?_append_right hright, Nat.add_sub_cancel_left, written_get,
61    hsmall, ite_true, hsource, Array.getD_eq_getD_getElem?]
62
63/-- The byte source is in the current output; reads of earlier writes
64implement arbitrary overlapping matches. -/
65theorem output_copy_refines_lz77 : Goal.output_copy_refines_lz77 := by
66  intro dict bytes offset count dist n
67  induction n generalizing bytes offset count with
68  | zero => intro _ _ _ _; simp [cpyN, copyBack]
69  | succ n ih =>
70    intro hc hd hdist hb
71    have ho : offset < bytes.size := by omega
72    have hsrc : offset - dist + 1 = offset + 1 - dist := by omega
73    rw [cpyN, hsrc]
74    rw [show offset + (n + 1) = offset + 1 + n by omega,
75      show count + (n + 1) = count + 1 + n by omega]
76    rw [ih (bytes.set! offset (bytes.getD (offset - dist) 0)) (offset + 1) (count + 1)
77      (by omega) hd (by omega) (by simp only [Array.size_set!]; omega)]
78    rw [copyBack, written_set_append bytes offset count _ hc ho]
79    rw [output_source dict bytes offset count dist hc (by omega) hd hdist]
80
81private theorem window_source (dict : List UInt8) (bytes : Array UInt8)
82    (offset count dist : Nat) (hc : count ≤ offset) (hb : offset ≤ bytes.size)
83    (hd : count < dist) (hbound : dist ≤ dict.length + count) :
84    (dict ++ writtenBytes bytes offset count).getD
85      ((dict ++ writtenBytes bytes offset count).length - dist) 0 =
86        dict.getD (dict.length + count - dist) 0 := by
87  rw [List.length_append, written_length bytes offset count hc hb]
88  have hi : dict.length + count - dist < dict.length := by omega
89  simp only [List.getD_eq_getElem?_getD, List.getElem?_append_left hi]
90
91private theorem window_copy (dict : List UInt8) (window : Array UInt8)
92    (dist : Nat) : ∀ n (bytes : Array UInt8) (offset count sourceOffset : Nat),
93    count ≤ offset → count ≤ dist → dist ≤ dict.length + count →
94    n ≤ dist - count → offset + n ≤ bytes.size → sourceOffset + n ≤ window.size →
95    (∀ i, i < n → window.getD (sourceOffset + i) 0 =
96      dict.getD (dict.length + count - dist + i) 0) →
97    writtenBytes (blitN window n sourceOffset offset bytes) (offset + n) (count + n) =
98      copyBack dict dist n (writtenBytes bytes offset count) := by
99  intro n
100  induction n with
101  | zero => intro bytes offset count sourceOffset _ _ _ _ _ _ _; simp [blitN, copyBack]
102  | succ n ih =>
103    intro bytes offset count sourceOffset hc hd hbound hn hb hw hcells
104    have hlt : count < dist := by omega
105    have ho : offset < bytes.size := by omega
106    rw [blitN]
107    rw [show offset + (n + 1) = offset + 1 + n by omega,
108      show count + (n + 1) = count + 1 + n by omega]
109    rw [ih (bytes.set! offset (window.getD sourceOffset 0)) (offset + 1) (count + 1)
110      (sourceOffset + 1) (by omega) (by omega) (by omega) (by omega)
111      (by simp only [Array.size_set!]; omega) (by omega) ?_]
112    · rw [copyBack, written_set_append bytes offset count _ hc ho]
113      have h0 := hcells 0 (by omega)
114      simp only [Nat.add_zero] at h0
115      rw [window_source dict bytes offset count dist hc (by omega) hlt hbound, h0]
116    · intro i hi
117      have hnext := hcells (i + 1) (by omega)
118      have hp : dict.length + (count + 1) - dist + i =
119          dict.length + count - dist + (i + 1) := by omega
120      simpa only [hp, Nat.add_assoc, Nat.add_comm 1 i] using hnext
121
122/-- A fixed saved-window segment agrees with the same growing-history copy
123until the source reaches the current output. -/
124theorem window_copy_refines_lz77 : Goal.window_copy_refines_lz77 := by
125  intro dict bytes window offset count sourceOffset dist n hc hd hbound hn hb hw hcells
126  exact window_copy dict window dist n bytes offset count sourceOffset hc (by omega) hbound hn hb hw hcells
127
128end ZlibF.Math.LZ77Copy
ZLIB × LEAN

Global contents

READING NOWLZ77Copy.lean