Skip to content
REFERENCE / ZLIB × LEAN

trees.c.tally.lean

Source snapshot · b71fdf4ef40380fd · 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.Proof.«trees.c.align»
2
3/-!
4# trees.c: `_tr_tally`
5-/
6
7namespace Zlib.Trees.Proofs.Out
8open C Zlib.Trees
9
10/-- One `s->sym_buf[s->sym_next++] = v` of `_tr_tally`. -/
11theorem sym_put_run {h : Heap} {id : Nat} {d : DeflateState} {b : Nat} {buf : Array UInt8}
12    (hb : TreesBase h id d b buf) (hlt : d.lit_bufsize.toNat + d.sym_next.toNat < buf.size) (v : UInt8)
13    (hsn : d.sym_next.toNat < 2 ^ 31) :
14    (do let d ← rd (some (.tab id))
15        setAt d.sym_buf d.sym_next.toNat v
16        md (some (.tab id)) fun d => { d with sym_next := d.sym_next + 1 } : M Unit) h =
17      .ok ((), setD (setB h b (buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) v)) id
18        { d with sym_next := d.sym_next + 1 }) := by
19  have hg : Space.get h (BRef.blk b) = some buf := hb.bytes
20  have e1 := Ptr.add_nat_ok (off := d.lit_bufsize.toNat) (n := d.sym_next.toNat) hg (by omega)
21  have e2 := Ptr.store_ok (v := v) (off := d.lit_bufsize.toNat + d.sym_next.toNat) hg hb.rw hlt
22  unfold OkOn at e1
23  unfold setAt
24  rw [bind_app, rd_run hb.dstate]
25  simp only [hb.sym]
26  rw [bind_app, bind_app, e1]
27  simp only []
28  rw [e2]
29  simp only []
30  have hd : (Space.put h (BRef.blk b) (buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) v)).dstates id = some d :=
31    hb.dstate
32  rw [md_run hd]
33  simp [setD, Space.put, setB]
34  rw [hb.sym]
35
36
37theorem length_code_le (i : Nat) (hi : i < 256) : (length_code_tab[i]'(by rw [length_code_tab_size]; exact hi)).toNat ≤ 28 := by
38  have : ∀ j : Fin 256, (length_code_tab[j.val]'(by rw [length_code_tab_size]; exact j.isLt)).toNat ≤ 28 := by
39    decide +kernel
40  exact this ⟨i, hi⟩
41
42theorem dist_code_le (i : Nat) (hi : i < 512) : (dist_code_tab[i]'(by rw [dist_code_tab_size]; exact hi)).toNat ≤ 29 := by
43  have : ∀ j : Fin 512, (dist_code_tab[j.val]'(by rw [dist_code_tab_size]; exact j.isLt)).toNat ≤ 29 := by
44    decide +kernel
45  exact this ⟨i, hi⟩
46
47theorem arr_get_bang (a : Array UInt8) (i : Nat) (hi : i < a.size) : a[i]! = a[i] := getElem!_pos a i hi
48
49/-- `d_code(dist)` as a number (`dist` here is `dist - 1` of the symbol). -/
50def dcodeN (d : Nat) : Nat := if d < 256 then (dist_code_tab[d]!).toNat else (dist_code_tab[256 + d / 128]!).toNat
51
52/-- `d_code` reads `_dist_code` inside its bounds for `dist < 32768`; the code is at most 29. -/
53theorem d_code_run {h : Heap} (hs : TreesStatic h.static) (dist : UInt32) (hd : dist.toNat < 32768) :
54    ∃ c : UInt8, d_code dist h = .ok (c, h) ∧ c.toNat = dcodeN dist.toNat ∧ c.toNat ≤ 29 := by
55  have hg : Space.get h BRef.st_dist_code = some dist_code_tab := by simp [Space.get, hs.dist_code]
56  unfold d_code
57  by_cases h1 : dist < 256
58  · have h2 : dist.toNat < 256 := by simpa [UInt32.lt_iff_toNat_lt] using h1
59    have hi : dist.toNat < dist_code_tab.size := by rw [dist_code_tab_size]; omega
60    have e := Ptr.index_ok (off := 0) (i := dist.toNat) hg (by omega)
61    unfold OkOn at e
62    simp only [h1, ite_true]
63    refine ⟨_, e, ?_, ?_⟩
64    · have := arr_get_bang dist_code_tab dist.toNat hi
65      simp only [dcodeN, h2, ite_true, Nat.zero_add]
66      exact congrArg UInt8.toNat this.symm
67    · exact dist_code_le _ (by omega)
68  · have h2 : ¬ dist.toNat < 256 := by simpa [UInt32.lt_iff_toNat_lt] using h1
69    have hsh : (dist >>> 7).toNat = dist.toNat / 128 := by
70      rw [UInt32.toNat_shiftRight]; simp [Nat.shiftRight_eq_div_pow]
71    have hidx : ((256 : UInt32) + (dist >>> 7)).toNat = 256 + dist.toNat / 128 := by
72      rw [UInt32.toNat_add, hsh]; simp; omega
73    have hi : 256 + dist.toNat / 128 < dist_code_tab.size := by rw [dist_code_tab_size]; omega
74    have e := Ptr.index_ok (off := 0) (i := 256 + dist.toNat / 128) hg (by omega)
75    unfold OkOn at e
76    simp only [h1, ite_false]
77    refine ⟨_, by rw [hidx, e], ?_, ?_⟩
78    · have := arr_get_bang dist_code_tab (256 + dist.toNat / 128) hi
79      simp only [dcodeN, h2, ite_false, Nat.zero_add]
80      exact congrArg UInt8.toNat this.symm
81    · exact dist_code_le _ (by omega)
82
83
84theorem toNat_add_one_u32 {x : UInt32} (hx : x.toNat + 1 < 2 ^ 32) : (x + 1).toNat = x.toNat + 1 := by
85  rw [UInt32.toNat_add]; have : (1 : UInt32).toNat = 1 := by decide
86  rw [this]; omega
87
88/-- The three stores of `_tr_tally` into the symbol buffer. -/
89theorem tally_puts {h : Heap} {id : Nat} {d : DeflateState} {b : Nat} {buf : Array UInt8}
90    (hb : TreesBase h id d b buf) (hroom : d.sym_next.toNat + 3 ≤ d.sym_end.toNat) (dist lc : UInt32)
91    (rest : Unit → M Int32) :
92    ((do
93          let d ← rd (some (DeflateStateRef.tab id))
94          setAt d.sym_buf (↑d.sym_next.toNat) dist.toUInt8
95          md (some (DeflateStateRef.tab id)) fun d => { d with sym_next := d.sym_next + 1 } : M Unit) >>= fun _ =>
96      ((do
97          let d ← rd (some (DeflateStateRef.tab id))
98          setAt d.sym_buf (↑d.sym_next.toNat) (dist >>> 8).toUInt8
99          md (some (DeflateStateRef.tab id)) fun d => { d with sym_next := d.sym_next + 1 } : M Unit) >>= fun _ =>
100      ((do
101          let d ← rd (some (DeflateStateRef.tab id))
102          setAt d.sym_buf (↑d.sym_next.toNat) lc.toUInt8
103          md (some (DeflateStateRef.tab id)) fun d => { d with sym_next := d.sym_next + 1 } : M Unit) >>= rest))) h =
104    rest () (setD (setB h b (((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
105        (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8).set!
106        (d.lit_bufsize.toNat + (d.sym_next.toNat + 2)) lc.toUInt8)) id { d with sym_next := d.sym_next + 1 + 1 + 1 }) := by
107  have hl := hb.lit_hi
108  have hse := hb.sym_end
109  have hs1 := hb.size
110  have hsn1 : (d.sym_next + 1).toNat = d.sym_next.toNat + 1 := toNat_add_one_u32 (by omega)
111  have hb1 := hb.step (buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8) (by simp)
112    { d with sym_next := d.sym_next + 1 } hb.wf rfl rfl rfl rfl rfl hb.pending_le
113  have hsn2 : (d.sym_next + 1 + 1).toNat = d.sym_next.toNat + 2 := by rw [toNat_add_one_u32 (by omega), hsn1]
114  have hb2 : TreesBase (setD (setB h b ((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
115      (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8)) id { d with sym_next := d.sym_next + 1 + 1 })
116      id { d with sym_next := d.sym_next + 1 + 1 } b ((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
117      (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8) := by
118    simpa only [setB_setD, setD_setD, setB_setB] using hb1.step ((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
119      (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8) (by simp)
120      { d with sym_next := d.sym_next + 1 + 1 } hb.wf rfl rfl rfl rfl rfl hb.pending_le
121  rw [bind_app, sym_put_run hb (by omega) _ (by omega)]
122  simp only []
123  rw [bind_app, sym_put_run hb1 (by simp only [Array.size_set!]; rw [hsn1]; omega) _ (by simp only []; rw [hsn1]; omega)]
124  simp only [hsn1, Nat.add_assoc, setB_setD, setD_setD, setB_setB]
125  rw [bind_app, sym_put_run hb2 (by simp only [Array.size_set!]; rw [hsn2]; omega) _ (by simp only []; rw [hsn2]; omega)]
126  simp only [hsn2, Nat.add_assoc, setB_setD, setD_setD, setB_setB]
127
128
129/-- The array with `Freq` of entry `i` incremented (`tree[i].Freq++`, modulo 2^16). -/
130def bumpFc (a : Array CtData) (i : Nat) : Array CtData := a.set! i { (a[i]!) with fc := (a[i]!).fc + 1 }
131
132/-- The part of `_tr_tally` after the three stores into the symbol buffer. -/
133def tallyTail (s : DeflateStatePtr) (dist lc : UInt32) : M Int32 := do
134  if dist == 0 then
135    let lt ← pLtree s
136    setFc lt lc.toNat ((← getFc lt lc.toNat) + 1)
137  else
138    md s fun d => { d with «matches» := d.«matches» + 1 }
139    let dist := dist - 1
140    let lcode ← Ptr.index (.ref .st_length_code 0 : BPtr) lc.toNat
141    let idx := (u8i lcode).toInt + LITERALS.toInt + 1
142    let lt ← pLtree s
143    setFc lt idx ((← getFc lt idx) + 1)
144    let dc ← d_code dist
145    let dt ← pDtree s
146    setFc dt dc.toNat ((← getFc dt dc.toNat) + 1)
147  let d ← rd s
148  return (if d.sym_next == d.sym_end then 1 else 0)
149
150theorem tally_split (s : DeflateStatePtr) (dist lc : UInt32) :
151    «_tr_tally» s dist lc = ((do
152          let d ← rd s
153          setAt d.sym_buf (↑d.sym_next.toNat) dist.toUInt8
154          md s fun d => { d with sym_next := d.sym_next + 1 } : M Unit) >>= fun _ =>
155      ((do
156          let d ← rd s
157          setAt d.sym_buf (↑d.sym_next.toNat) (dist >>> 8).toUInt8
158          md s fun d => { d with sym_next := d.sym_next + 1 } : M Unit) >>= fun _ =>
159      ((do
160          let d ← rd s
161          setAt d.sym_buf (↑d.sym_next.toNat) lc.toUInt8
162          md s fun d => { d with sym_next := d.sym_next + 1 } : M Unit) >>= fun _ => tallyTail s dist lc))) := rfl
163
164theorem tallyTail_lit {H : Heap} {id : Nat} {D : DeflateState} (hd : H.dstates id = some D) (dist lc : UInt32)
165    (hdist : dist = 0) (hlc : lc.toNat < D.dyn_ltree.size) :
166    tallyTail (some (.tab id)) dist lc H =
167      .ok ((if D.sym_next == D.sym_end then 1 else 0),
168        setD H id { D with dyn_ltree := bumpFc D.dyn_ltree lc.toNat }) := by
169  subst hdist
170  have hg : getFc (.ref (Sel.l.ref id) 0) ((lc.toNat : Nat) : Int) H = .ok ((D.dyn_ltree[lc.toNat]!).fc, H) :=
171    getFc_sel hd .l hlc
172  have hs := setFc_sel hd .l (i := lc.toNat) hlc ((D.dyn_ltree[lc.toNat]!).fc + 1)
173  unfold tallyTail
174  simp only [beq_self_eq_true, ite_true]
175  rw [bind_app, pLtree_run hd]
176  simp only []
177  rw [bind_app]
178  have hg' : getFc (.ref (CtDataRef.dstate_dyn_ltree id) 0) ((lc.toNat : Nat) : Int) H = _ := hg
179  rw [hg']
180  simp only []
181  have hs' : setFc (.ref (CtDataRef.dstate_dyn_ltree id) 0) ((lc.toNat : Nat) : Int) ((D.dyn_ltree[lc.toNat]!).fc + 1) H = _ := hs
182  rw [bind_app, hs']
183  simp only []
184  simp (disch := simp [hd]) only [bind_app, rd_run', rdD_setD_same, pure_app]
185  simp only [Sel.upd, Sel.arr, bumpFc]
186  rfl
187
188
189theorem LITERALS_toInt : LITERALS.toInt = 256 := by decide
190
191theorem u8i_toInt (x : UInt8) : (u8i x).toInt = x.toNat := by
192  unfold u8i
193  have := x.toNat_lt
194  exact i32_ofInt_toInt (by omega) (by omega)
195
196/-- The record after the counting part of a match symbol. -/
197def tallyMatchRec (D : DeflateState) (dist lc : UInt32) : DeflateState :=
198  { D with «matches» := D.«matches» + 1, dyn_ltree := bumpFc D.dyn_ltree ((length_code_tab[lc.toNat]!).toNat + 257), dyn_dtree := bumpFc D.dyn_dtree (dcodeN (dist.toNat - 1)) }
199
200theorem idx_cast (x : UInt8) : (u8i x).toInt + LITERALS.toInt + 1 = (((x.toNat + 257 : Nat)) : Int) := by
201  rw [u8i_toInt, LITERALS_toInt]; omega
202
203theorem tallyTail_match {H : Heap} {id : Nat} {D : DeflateState} (hd : H.dstates id = some D)
204    (hs : TreesStatic H.static) (hwf : D.WellFormed) (dist lc : UInt32)
205    (hdist : (dist == 0) = false) (hlc : lc.toNat < 256) (hd32 : dist.toNat ≤ 32768) :
206    tallyTail (some (.tab id)) dist lc H =
207      .ok ((if D.sym_next == D.sym_end then 1 else 0), setD H id (tallyMatchRec D dist lc)) := by
208  obtain ⟨w1, w2, w3, w4, w5, w6⟩ := hwf
209  have hd0 : dist ≠ 0 := by
210    intro h0; subst h0; simp at hdist
211  have hd1 : (dist - 1).toNat = dist.toNat - 1 := by
212    have : 1 ≤ dist.toNat := by
213      rcases Nat.eq_zero_or_pos dist.toNat with h0 | h0
214      · exact absurd (UInt32.toNat_inj.mp (by simpa using h0)) hd0
215      · exact h0
216    rw [UInt32.toNat_sub_of_le _ _ (by simp [UInt32.le_iff_toNat_le]; omega)]
217    simp
218  have hsL : (setD H id { D with «matches» := D.«matches» + 1 }).dstates id = some { D with «matches» := D.«matches» + 1 } :=
219    setD_dstates_same _ _ _
220  have hsS : TreesStatic (setD H id { D with «matches» := D.«matches» + 1 }).static := by simpa using hs
221  have hlg : Space.get (setD H id { D with «matches» := D.«matches» + 1 }) BRef.st_length_code = some length_code_tab := by
222    simp [Space.get, hs.length_code]
223  have hil : lc.toNat < length_code_tab.size := by rw [length_code_tab_size]; omega
224  have eL := Ptr.index_ok (off := 0) (i := lc.toNat) hlg (by omega)
225  unfold OkOn at eL
226  have eL' : Ptr.index (.ref .st_length_code 0 : BPtr) (lc.toNat : Int) (setD H id { D with «matches» := D.«matches» + 1 })
227      = .ok (length_code_tab[lc.toNat]!, setD H id { D with «matches» := D.«matches» + 1 }) := by
228    rw [eL]; simp only [Nat.zero_add]; rw [arr_get_bang length_code_tab lc.toNat hil]
229  have hlc28 : (length_code_tab[lc.toNat]!).toNat ≤ 28 := by
230    rw [arr_get_bang length_code_tab lc.toNat hil]; exact length_code_le _ hlc
231  unfold tallyTail
232  simp only [hdist, Bool.false_eq_true, ite_false]
233  rw [bind_app, md_run hd]
234  simp only []
235  rw [bind_app, eL']
236  simp only []
237  have hD1w : ({ D with «matches» := D.«matches» + 1 } : DeflateState).dyn_ltree.size = 573 := w1
238  have hD1w2 : ({ D with «matches» := D.«matches» + 1 } : DeflateState).dyn_dtree.size = 61 := w2
239  generalize hD1 : ({ D with «matches» := D.«matches» + 1 } : DeflateState) = D1 at *
240  rw [bind_app, pLtree_run hsL]
241  simp only [idx_cast]
242  have hi1 : (length_code_tab[lc.toNat]!).toNat + 257 < (Sel.l.arr D1).size := by
243    show _ < D1.dyn_ltree.size; omega
244  rw [bind_app]
245  have g1 : getFc (.ref (CtDataRef.dstate_dyn_ltree id) 0) ((((length_code_tab[lc.toNat]!).toNat + 257 : Nat)) : Int)
246      (setD H id D1) = _ := getFc_sel hsL .l hi1
247  rw [g1]
248  simp only []
249  have s1 : setFc (.ref (CtDataRef.dstate_dyn_ltree id) 0) ((((length_code_tab[lc.toNat]!).toNat + 257 : Nat)) : Int)
250      ((Sel.l.arr D1)[(length_code_tab[lc.toNat]!).toNat + 257]!.fc + 1) (setD H id D1) = _ :=
251    setFc_sel hsL .l hi1 _
252  rw [bind_app, s1]
253  simp only [setD_setD]
254  have hsz2 : (Sel.l.upd D1 ((Sel.l.arr D1).set! ((length_code_tab[lc.toNat]!).toNat + 257)
255      { (Sel.l.arr D1)[(length_code_tab[lc.toNat]!).toNat + 257]! with fc := (Sel.l.arr D1)[(length_code_tab[lc.toNat]!).toNat + 257]!.fc + 1 })).dyn_dtree.size = 61 := hD1w2
256  generalize hD2 : Sel.l.upd D1 ((Sel.l.arr D1).set! ((length_code_tab[lc.toNat]!).toNat + 257)
257      { (Sel.l.arr D1)[(length_code_tab[lc.toNat]!).toNat + 257]! with fc := (Sel.l.arr D1)[(length_code_tab[lc.toNat]!).toNat + 257]!.fc + 1 }) = D2 at *
258  have hsD : (setD H id D2).dstates id = some D2 := setD_dstates_same _ _ _
259  obtain ⟨c, hcr, hcn, hc29⟩ := d_code_run (h := setD H id D2) (by simpa using hs) (dist - 1) (by omega)
260  rw [bind_app, hcr]
261  simp only []
262  rw [bind_app, pDtree_run hsD]
263  simp only []
264  have hi2 : c.toNat < (Sel.d.arr D2).size := by show _ < D2.dyn_dtree.size; omega
265  have g2 : getFc (.ref (CtDataRef.dstate_dyn_dtree id) 0) ((c.toNat : Nat) : Int) (setD H id D2) = _ := getFc_sel hsD .d hi2
266  rw [bind_app, g2]
267  simp only []
268  have s2 : setFc (.ref (CtDataRef.dstate_dyn_dtree id) 0) ((c.toNat : Nat) : Int)
269      ((Sel.d.arr D2)[c.toNat]!.fc + 1) (setD H id D2) = _ := setFc_sel hsD .d hi2 _
270  rw [bind_app, s2]
271  simp only [setD_setD]
272  simp (disch := simp) only [bind_app, rd_run', rdD_setD_same, pure_app]
273  rw [hcn, hd1]
274  subst hD2
275  subst hD1
276  unfold tallyMatchRec bumpFc
277  simp only [Sel.upd, Sel.arr]
278  rfl
279
280
281@[simp] theorem bumpFc_size (a : Array CtData) (i : Nat) : (bumpFc a i).size = a.size := by
282  simp [bumpFc]
283
284/-- The record after `_tr_tally`. -/
285def tallyRec (d : DeflateState) (dist lc : UInt32) : DeflateState :=
286  if dist = 0 then { d with sym_next := d.sym_next + 1 + 1 + 1, dyn_ltree := bumpFc d.dyn_ltree lc.toNat }
287  else tallyMatchRec { d with sym_next := d.sym_next + 1 + 1 + 1 } dist lc
288
289theorem tallyRec_wf {d : DeflateState} (hw : d.WellFormed) (dist lc : UInt32) : (tallyRec d dist lc).WellFormed := by
290  obtain ⟨w1, w2, w3, w4, w5, w6⟩ := hw
291  unfold tallyRec tallyMatchRec
292  split <;> exact ⟨by simpa using w1, by simpa using w2, w3, w4, w5, w6⟩
293
294theorem tallyRec_fields (d : DeflateState) (dist lc : UInt32) :
295    (tallyRec d dist lc).pending_buf = d.pending_buf ∧ (tallyRec d dist lc).pending_buf_size = d.pending_buf_size ∧
296    (tallyRec d dist lc).sym_buf = d.sym_buf ∧ (tallyRec d dist lc).lit_bufsize = d.lit_bufsize ∧
297    (tallyRec d dist lc).sym_end = d.sym_end ∧ (tallyRec d dist lc).pending = d.pending := by
298  unfold tallyRec tallyMatchRec
299  split <;> exact ⟨rfl, rfl, rfl, rfl, rfl, rfl⟩
300
301theorem tallyRec_run {id : Nat} {d : DeflateState} (hr : TreesRun id d) (hroom : d.sym_next.toNat + 3 ≤ d.sym_end.toNat)
302    (hm : d.sym_next.toNat % 3 = 0) (hsn : d.sym_next.toNat + 3 < 2 ^ 32) (dist lc : UInt32) :
303    TreesRun id (tallyRec d dist lc) := by
304  have e : (d.sym_next + 1 + 1 + 1).toNat = d.sym_next.toNat + 3 := by
305    have e1 : (d.sym_next + 1).toNat = d.sym_next.toNat + 1 := toNat_add_one_u32 (by omega)
306    have e2 : (d.sym_next + 1 + 1).toNat = d.sym_next.toNat + 2 := by
307      rw [toNat_add_one_u32 (by rw [e1]; omega), e1]
308    rw [toNat_add_one_u32 (by rw [e2]; omega), e2]
309  unfold tallyRec tallyMatchRec
310  split
311  · exact ⟨hr.ldyn, hr.lstat, hr.ddyn, hr.dstat, hr.bldyn, hr.blstat, hr.bi_lo, hr.bi_hi, hr.bi_buf,
312      by show (d.sym_next + 1 + 1 + 1).toNat ≤ d.sym_end.toNat; omega,
313      by show (d.sym_next + 1 + 1 + 1).toNat % 3 = 0; omega⟩
314  · exact ⟨hr.ldyn, hr.lstat, hr.ddyn, hr.dstat, hr.bldyn, hr.blstat, hr.bi_lo, hr.bi_hi, hr.bi_buf,
315      by show (d.sym_next + 1 + 1 + 1).toNat ≤ d.sym_end.toNat; omega,
316      by show (d.sym_next + 1 + 1 + 1).toNat % 3 = 0; omega⟩
317
318
319/-- **`_tr_tally`, safety and specification.** `_tr_tally(s, dist, lc)` stores the symbol `(dist, lc)` as 3 bytes at
320`sym_buf[sym_next ..]` (`dist` little-endian, then `lc`), counts it in `dyn_ltree` (a literal: `dyn_ltree[lc].Freq++`;
321a match: `matches++`, `dyn_ltree[_length_code[lc] + 257].Freq++`, `dyn_dtree[d_code(dist - 1)].Freq++`) and returns
322whether the symbol buffer is now full (`sym_next == sym_end`), which is when `deflate.c` flushes the block.
323Preconditions: `TreesInvAt`; `sym_next + 3 <= sym_end` (deflate.c flushes the block as soon as `sym_next == sym_end`,
324so a tally always starts below it); a literal has `lc < 256` (`lc` is a byte); a match has `lc < 256` (length minus
325`MIN_MATCH`, at most 255) and `1 <= dist <= 32768` (`MAX_DIST` is at most 32506). Nothing else of the record changes;
326the byte block changes only at the three symbol bytes. -/
327theorem tr_tally_spec {h : Heap} {id : Nat} {d : DeflateState} {b : Nat} {buf : Array UInt8}
328    (hI : TreesInvAt h id d b buf) (dist lc : UInt32)
329    (hroom : d.sym_next.toNat + 3 ≤ d.sym_end.toNat)
330    (hlit : dist = 0 → lc.toNat < 256) (hmatch : dist ≠ 0 → lc.toNat < 256 ∧ dist.toNat ≤ 32768) :
331    ∃ buf' r, «_tr_tally» (some (.tab id)) dist lc h = .ok (r, setD (setB h b buf') id (tallyRec d dist lc)) ∧
332      TreesInvAt (setD (setB h b buf') id (tallyRec d dist lc)) id (tallyRec d dist lc) b buf' ∧
333      r = (if d.sym_next + 1 + 1 + 1 == d.sym_end then 1 else 0) ∧
334      buf'.size = buf.size ∧
335      buf'.getD (d.lit_bufsize.toNat + d.sym_next.toNat) 0 = dist.toUInt8 ∧
336      buf'.getD (d.lit_bufsize.toNat + d.sym_next.toNat + 1) 0 = (dist >>> 8).toUInt8 ∧
337      buf'.getD (d.lit_bufsize.toNat + d.sym_next.toNat + 2) 0 = lc.toUInt8 ∧
338      (∀ i, (i < d.lit_bufsize.toNat + d.sym_next.toNat ∨ d.lit_bufsize.toNat + d.sym_next.toNat + 3 ≤ i) →
339        buf'.getD i 0 = buf.getD i 0) := by
340  obtain ⟨hb, hr⟩ := hI
341  have hl := hb.lit_hi
342  have hse := hb.sym_end
343  have hs1 := hb.size
344  have hm := hr.sym_next_mod
345  have hsn : d.sym_next.toNat + 3 < 2 ^ 32 := by omega
346  have e1 : (d.sym_next + 1).toNat = d.sym_next.toNat + 1 := toNat_add_one_u32 (by omega)
347  have e2 : (d.sym_next + 1 + 1).toNat = d.sym_next.toNat + 2 := by
348    rw [toNat_add_one_u32 (by rw [e1]; omega), e1]
349  have e3 : (d.sym_next + 1 + 1 + 1).toNat = d.sym_next.toNat + 3 := by
350    rw [toNat_add_one_u32 (by rw [e2]; omega), e2]
351  set_option maxRecDepth 4000 in
352  have hbuf3 : ((((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
353        (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8).set!
354        (d.lit_bufsize.toNat + (d.sym_next.toNat + 2)) lc.toUInt8)).size = buf.size := by simp
355  have hb3 : TreesBase (setD (setB h b ((((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
356        (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8).set!
357        (d.lit_bufsize.toNat + (d.sym_next.toNat + 2)) lc.toUInt8))) id { d with sym_next := d.sym_next + 1 + 1 + 1 })
358      id { d with sym_next := d.sym_next + 1 + 1 + 1 } b ((((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
359        (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8).set!
360        (d.lit_bufsize.toNat + (d.sym_next.toNat + 2)) lc.toUInt8)) :=
361    hb.step _ hbuf3 _ hb.wf rfl rfl rfl rfl rfl hb.pending_le
362  have hd3 := setD_dstates_same (setB h b ((((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
363        (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8).set!
364        (d.lit_bufsize.toNat + (d.sym_next.toNat + 2)) lc.toUInt8))) id { d with sym_next := d.sym_next + 1 + 1 + 1 }
365  have hrun : «_tr_tally» (some (.tab id)) dist lc h =
366      .ok ((if d.sym_next + 1 + 1 + 1 == d.sym_end then 1 else 0),
367        setD (setB h b ((((buf.set! (d.lit_bufsize.toNat + d.sym_next.toNat) dist.toUInt8).set!
368        (d.lit_bufsize.toNat + (d.sym_next.toNat + 1)) (dist >>> 8).toUInt8).set!
369        (d.lit_bufsize.toNat + (d.sym_next.toNat + 2)) lc.toUInt8))) id (tallyRec d dist lc)) := by
370    rw [tally_split, tally_puts hb hroom dist lc (fun _ => tallyTail (some (.tab id)) dist lc)]
371    by_cases hz : dist = 0
372    · have hlc := hlit hz
373      have hlt : lc.toNat < ({ d with sym_next := d.sym_next + 1 + 1 + 1 } : DeflateState).dyn_ltree.size := by
374        show lc.toNat < d.dyn_ltree.size
375        have := hb.wf.1; omega
376      rw [tallyTail_lit hd3 dist lc hz hlt]
377      simp only [tallyRec, hz, ite_true, setD_setD]
378    · obtain ⟨hlc, hdd⟩ := hmatch hz
379      have hdz : (dist == 0) = false := by simpa using hz
380      rw [tallyTail_match hd3 (by simpa using hb.static) hb.wf dist lc hdz hlc hdd]
381      simp only [tallyRec, hz, ite_false, setD_setD]
382  refine ⟨_, _, hrun, ?_, rfl, hbuf3, ?_, ?_, ?_, ?_⟩
383  · obtain ⟨f1, f2, f3, f4, f5, f6⟩ := tallyRec_fields d dist lc
384    exact ⟨hb.step _ hbuf3 _ (tallyRec_wf hb.wf dist lc) f1 f2 f3 f4 f5 (by rw [f6, f2]; exact hb.pending_le),
385      tallyRec_run hr hroom hm hsn dist lc⟩
386  · rw [getD_set_u8, getD_set_u8, getD_set_u8]
387    have n1 : ¬ (d.lit_bufsize.toNat + (d.sym_next.toNat + 2) = d.lit_bufsize.toNat + d.sym_next.toNat) := by omega
388    have n2 : ¬ (d.lit_bufsize.toNat + (d.sym_next.toNat + 1) = d.lit_bufsize.toNat + d.sym_next.toNat) := by omega
389    have n3 : d.lit_bufsize.toNat + d.sym_next.toNat < buf.size := by omega
390    simp [n1, n2, n3]
391  · rw [getD_set_u8, getD_set_u8, getD_set_u8]
392    have n1 : ¬ (d.lit_bufsize.toNat + (d.sym_next.toNat + 2) = d.lit_bufsize.toNat + d.sym_next.toNat + 1) := by omega
393    have n3 : d.lit_bufsize.toNat + (d.sym_next.toNat + 1) < buf.size := by omega
394    simp [n1, n3, Nat.add_assoc]
395  · rw [getD_set_u8, getD_set_u8, getD_set_u8]
396    have n3 : d.lit_bufsize.toNat + (d.sym_next.toNat + 2) < buf.size := by omega
397    simp [n3, Nat.add_assoc]
398  · intro i hi
399    have n1 : ¬ (d.lit_bufsize.toNat + (d.sym_next.toNat + 2) = i) := by omega
400    have n2 : ¬ (d.lit_bufsize.toNat + (d.sym_next.toNat + 1) = i) := by omega
401    have n3 : ¬ (d.lit_bufsize.toNat + d.sym_next.toNat = i) := by omega
402    rw [getD_set_u8, getD_set_u8, getD_set_u8]
403    simp [n1, n2, n3]
404
405end Zlib.Trees.Proofs.Out
ZLIB × LEAN

Global contents

READING NOWtrees.c.tally.lean