@@ -11,6 +11,8 @@ import all Init.Data.BitVec.BasicAux
1111public import Init.Data.Fin.Lemmas
1212public import Init.Data.List.BasicAux
1313import Init.Data.List.Lemmas
14+ import Init.Data.List.TakeDrop
15+ import Init.Data.List.Nat.TakeDrop
1416public import Init.Data.BitVec.Basic
1517import Init.ByCases
1618import Init.Data.BitVec.Bootstrap
@@ -2934,6 +2936,130 @@ theorem setWidth_append {x : BitVec w} {y : BitVec v} :
29342936 simp only [getElem_xor, getElem_append]
29352937 split <;> simp
29362938
2939+ /-! ## flattenList -/
2940+
2941+ @[simp] theorem getMsbD_flattenList {w : Nat} (vs : List (BitVec w)) (i) :
2942+ (BitVec.flattenList vs).getMsbD i = (vs[i / w]?.getD 0 #w).getMsbD (i % w) := by
2943+ by_cases p : 0 < w
2944+ · match vs with
2945+ | [] => simp
2946+ | x :: rest =>
2947+ simp only [BitVec.flattenList, getMsbD_cast, getMsbD_append]
2948+ split <;> rename_i h
2949+ · obtain ⟨j, rfl⟩ := Nat.exists_eq_add_of_le h
2950+ rw [getMsbD_flattenList]
2951+ simp [p, Nat.add_div_left, Nat.add_sub_cancel_left]
2952+ · have hi0 : i / w = 0 := Nat.div_eq_of_lt (by omega)
2953+ have him : i % w = i := Nat.mod_eq_of_lt (by omega)
2954+ rw [hi0, him]
2955+ simp
2956+ · simp at p
2957+ subst p
2958+ simp
2959+
2960+ @[simp] theorem getLsbD_flattenList {w : Nat} (vs : List (BitVec w)) (i) :
2961+ (BitVec.flattenList vs).getLsbD i =
2962+ (decide (i < w * vs.length) && (vs[vs.length - 1 - i / w]?.getD 0 #w).getLsbD (i % w)) := by
2963+ by_cases p : 0 < w
2964+ · rw [getLsbD_eq_getMsbD, getMsbD_flattenList, getLsbD_eq_getMsbD]
2965+ have h₁ : i % w < w := Nat.mod_lt i p
2966+ simp only [h₁, decide_true, Bool.true_and]
2967+ by_cases h₂ : i < w * vs.length
2968+ · simp only [h₂, decide_true, Bool.true_and]
2969+ congr
2970+ · rw [Nat.sub_sub, Nat.add_comm, Nat.mul_sub_div _ _ _ h₂, Nat.sub_sub, Nat.add_comm]
2971+ · rw [Nat.sub_sub, Nat.add_comm, Nat.mul_sub_mod h₂, Nat.sub_sub, Nat.add_comm]
2972+ · simp only [h₂, decide_false, Bool.false_and]
2973+ · simp_all
2974+
2975+ @[simp] theorem flattenList_zero_length (vs : List (BitVec 0 )) : BitVec.flattenList vs = 0 := by
2976+ apply eq_of_getLsbD_eq
2977+ intro i hi
2978+ simp at hi
2979+
2980+ /--
2981+ Divide-and-conquer worker for `BitVec.flattenList`, returning the underlying
2982+ natural number value with the head of the list in the most significant bits.
2983+
2984+ Splitting the list in half means each bit region is shifted `O(log xs.length)`
2985+ times rather than once per element, so flattening a list of length `L` costs
2986+ `O(n * L * log L)` instead of the `O(n * L²)` of a left fold (which reshifts the
2987+ whole growing accumulator at every step). The recursion depth is `O(log L)`, so
2988+ this also does not overflow the stack.
2989+ -/
2990+ def flattenList.toNatAux {n : Nat} : List (BitVec n) → Nat
2991+ | [] => 0
2992+ | [x] => x.toNat
2993+ | x :: y :: rest =>
2994+ let xs := x :: y :: rest
2995+ let mid := xs.length / 2
2996+ flattenList.toNatAux (xs.take mid) <<< (n * (xs.drop mid).length)
2997+ ||| flattenList.toNatAux (xs.drop mid)
2998+ termination_by l => l.length
2999+ decreasing_by
3000+ all_goals simp only [List.length_take, List.length_drop, List.length_cons]
3001+ all_goals omega
3002+
3003+ /--
3004+ Divide-and-conquer implementation of `BitVec.flattenList`, swapped in at runtime
3005+ via `@[csimp]`. See `BitVec.flattenList.toNatAux` for the cost analysis.
3006+ -/
3007+ def flattenListFast {n : Nat} (xs : List (BitVec n)) : BitVec (n * xs.length) :=
3008+ .ofNat (n * xs.length) (BitVec.flattenList.toNatAux xs)
3009+
3010+ theorem toNat_flattenList_append {n : Nat} (l r : List (BitVec n)) :
3011+ (BitVec.flattenList (l ++ r)).toNat
3012+ = (BitVec.flattenList l).toNat <<< (n * r.length) ||| (BitVec.flattenList r).toNat := by
3013+ induction l with
3014+ | nil => simp [BitVec.flattenList]
3015+ | cons x l ih =>
3016+ rw [List.cons_append]
3017+ simp only [BitVec.flattenList, toNat_cast, toNat_append, ih, List.length_append, Nat.mul_add]
3018+ rw [Nat.shiftLeft_or_distrib, ← Nat.shiftLeft_add, Nat.or_assoc]
3019+
3020+ theorem flattenList.toNatAux_eq {n : Nat} (xs : List (BitVec n)) :
3021+ BitVec.flattenList.toNatAux xs = (BitVec.flattenList xs).toNat := by
3022+ induction xs using BitVec.flattenList.toNatAux.induct with
3023+ | case1 => simp [BitVec.flattenList.toNatAux, BitVec.flattenList]
3024+ | case2 x => simp [BitVec.flattenList.toNatAux, BitVec.flattenList]
3025+ | case3 x y rest xs mid ih1 ih2 =>
3026+ rw [BitVec.flattenList.toNatAux, ih1, ih2, ← toNat_flattenList_append, List.take_append_drop]
3027+
3028+ @[csimp] theorem flattenList_eq_flattenListFast :
3029+ @BitVec.flattenList = @BitVec.flattenListFast := by
3030+ funext n xs
3031+ rw [BitVec.flattenListFast, BitVec.flattenList.toNatAux_eq, ofNat_toNat, setWidth_eq]
3032+
3033+ /-! ## extractLsb -/
3034+
3035+ /--
3036+ Extracting a bitvector from `flattenList`, when we only extract from a single bitvector.
3037+ -/
3038+ theorem extractLsb_flattenList (hi lo : Nat) {w : Nat} (vs : List (BitVec w))
3039+ (w₁ : lo ≤ hi) (w₂ : hi < w * vs.length) (h : hi / w = lo / w) :
3040+ extractLsb hi lo (BitVec.flattenList vs) =
3041+ BitVec.cast (by simp [Nat.mod_eq_sub_mul_div, h]; have := Nat.mul_div_le lo w; omega)
3042+ (extractLsb (hi % w) (lo % w) (vs[vs.length - 1 - hi / w]?.getD 0 #w)) := by
3043+ by_cases p : 0 < w
3044+ · have t : w * (lo / w) ≤ lo := Nat.mul_div_le lo w
3045+ have t' : hi < w * (lo / w) + w := by rw [← h]; apply Nat.lt_mul_div_self_add p
3046+ apply eq_of_getLsbD_eq
3047+ intro i hi_lt
3048+ have q : i < hi - lo + 1 := hi_lt
3049+ have q' : i < hi % w - lo % w + 1 := by simp [Nat.mod_eq_sub_mul_div, h]; omega
3050+ have q'' : lo + i < w * vs.length := by omega
3051+ have h₁ : (lo + i) / w = lo / w := by
3052+ apply Nat.div_eq_of_lt_le <;> rw [Nat.mul_comm]
3053+ · omega
3054+ · simp only [Nat.mul_add]; omega
3055+ have h₂ : (lo + i) % w = lo % w + i := by simp [Nat.mod_eq_sub_mul_div, h₁]; omega
3056+ simp only [getLsbD_extractLsb, getLsbD_flattenList, q, q', q'', h₁, h₂, h, getLsbD_cast,
3057+ decide_true, Bool.true_and]
3058+ · simp at p
3059+ subst p
3060+ omega
3061+
3062+ /-! ### rev -/
29373063theorem shiftRight_add {w : Nat} (x : BitVec w) (n m : Nat) :
29383064 x >>> (n + m) = (x >>> n) >>> m:= by
29393065 ext i
0 commit comments