This PR sets up the new integrated test/bench suite. It then migrates all benchmarks and some related tests to the new suite. There's also some documentation and some linting. For now, a lot of the old tests are left alone so this PR doesn't become even larger than it already is. Eventually, all tests should be migrated to the new suite though so there isn't a confusing mix of two systems.
508 lines
13 KiB
Text
508 lines
13 KiB
Text
set_option autoImplicit false -- For compatibility with downstream projects, so we can retest after Mathlib.
|
||
set_option relaxedAutoImplicit false
|
||
|
||
open List
|
||
|
||
variable {α : Type _}
|
||
variable {x y z : α}
|
||
variable (l l₁ l₂ l₃ : List α)
|
||
|
||
variable (L₁ L₂ : List (List α))
|
||
|
||
variable {β : Type _}
|
||
variable {f g : α → β}
|
||
|
||
variable {γ : Type _}
|
||
variable {f' : β → γ}
|
||
|
||
variable (m n : Nat)
|
||
|
||
/-! ## Preliminaries -/
|
||
|
||
/-! ### cons -/
|
||
|
||
/-! ### length -/
|
||
|
||
/-! ### L[i] and L[i]? -/
|
||
|
||
/-! ### mem -/
|
||
|
||
/-! ### set -/
|
||
|
||
/-! ### foldlM and foldrM -/
|
||
|
||
/-! ### foldl and foldr -/
|
||
|
||
/-! ### Equality -/
|
||
|
||
/-! ### Lexicographic order -/
|
||
|
||
/-! ## Getters -/
|
||
|
||
#check_simp [x, y, x, y][0] ~> x
|
||
#check_simp [x, y, x, y][1] ~> y
|
||
#check_simp [x, y, x, y][2] ~> x
|
||
#check_simp [x, y, x, y][3] ~> y
|
||
|
||
#check_simp [x, y, x, y][0]? ~> some x
|
||
#check_simp [x, y, x, y][1]? ~> some y
|
||
#check_simp [x, y, x, y][2]? ~> some x
|
||
#check_simp [x, y, x, y][3]? ~> some y
|
||
|
||
/-! ### get, get!, get?, getD -/
|
||
|
||
/-! ### getLast, getLast!, getLast?, getLastD -/
|
||
|
||
/-! ## Head and tail -/
|
||
|
||
/-! ### head, head!, head?, headD -/
|
||
|
||
#check_simp l.headD x ~> l.head?.getD x
|
||
|
||
#check_simp l.head? = none ~> l = []
|
||
|
||
/-! ### tail!, tail?, tailD -/
|
||
|
||
/-! ## Basic operations -/
|
||
|
||
/-! ### map -/
|
||
|
||
#check_simp l.map id ~> l
|
||
#check_simp l.map (fun x => x) ~> l
|
||
#check_simp [].map f ~> []
|
||
#check_simp [x].map f ~> [f x]
|
||
|
||
#check_simp map f l = map g l ~> ∀ a ∈ l, f a = g a
|
||
variable (l : List Nat) in
|
||
#check_simp map (· + 1) l = map (·.succ) l ~> True
|
||
variable (l : List Nat) in
|
||
#check_simp map (0 * ·) l ~> map (fun _ => 0) l
|
||
variable (l : List String) in
|
||
#check_simp map (fun s => s ++ s) ("a" :: l) ~> "aa" :: map (fun s => s ++ s) l
|
||
|
||
#check_simp l.map f = [] ~> l = []
|
||
|
||
variable (w : l ≠ []) in
|
||
#check_simp head (l.map f) (by simpa) ~> f (head l (by simpa))
|
||
variable (l : List String) in
|
||
#check_simp head (("a" :: l).map fun s => s ++ s) (by simp) ~> "aa"
|
||
|
||
variable (w : l ≠ []) in
|
||
#check_simp getLast (l.map f) (by simpa) ~> f (getLast l (by simpa))
|
||
|
||
#check_simp (l₁ ++ l₂).map f ~> l₁.map f ++ l₂.map f
|
||
#check_simp (l.map f).map f' ~> l.map (f' ∘ f)
|
||
#check_simp (concat l x).map f ~> map f l ++ [f x]
|
||
|
||
variable (L : List (List α)) in
|
||
#check_simp L.flatten.map f ~> (L.map (map f)).flatten
|
||
#check_simp [l₁, l₂].flatten.map f ~> map f l₁ ++ map f l₂
|
||
|
||
#check_simp l.map (Function.const α "1") ~> replicate l.length "1"
|
||
#check_simp [x, y].map (Function.const α "1") ~> ["1", "1"]
|
||
|
||
#check_simp l.reverse.map f ~> (l.map f).reverse
|
||
|
||
#check_simp (l.take 3).map f ~> (l.map f).take 3
|
||
#check_simp (l.drop 3).map f ~> (l.map f).drop 3
|
||
|
||
#check_simp l.dropLast.map f ~> (l.map f).dropLast
|
||
|
||
variable (p : β → Bool) in
|
||
#check_simp (l.map f).find? p ~> (l.find? (p ∘ f)).map f
|
||
|
||
/-! ### filter -/
|
||
|
||
/-! ### filterMap -/
|
||
|
||
/-! ### append -/
|
||
|
||
variable (w : l₁ ≠ []) in
|
||
#check_tactic head (l₁ ++ l₂) (by simp_all) ~> head l₁ w by simp_all
|
||
|
||
#check_simp (l₁ ++ l₂).head? ~> l₁.head?.or l₂.head?
|
||
#check_simp (l₁ ++ l₂).getLast? ~> l₂.getLast?.or l₁.getLast?
|
||
|
||
/-! ### concat -/
|
||
|
||
/-! ### flatten -/
|
||
|
||
#check_simp (L₁ ++ L₂).flatten ~> L₁.flatten ++ L₂.flatten
|
||
|
||
/-! ### bind -/
|
||
|
||
/-! ### replicate -/
|
||
|
||
#check_simp replicate 0 x ~> []
|
||
#check_simp replicate 1 x ~> [x]
|
||
#check_simp replicate 5 x ~> [x, x, x, x, x]
|
||
|
||
-- `∈` and `contains
|
||
|
||
#check_simp y ∈ replicate 0 x ~> False
|
||
|
||
variable [BEq α] in
|
||
#check_simp (replicate 0 x).contains y ~> false
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate 0 x).contains y ~> false
|
||
|
||
#check_simp y ∈ replicate 7 x ~> y = x
|
||
|
||
variable [BEq α] in
|
||
#check_simp (replicate 7 x).contains y ~> y == x
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate 7 x).contains y ~> y == x
|
||
|
||
-- `getElem` and `getElem?`
|
||
|
||
variable (h : n < m) (w) in
|
||
#check_tactic (replicate m x)[n]'w ~> x by simp
|
||
|
||
variable (h : n < m) in
|
||
#check_tactic (replicate m x)[n]? ~> some x by simp [h]
|
||
|
||
#check_simp (replicate 7 x)[5] ~> x
|
||
|
||
#check_simp (replicate 7 x)[5]? ~> some x
|
||
|
||
variable (w : replicate n x ≠ []) in
|
||
#check_tactic (replicate n x).head w ~> x by simp_all
|
||
|
||
variable (w : replicate n x ≠ []) in
|
||
#check_tactic (replicate n x).getLast w ~> x by simp_all
|
||
|
||
-- injectivity
|
||
|
||
#check_simp replicate 3 x = replicate 7 x ~> False
|
||
#check_simp replicate 3 x = replicate 3 y ~> x = y
|
||
#check_simp replicate 3 "1" = replicate 3 "1" ~> True
|
||
#check_simp replicate n x = replicate m y ~> n = m ∧ (n = 0 ∨ x = y)
|
||
|
||
-- append
|
||
|
||
#check_simp replicate n x ++ replicate m x ~> replicate (n + m) x
|
||
|
||
-- map
|
||
|
||
#check_simp (replicate n "x").map (fun s => s ++ s) ~> replicate n "xx"
|
||
|
||
-- filter
|
||
|
||
#check_simp (replicate n [1]).filter (fun s => s.length = 1) ~> replicate n [1]
|
||
#check_simp (replicate n [1]).filter (fun s => s.length = 2) ~> []
|
||
|
||
-- filterMap
|
||
|
||
#check_simp (replicate n [1]).filterMap (fun s => if s.length = 1 then some s else none) ~> replicate n [1]
|
||
#check_simp (replicate n [1]).filterMap (fun s => if s.length = 2 then some s else none) ~> []
|
||
|
||
-- join
|
||
|
||
#check_simp (replicate n (replicate m x)).flatten ~> replicate (n * m) x
|
||
#check_simp (replicate 1 (replicate m x)).flatten ~> replicate m x
|
||
#check_simp (replicate n (replicate 1 x)).flatten ~> replicate n x
|
||
#check_simp (replicate n (replicate 0 x)).flatten ~> []
|
||
#check_simp (replicate 0 (replicate m x)).flatten ~> []
|
||
#check_simp (replicate 0 (replicate 0 x)).flatten ~> []
|
||
|
||
-- isEmpty
|
||
|
||
#check_simp (replicate (n + 1) x).isEmpty ~> false
|
||
#check_simp (replicate 0 x).isEmpty ~> true
|
||
variable (h : ¬ n = 0) in -- It would be nice if this also worked with `h : 0 < n`
|
||
#check_tactic (replicate n x).isEmpty ~> false by simp [h]
|
||
|
||
-- reverse
|
||
|
||
#check_simp (replicate n x).reverse ~> replicate n x
|
||
|
||
-- dropLast
|
||
|
||
#check_simp (replicate 0 x).dropLast ~> []
|
||
#check_simp (replicate n x).dropLast ~> replicate (n-1) x
|
||
#check_simp (replicate (n+1) x).dropLast ~> replicate n x
|
||
|
||
-- isPrefixOf
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp isPrefixOf [x, y, x] (replicate n x) ~> decide (3 ≤ n) && y == x
|
||
|
||
attribute [local simp] isPrefixOf_cons₂ in
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp isPrefixOf [x, y, x] (replicate (n+3) x) ~> y == x
|
||
|
||
-- isSuffixOf
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp isSuffixOf [x, y, x] (replicate n x) ~> decide (3 ≤ n) && y == x
|
||
|
||
-- rotateLeft
|
||
|
||
#check_simp (replicate n x).rotateLeft m ~> replicate n x
|
||
|
||
-- rotateRight
|
||
|
||
#check_simp (replicate n x).rotateRight m ~> replicate n x
|
||
|
||
-- replace
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate (n+1) x).replace x y ~> y :: replicate n x
|
||
|
||
#check_simp (replicate n "1").replace "2" "3" ~> (replicate n "1")
|
||
|
||
-- insert
|
||
|
||
variable [BEq α] [LawfulBEq α] (h : 0 < n) in
|
||
#check_tactic (replicate n x).insert x ~> replicate n x by simp [h]
|
||
|
||
#check_simp (replicate n "1").insert "2" ~> "2" :: replicate n "1"
|
||
|
||
-- erase
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate (n+1) x).erase x ~> replicate n x
|
||
|
||
#check_simp (replicate n "1").erase "2" ~> replicate n "1"
|
||
|
||
-- find?
|
||
|
||
#check_simp (replicate (n+1) x).find? (fun _ => true) ~> some x
|
||
#check_simp (replicate (n+1) x).find? (fun _ => false) ~> none
|
||
|
||
variable {p : α → Bool} (w : p x) in
|
||
#check_tactic (replicate (n+1) x).find? p ~> some x by simp [w]
|
||
variable {p : α → Bool} (w : ¬ p x) in
|
||
#check_tactic (replicate (n+1) x).find? p ~> none by simp [w]
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? (fun _ => true) ~> some x by simp [h]
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? (fun _ => false) ~> none by simp [h]
|
||
|
||
variable {p : α → Bool} (w : p x) (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? p ~> some x by simp [w, h]
|
||
variable {p : α → Bool} (w : ¬ p x) (h : 0 < n) in
|
||
#check_tactic (replicate n x).find? p ~> none by simp [w, h]
|
||
|
||
-- findSome?
|
||
|
||
#check_simp (replicate (n+1) x).findSome? (fun x => some x) ~> some x
|
||
#check_simp (replicate (n+1) x).findSome? (fun _ => (none : Option β)) ~> none
|
||
|
||
variable {f : α → Option β} in
|
||
#check_tactic (replicate (n+1) x).findSome? f ~> f x by simp
|
||
variable {f : α → Option β} (w : (f x).isNone) in
|
||
#check_tactic (replicate (n+1) x).findSome? f ~> none by simp_all
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? (fun x => some x) ~> some x by simp [h]
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? (fun _ => (none : Option β)) ~> none by simp [h]
|
||
|
||
variable {f : α → Option β} (w : (f x).isSome) (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? f ~> f x by simp [h]
|
||
variable {f : α → Option β} (w : (f x).isNone) (h : 0 < n) in
|
||
#check_tactic (replicate n x).findSome? f ~> none by simp_all
|
||
|
||
-- lookup
|
||
|
||
variable [BEq α] [LawfulBEq α] in
|
||
#check_simp (replicate (n+1) (x, y)).lookup x ~> some y
|
||
|
||
variable [BEq α] [LawfulBEq α] (h : 0 < n) in
|
||
#check_tactic (replicate n (x, y)).lookup x ~> some y by simp [h]
|
||
|
||
#check_simp (replicate n ("1", "2")).lookup "3" ~> none
|
||
|
||
-- zip
|
||
|
||
#check_simp (replicate n x).zip (replicate n y) ~> replicate n (x, y)
|
||
#check_simp (replicate n x).zip (replicate m y) ~> replicate (min n m) (x, y)
|
||
variable (h : n ≤ m) in
|
||
#check_tactic (replicate n x).zip (replicate m y) ~> replicate n (x, y) by simp [h, Nat.min_eq_left]
|
||
|
||
-- zipWith
|
||
section
|
||
variable (f : α → α → α)
|
||
|
||
#check_simp zipWith f (replicate n x) (replicate n y) ~> replicate n (f x y)
|
||
#check_simp zipWith f (replicate n x) (replicate m y) ~> replicate (min n m) (f x y)
|
||
variable (h : n ≤ m) in
|
||
#check_tactic zipWith f (replicate n x) (replicate m y) ~> replicate n (f x y) by simp [h, Nat.min_eq_left]
|
||
|
||
-- unzip
|
||
#check_simp unzip (replicate n (x, y)) ~> (replicate n x, replicate n y)
|
||
|
||
-- min?
|
||
|
||
-- Note this relies on the fact that we do not have `replicate_succ` as a `@[simp]` lemma
|
||
#check_simp (replicate (n+1) 7).min? ~> some 7
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n 7).min? ~> some 7 by simp [h]
|
||
|
||
-- max?
|
||
|
||
-- Note this relies on the fact that we do not have `replicate_succ` as a `@[simp]` lemma
|
||
#check_simp (replicate (n+1) 7).max? ~> some 7
|
||
|
||
variable (h : 0 < n) in
|
||
#check_tactic (replicate n 7).max? ~> some 7 by simp [h]
|
||
|
||
end
|
||
|
||
/-! ### reverse -/
|
||
|
||
variable (p : α → Bool) in
|
||
#check_simp (l.reverse.filter p) ~> (l.filter p).reverse
|
||
|
||
variable (f : α → Option β) in
|
||
#check_simp (l.reverse.filterMap f) ~> (l.filterMap f).reverse
|
||
|
||
#check_simp l.reverse.head? ~> l.getLast?
|
||
#check_simp l.reverse.getLast? ~> l.head?
|
||
|
||
variable (h : l.reverse ≠ []) in
|
||
#check_simp l.reverse.head h ~> l.getLast (by simp_all)
|
||
|
||
variable (h : l.reverse ≠ []) in
|
||
#check_simp l.reverse.getLast h ~> l.head (by simp_all)
|
||
|
||
/-! ## List membership -/
|
||
|
||
/-! ### elem / contains -/
|
||
|
||
/-! ## Sublists -/
|
||
|
||
/-! ### take and drop -/
|
||
|
||
/-! ### takeWhile and dropWhile -/
|
||
|
||
/-! ### partition -/
|
||
|
||
/-! ### dropLast -/
|
||
|
||
/-! ### isPrefixOf -/
|
||
|
||
/-! ### isSuffixOf -/
|
||
|
||
variable [BEq α] in
|
||
#check_simp ([] : List α).isSuffixOf l ~> true
|
||
|
||
/-! ### rotateLeft -/
|
||
|
||
/-! ### rotateRight -/
|
||
|
||
|
||
/-! ## Pairwise and Nodup -/
|
||
|
||
/-! ### Pairwise -/
|
||
section Pairwise
|
||
variable (R : α → α → Prop)
|
||
#check_simp Pairwise R [] ~> True
|
||
#check_simp Pairwise R (x :: l) ~> (∀ (a' : α), a' ∈ l → R x a') ∧ Pairwise R l
|
||
#check_simp Pairwise R [x, y, z] ~> (R x y ∧ R x z) ∧ R y z
|
||
|
||
#check_simp Pairwise R (replicate n x) ~> n ≤ 1 ∨ R x x
|
||
#check_simp Pairwise R (replicate 1 x) ~> True
|
||
#check_simp Pairwise R (replicate (n+2) x) ~> R x x
|
||
#check_simp Pairwise (· < ·) (replicate 2 m) ~> False
|
||
#check_simp Pairwise (· < ·) (replicate n m) ~> n ≤ 1
|
||
#check_simp Pairwise (· < ·) (replicate (n + 2) m) ~> False
|
||
#check_simp Pairwise (· = ·) (replicate 2 m) ~> True
|
||
#check_simp Pairwise (· = ·) (replicate n m) ~> True
|
||
|
||
end Pairwise
|
||
|
||
/-! ### Nodup -/
|
||
|
||
#check_simp Nodup [] ~> True
|
||
#check_simp Nodup (x :: l) ~> ¬x ∈ l ∧ l.Nodup
|
||
#check_simp Nodup [x, y, z] ~> (¬x = y ∧ ¬x = z) ∧ ¬y = z
|
||
|
||
#check_simp Nodup (replicate (n+2) x) ~> False
|
||
#check_simp Nodup (replicate 2 x) ~> False
|
||
|
||
/-! ## Manipulating elements -/
|
||
|
||
/-! ### replace -/
|
||
|
||
/-! ### insert -/
|
||
|
||
/-! ### erase -/
|
||
|
||
/-! ### find? -/
|
||
|
||
/-! ### findSome? -/
|
||
|
||
/-! ### lookup -/
|
||
|
||
/-! ## Logic -/
|
||
|
||
/-! ### any / all -/
|
||
|
||
/-! ## Zippers -/
|
||
|
||
/-! ### zip -/
|
||
|
||
/-! ### zipWith -/
|
||
|
||
/-! ### zipWithAll -/
|
||
|
||
/-! ## Ranges and enumeration -/
|
||
|
||
example : (List.range 1).sum = 0 := by simp
|
||
|
||
/-! ### enumFrom -/
|
||
|
||
/-! ### min? -/
|
||
|
||
/-! ### max? -/
|
||
|
||
/-! ## ofFn -/
|
||
|
||
example (f : Fin 3 → Nat) : List.ofFn f = [f 0, f 1, f 2] := rfl
|
||
|
||
-- Out of place, but lets check that `Fin.foldl` is semireducible too.
|
||
-- Well, no longer the case
|
||
-- example (f : Fin 3 → Nat) : Fin.foldl 3 (fun acc i => f i :: acc) [] = [f 2, f 1, f 0] := rfl
|
||
|
||
/-! ## Monadic operations -/
|
||
|
||
#check_simp
|
||
(Id.run do
|
||
let mut s := 0
|
||
for i in [1,2,3,4] do
|
||
s := s + i
|
||
pure s) ~> 10
|
||
|
||
#check_simp
|
||
(Id.run do
|
||
let mut s := 0
|
||
for h : i in [1,2,3,4] do
|
||
s := s + i
|
||
pure s) ~> 10
|
||
|
||
variable (l : List α) (k m : Nat) in
|
||
#check_simp
|
||
(Id.run do
|
||
let mut x := m
|
||
for _ in l do
|
||
x := x + k
|
||
pure x) ~> m + k * l.length
|
||
|
||
-- as above, but for an arbitrary monad
|
||
variable (l : List α) (k m : Nat) {M} [Monad M] [LawfulMonad M] in
|
||
#check_simp
|
||
(show M _ from do
|
||
let mut x := m
|
||
for _ in l do
|
||
x := x + k
|
||
pure x) ~> pure (m + k * l.length)
|
||
|
||
/-! ### mapM -/
|
||
|
||
/-! ### forM -/
|