File: Mathlib/Data/Fin/Tuple/Basic.lean

full_name: Fin.tuple0_le
code: theorem tuple0_le {α : Fin 0 → Type*} [∀ i, Preorder (α i)] (f g : ∀ i, α i) : f ≤ g 
goal: f ≤ g

full_name: Fin.tail
code: /-- The tail of an `n+1` tuple, i.e., its last `n` entries. -/
def tail (q : ∀ i, α i) : ∀ i : Fin n, α i.succ 
goal: α i.succ

full_name: Fin.tail_def
code: theorem tail_def {n : ℕ} {α : Fin (n + 1) → Type*} {q : ∀ i, α i} :
    (tail fun k : Fin (n + 1) ↦ q k) = fun k : Fin n ↦ q k.succ 
goal: (Fin.tail fun k => q k) = fun k => q k.succ

full_name: Fin.cons
code: /-- Adding an element at the beginning of an `n`-tuple, to get an `n+1`-tuple. -/
def cons (x : α 0) (p : ∀ i : Fin n, α i.succ) : ∀ i, α i 
goal: α i

full_name: Fin.tail_cons
code: @[simp]
theorem tail_cons : tail (cons x p) = p 
goal: Fin.tail (Fin.cons x p) = p

full_name: Fin.cons_succ
code: @[simp]
theorem cons_succ : cons x p i.succ = p i 
goal: Fin.cons x p i.succ = p i

full_name: Fin.cons_zero
code: @[simp]
theorem cons_zero : cons x p 0 = x 
goal: Fin.cons x p 0 = x

full_name: Fin.cons_one
code: @[simp]
theorem cons_one {α : Fin (n + 2) → Type*} (x : α 0) (p : ∀ i : Fin n.succ, α i.succ) :
    cons x p 1 = p 0 
goal: Fin.cons x p 1 = p 0

full_name: Fin.cons_update
code: /-- Updating a tuple and adding an element at the beginning commute. -/
@[simp]
theorem cons_update : cons x (update p i y) = update (cons x p) i.succ y 
goal: Fin.cons x (Function.update p i y) = Function.update (Fin.cons x p) i.succ y

full_name: Fin.cons_injective2
code: /-- As a binary function, `Fin.cons` is injective. -/
theorem cons_injective2 : Function.Injective2 (@cons n α) 
goal: Function.Injective2 Fin.cons

full_name: Fin.cons_eq_cons
code: @[simp]
theorem cons_eq_cons {x₀ y₀ : α 0} {x y : ∀ i : Fin n, α i.succ} :
    cons x₀ x = cons y₀ y ↔ x₀ = y₀ ∧ x = y 
goal: Fin.cons x₀ x = Fin.cons y₀ y ↔ x₀ = y₀ ∧ x = y

full_name: Fin.cons_left_injective
code: theorem cons_left_injective (x : ∀ i : Fin n, α i.succ) : Function.Injective fun x₀ ↦ cons x₀ x 
goal: Function.Injective fun x₀ => Fin.cons x₀ x

full_name: Fin.cons_right_injective
code: theorem cons_right_injective (x₀ : α 0) : Function.Injective (cons x₀) 
goal: Function.Injective (Fin.cons x₀)

full_name: Fin.update_cons_zero
code: /-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_cons_zero : update (cons x p) 0 z = cons z p 
goal: Function.update (Fin.cons x p) 0 z = Fin.cons z p

full_name: Fin.cons_self_tail
code: /-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp, nolint simpNF] -- Porting note: linter claims LHS doesn't simplify
theorem cons_self_tail : cons (q 0) (tail q) = q 
goal: Fin.cons (q 0) (Fin.tail q) = q

full_name: Fin.consCases
code: /-- Recurse on an `n+1`-tuple by splitting it into a single element and an `n`-tuple. -/
@[elab_as_elim]
def consCases {P : (∀ i : Fin n.succ, α i) → Sort v} (h : ∀ x₀ x, P (Fin.cons x₀ x))
    (x : ∀ i : Fin n.succ, α i) : P x 
goal: P x

full_name: Fin.consCases_cons
code: @[simp]
theorem consCases_cons {P : (∀ i : Fin n.succ, α i) → Sort v} (h : ∀ x₀ x, P (Fin.cons x₀ x))
    (x₀ : α 0) (x : ∀ i : Fin n, α i.succ) : @consCases _ _ _ h (cons x₀ x) = h x₀ x 
goal: Fin.consCases h (Fin.cons x₀ x) = h x₀ x

full_name: Fin.consInduction
code: /-- Recurse on a tuple by splitting into `Fin.elim0` and `Fin.cons`. -/
@[elab_as_elim]
def consInduction {α : Type*} {P : ∀ {n : ℕ}, (Fin n → α) → Sort v} (h0 : P Fin.elim0)
    (h : ∀ {n} (x₀) (x : Fin n → α), P x → P (Fin.cons x₀ x)) : ∀ {n : ℕ} (x : Fin n → α), P x
  
goal: P x

full_name: Fin.cons_injective_of_injective
code: theorem cons_injective_of_injective {α} {x₀ : α} {x : Fin n → α} (hx₀ : x₀ ∉ Set.range x)
    (hx : Function.Injective x) : Function.Injective (cons x₀ x : Fin n.succ → α) 
goal: Function.Injective (Fin.cons x₀ x)

full_name: Fin.cons_injective_iff
code: theorem cons_injective_iff {α} {x₀ : α} {x : Fin n → α} :
    Function.Injective (cons x₀ x : Fin n.succ → α) ↔ x₀ ∉ Set.range x ∧ Function.Injective x 
goal: Function.Injective (Fin.cons x₀ x) ↔ x₀ ∉ Set.range x ∧ Function.Injective x

full_name: Fin.forall_fin_zero_pi
code: @[simp]
theorem forall_fin_zero_pi {α : Fin 0 → Sort*} {P : (∀ i, α i) → Prop} :
    (∀ x, P x) ↔ P finZeroElim 
goal: (∀ (x : (i : Fin 0) → α i), P x) ↔ P finZeroElim

full_name: Fin.exists_fin_zero_pi
code: @[simp]
theorem exists_fin_zero_pi {α : Fin 0 → Sort*} {P : (∀ i, α i) → Prop} :
    (∃ x, P x) ↔ P finZeroElim 
goal: (∃ x, P x) ↔ P finZeroElim

full_name: Fin.forall_fin_succ_pi
code: theorem forall_fin_succ_pi {P : (∀ i, α i) → Prop} : (∀ x, P x) ↔ ∀ a v, P (Fin.cons a v) 
goal: (∀ (x : (i : Fin (n + 1)) → α i), P x) ↔ ∀ (a : α 0) (v : (i : Fin n) → α i.succ), P (Fin.cons a v)

full_name: Fin.exists_fin_succ_pi
code: theorem exists_fin_succ_pi {P : (∀ i, α i) → Prop} : (∃ x, P x) ↔ ∃ a v, P (Fin.cons a v) 
goal: (∃ x, P x) ↔ ∃ a v, P (Fin.cons a v)

full_name: Fin.tail_update_zero
code: /-- Updating the first element of a tuple does not change the tail. -/
@[simp]
theorem tail_update_zero : tail (update q 0 z) = tail q 
goal: Fin.tail (Function.update q 0 z) = Fin.tail q

full_name: Fin.tail_update_succ
code: /-- Updating a nonzero element and taking the tail commute. -/
@[simp]
theorem tail_update_succ : tail (update q i.succ y) = update (tail q) i y 
goal: Fin.tail (Function.update q i.succ y) = Function.update (Fin.tail q) i y

full_name: Fin.comp_cons
code: theorem comp_cons {α : Type*} {β : Type*} (g : α → β) (y : α) (q : Fin n → α) :
    g ∘ cons y q = cons (g y) (g ∘ q) 
goal: g ∘ Fin.cons y q = Fin.cons (g y) (g ∘ q)

full_name: Fin.comp_tail
code: theorem comp_tail {α : Type*} {β : Type*} (g : α → β) (q : Fin n.succ → α) :
    g ∘ tail q = tail (g ∘ q) 
goal: g ∘ Fin.tail q = Fin.tail (g ∘ q)

full_name: Fin.le_cons
code: theorem le_cons [∀ i, Preorder (α i)] {x : α 0} {q : ∀ i, α i} {p : ∀ i : Fin n, α i.succ} :
    q ≤ cons x p ↔ q 0 ≤ x ∧ tail q ≤ p 
goal: q ≤ Fin.cons x p ↔ q 0 ≤ x ∧ Fin.tail q ≤ p

full_name: Fin.cons_le
code: theorem cons_le [∀ i, Preorder (α i)] {x : α 0} {q : ∀ i, α i} {p : ∀ i : Fin n, α i.succ} :
    cons x p ≤ q ↔ x ≤ q 0 ∧ p ≤ tail q 
goal: Fin.cons x p ≤ q ↔ x ≤ q 0 ∧ p ≤ Fin.tail q

full_name: Fin.cons_le_cons
code: theorem cons_le_cons [∀ i, Preorder (α i)] {x₀ y₀ : α 0} {x y : ∀ i : Fin n, α i.succ} :
    cons x₀ x ≤ cons y₀ y ↔ x₀ ≤ y₀ ∧ x ≤ y 
goal: Fin.cons x₀ x ≤ Fin.cons y₀ y ↔ x₀ ≤ y₀ ∧ x ≤ y

full_name: Fin.range_fin_succ
code: theorem range_fin_succ {α} (f : Fin (n + 1) → α) :
    Set.range f = insert (f 0) (Set.range (Fin.tail f)) 
goal: Set.range f = insert (f 0) (Set.range (Fin.tail f))

full_name: Fin.range_cons
code: @[simp]
theorem range_cons {α : Type*} {n : ℕ} (x : α) (b : Fin n → α) :
    Set.range (Fin.cons x b : Fin n.succ → α) = insert x (Set.range b) 
goal: Set.range (Fin.cons x b) = insert x (Set.range b)

full_name: Fin.append
code: /-- Append a tuple of length `m` to a tuple of length `n` to get a tuple of length `m + n`.
This is a non-dependent version of `Fin.add_cases`. -/
def append {α : Type*} (a : Fin m → α) (b : Fin n → α) : Fin (m + n) → α 
goal: Fin (m + n) → α

full_name: Fin.append_left
code: @[simp]
theorem append_left {α : Type*} (u : Fin m → α) (v : Fin n → α) (i : Fin m) :
    append u v (Fin.castAdd n i) = u i 
goal: Fin.append u v (Fin.castAdd n i) = u i

full_name: Fin.append_right
code: @[simp]
theorem append_right {α : Type*} (u : Fin m → α) (v : Fin n → α) (i : Fin n) :
    append u v (natAdd m i) = v i 
goal: Fin.append u v (Fin.natAdd m i) = v i

full_name: Fin.append_right_nil
code: theorem append_right_nil {α : Type*} (u : Fin m → α) (v : Fin n → α) (hv : n = 0) :
    append u v = u ∘ Fin.cast (by rw [hv, Nat.add_zero]) 
goal: Fin.append u v = u ∘ Fin.cast ⋯

full_name: Fin.append_elim0
code: @[simp]
theorem append_elim0 {α : Type*} (u : Fin m → α) :
    append u Fin.elim0 = u ∘ Fin.cast (Nat.add_zero _) 
goal: Fin.append u Fin.elim0 = u ∘ Fin.cast ⋯

full_name: Fin.append_left_nil
code: theorem append_left_nil {α : Type*} (u : Fin m → α) (v : Fin n → α) (hu : m = 0) :
    append u v = v ∘ Fin.cast (by rw [hu, Nat.zero_add]) 
goal: Fin.append u v = v ∘ Fin.cast ⋯

full_name: Fin.elim0_append
code: @[simp]
theorem elim0_append {α : Type*} (v : Fin n → α) :
    append Fin.elim0 v = v ∘ Fin.cast (Nat.zero_add _) 
goal: Fin.append Fin.elim0 v = v ∘ Fin.cast ⋯

full_name: Fin.append_assoc
code: theorem append_assoc {p : ℕ} {α : Type*} (a : Fin m → α) (b : Fin n → α) (c : Fin p → α) :
    append (append a b) c = append a (append b c) ∘ Fin.cast (Nat.add_assoc ..) 
goal: Fin.append (Fin.append a b) c = Fin.append a (Fin.append b c) ∘ Fin.cast ⋯

full_name: Fin.append_left_eq_cons
code: /-- Appending a one-tuple to the left is the same as `Fin.cons`. -/
theorem append_left_eq_cons {α : Type*} {n : ℕ} (x₀ : Fin 1 → α) (x : Fin n → α) :
    Fin.append x₀ x = Fin.cons (x₀ 0) x ∘ Fin.cast (Nat.add_comm ..) 
goal: Fin.append x₀ x = Fin.cons (x₀ 0) x ∘ Fin.cast ⋯

full_name: Fin.cons_eq_append
code: /-- `Fin.cons` is the same as appending a one-tuple to the left. -/
theorem cons_eq_append {α : Type*} (x : α) (xs : Fin n → α) :
    cons x xs = append (cons x Fin.elim0) xs ∘ Fin.cast (Nat.add_comm ..) 
goal: Fin.cons x xs = Fin.append (Fin.cons x Fin.elim0) xs ∘ Fin.cast ⋯

full_name: Fin.append_cast_left
code: @[simp] lemma append_cast_left {n m} {α : Type*} (xs : Fin n → α) (ys : Fin m → α) (n' : ℕ)
    (h : n' = n) :
    Fin.append (xs ∘ Fin.cast h) ys = Fin.append xs ys ∘ (Fin.cast <| by rw [h]) 
goal: Fin.append (xs ∘ Fin.cast h) ys = Fin.append xs ys ∘ Fin.cast ⋯

full_name: Fin.append_cast_right
code: @[simp] lemma append_cast_right {n m} {α : Type*} (xs : Fin n → α) (ys : Fin m → α) (m' : ℕ)
    (h : m' = m) :
    Fin.append xs (ys ∘ Fin.cast h) = Fin.append xs ys ∘ (Fin.cast <| by rw [h]) 
goal: Fin.append xs (ys ∘ Fin.cast h) = Fin.append xs ys ∘ Fin.cast ⋯

full_name: Fin.append_rev
code: lemma append_rev {m n} {α : Type*} (xs : Fin m → α) (ys : Fin n → α) (i : Fin (m + n)) :
    append xs ys (rev i) = append (ys ∘ rev) (xs ∘ rev) (cast (Nat.add_comm ..) i) 
goal: Fin.append xs ys i.rev = Fin.append (ys ∘ Fin.rev) (xs ∘ Fin.rev) (Fin.cast ⋯ i)

full_name: Fin.append_comp_rev
code: lemma append_comp_rev {m n} {α : Type*} (xs : Fin m → α) (ys : Fin n → α) :
    append xs ys ∘ rev = append (ys ∘ rev) (xs ∘ rev) ∘ cast (Nat.add_comm ..) 
goal: Fin.append xs ys ∘ Fin.rev = Fin.append (ys ∘ Fin.rev) (xs ∘ Fin.rev) ∘ Fin.cast ⋯

full_name: Fin.repeat
code: /-- Repeat `a` `m` times. For example `Fin.repeat 2 ![0, 3, 7] = ![0, 3, 7, 0, 3, 7]`. -/
-- Porting note: removed @[simp]
def «repeat» {α : Type*} (m : ℕ) (a : Fin n → α) : Fin (m * n) → α
  
goal: Fin (m * n) → α

full_name: Fin.repeat_apply
code: @[simp]
theorem repeat_apply {α : Type*} (a : Fin n → α) (i : Fin (m * n)) :
    Fin.repeat m a i = a i.modNat 
goal: Fin.repeat m a i = a i.modNat

full_name: Fin.repeat_zero
code: @[simp]
theorem repeat_zero {α : Type*} (a : Fin n → α) :
    Fin.repeat 0 a = Fin.elim0 ∘ cast (Nat.zero_mul _) 
goal: Fin.repeat 0 a = Fin.elim0 ∘ Fin.cast ⋯

full_name: Fin.repeat_one
code: @[simp]
theorem repeat_one {α : Type*} (a : Fin n → α) : Fin.repeat 1 a = a ∘ cast (Nat.one_mul _) 
goal: Fin.repeat 1 a = a ∘ Fin.cast ⋯

full_name: Fin.repeat_succ
code: theorem repeat_succ {α : Type*} (a : Fin n → α) (m : ℕ) :
    Fin.repeat m.succ a =
      append a (Fin.repeat m a) ∘ cast ((Nat.succ_mul _ _).trans (Nat.add_comm ..)) 
goal: Fin.repeat m.succ a = Fin.append a (Fin.repeat m a) ∘ Fin.cast ⋯

full_name: Fin.repeat_add
code: @[simp]
theorem repeat_add {α : Type*} (a : Fin n → α) (m₁ m₂ : ℕ) : Fin.repeat (m₁ + m₂) a =
    append (Fin.repeat m₁ a) (Fin.repeat m₂ a) ∘ cast (Nat.add_mul ..) 
goal: Fin.repeat (m₁ + m₂) a = Fin.append (Fin.repeat m₁ a) (Fin.repeat m₂ a) ∘ Fin.cast ⋯

full_name: Fin.repeat_rev
code: theorem repeat_rev {α : Type*} (a : Fin n → α) (k : Fin (m * n)) :
    Fin.repeat m a k.rev = Fin.repeat m (a ∘ Fin.rev) k 
goal: Fin.repeat m a k.rev = Fin.repeat m (a ∘ Fin.rev) k

full_name: Fin.repeat_comp_rev
code: theorem repeat_comp_rev {α} (a : Fin n → α) :
    Fin.repeat m a ∘ Fin.rev = Fin.repeat m (a ∘ Fin.rev) 
goal: Fin.repeat m a ∘ Fin.rev = Fin.repeat m (a ∘ Fin.rev)

full_name: Fin.init
code: /-- The beginning of an `n+1` tuple, i.e., its first `n` entries -/
def init (q : ∀ i, α i) (i : Fin n) : α (castSucc i) 
goal: α i.castSucc

full_name: Fin.init_def
code: theorem init_def {n : ℕ} {α : Fin (n + 1) → Type*} {q : ∀ i, α i} :
    (init fun k : Fin (n + 1) ↦ q k) = fun k : Fin n ↦ q (castSucc k) 
goal: (Fin.init fun k => q k) = fun k => q k.castSucc

full_name: Fin.snoc
code: /-- Adding an element at the end of an `n`-tuple, to get an `n+1`-tuple. The name `snoc` comes from
`cons` (i.e., adding an element to the left of a tuple) read in reverse order. -/
def snoc (p : ∀ i : Fin n, α (castSucc i)) (x : α (last n)) (i : Fin (n + 1)) : α i 
goal: α i

full_name: Fin.init_snoc
code: @[simp]
theorem init_snoc : init (snoc p x) = p 
goal: Fin.init (Fin.snoc p x) = p

full_name: Fin.snoc_castSucc
code: @[simp]
theorem snoc_castSucc : snoc p x (castSucc i) = p i 
goal: Fin.snoc p x i.castSucc = p i

full_name: Fin.snoc_comp_castSucc
code: @[simp]
theorem snoc_comp_castSucc {n : ℕ} {α : Sort _} {a : α} {f : Fin n → α} :
    (snoc f a : Fin (n + 1) → α) ∘ castSucc = f 
goal: Fin.snoc f a ∘ Fin.castSucc = f

full_name: Fin.snoc_last
code: @[simp]
theorem snoc_last : snoc p x (last n) = x 
goal: Fin.snoc p x (Fin.last n) = x

full_name: Fin.snoc_zero
code: lemma snoc_zero {α : Type*} (p : Fin 0 → α) (x : α) :
    Fin.snoc p x = fun _ ↦ x 
goal: Fin.snoc p x = fun x_1 => x

full_name: Fin.snoc_comp_nat_add
code: @[simp]
theorem snoc_comp_nat_add {n m : ℕ} {α : Sort _} (f : Fin (m + n) → α) (a : α) :
    (snoc f a : Fin _ → α) ∘ (natAdd m : Fin (n + 1) → Fin (m + n + 1)) =
      snoc (f ∘ natAdd m) a 
goal: Fin.snoc f a ∘ Fin.natAdd m = Fin.snoc (f ∘ Fin.natAdd m) a

full_name: Fin.snoc_cast_add
code: @[simp]
theorem snoc_cast_add {α : Fin (n + m + 1) → Type*} (f : ∀ i : Fin (n + m), α (castSucc i))
    (a : α (last (n + m))) (i : Fin n) : (snoc f a) (castAdd (m + 1) i) = f (castAdd m i) 
goal: Fin.snoc f a (Fin.castAdd (m + 1) i) = f (Fin.castAdd m i)

full_name: Fin.snoc_comp_cast_add
code: @[simp]
theorem snoc_comp_cast_add {n m : ℕ} {α : Sort _} (f : Fin (n + m) → α) (a : α) :
    (snoc f a : Fin _ → α) ∘ castAdd (m + 1) = f ∘ castAdd m 
goal: Fin.snoc f a ∘ Fin.castAdd (m + 1) = f ∘ Fin.castAdd m

full_name: Fin.snoc_update
code: /-- Updating a tuple and adding an element at the end commute. -/
@[simp]
theorem snoc_update : snoc (update p i y) x = update (snoc p x) (castSucc i) y 
goal: Fin.snoc (Function.update p i y) x = Function.update (Fin.snoc p x) i.castSucc y

full_name: Fin.update_snoc_last
code: /-- Adding an element at the beginning of a tuple and then updating it amounts to adding it
directly. -/
theorem update_snoc_last : update (snoc p x) (last n) z = snoc p z 
goal: Function.update (Fin.snoc p x) (Fin.last n) z = Fin.snoc p z

full_name: Fin.snoc_init_self
code: /-- Concatenating the first element of a tuple with its tail gives back the original tuple -/
@[simp]
theorem snoc_init_self : snoc (init q) (q (last n)) = q 
goal: Fin.snoc (Fin.init q) (q (Fin.last n)) = q

full_name: Fin.init_update_last
code: /-- Updating the last element of a tuple does not change the beginning. -/
@[simp]
theorem init_update_last : init (update q (last n) z) = init q 
goal: Fin.init (Function.update q (Fin.last n) z) = Fin.init q

full_name: Fin.init_update_castSucc
code: /-- Updating an element and taking the beginning commute. -/
@[simp]
theorem init_update_castSucc : init (update q (castSucc i) y) = update (init q) i y 
goal: Fin.init (Function.update q i.castSucc y) = Function.update (Fin.init q) i y

full_name: Fin.tail_init_eq_init_tail
code: /-- `tail` and `init` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem tail_init_eq_init_tail {β : Type*} (q : Fin (n + 2) → β) :
    tail (init q) = init (tail q) 
goal: Fin.tail (Fin.init q) = Fin.init (Fin.tail q)

full_name: Fin.cons_snoc_eq_snoc_cons
code: /-- `cons` and `snoc` commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use. -/
theorem cons_snoc_eq_snoc_cons {β : Type*} (a : β) (q : Fin n → β) (b : β) :
    @cons n.succ (fun _ ↦ β) a (snoc q b) = snoc (cons a q) b 
goal: Fin.cons a (Fin.snoc q b) = Fin.snoc (Fin.cons a q) b

full_name: Fin.comp_snoc
code: theorem comp_snoc {α : Type*} {β : Type*} (g : α → β) (q : Fin n → α) (y : α) :
    g ∘ snoc q y = snoc (g ∘ q) (g y) 
goal: g ∘ Fin.snoc q y = Fin.snoc (g ∘ q) (g y)

full_name: Fin.append_right_eq_snoc
code: /-- Appending a one-tuple to the right is the same as `Fin.snoc`. -/
theorem append_right_eq_snoc {α : Type*} {n : ℕ} (x : Fin n → α) (x₀ : Fin 1 → α) :
    Fin.append x x₀ = Fin.snoc x (x₀ 0) 
goal: Fin.append x x₀ = Fin.snoc x (x₀ 0)

full_name: Fin.snoc_eq_append
code: /-- `Fin.snoc` is the same as appending a one-tuple -/
theorem snoc_eq_append {α : Type*} (xs : Fin n → α) (x : α) :
    snoc xs x = append xs (cons x Fin.elim0) 
goal: Fin.snoc xs x = Fin.append xs (Fin.cons x Fin.elim0)

full_name: Fin.append_left_snoc
code: theorem append_left_snoc {n m} {α : Type*} (xs : Fin n → α) (x : α) (ys : Fin m → α) :
    Fin.append (Fin.snoc xs x) ys =
      Fin.append xs (Fin.cons x ys) ∘ Fin.cast (Nat.succ_add_eq_add_succ ..) 
goal: Fin.append (Fin.snoc xs x) ys = Fin.append xs (Fin.cons x ys) ∘ Fin.cast ⋯

full_name: Fin.append_right_cons
code: theorem append_right_cons {n m} {α : Type*} (xs : Fin n → α) (y : α) (ys : Fin m → α) :
    Fin.append xs (Fin.cons y ys) =
      Fin.append (Fin.snoc xs y) ys ∘ Fin.cast (Nat.succ_add_eq_add_succ ..).symm 
goal: Fin.append xs (Fin.cons y ys) = Fin.append (Fin.snoc xs y) ys ∘ Fin.cast ⋯

full_name: Fin.append_cons
code: theorem append_cons {α} (a : α) (as : Fin n → α) (bs : Fin m → α) :
    Fin.append (cons a as) bs
    = cons a (Fin.append as bs) ∘ (Fin.cast <| Nat.add_right_comm n 1 m) 
goal: Fin.append (Fin.cons a as) bs = Fin.cons a (Fin.append as bs) ∘ Fin.cast ⋯

full_name: Fin.append_snoc
code: theorem append_snoc {α} (as : Fin n → α) (bs : Fin m → α) (b : α) :
    Fin.append as (snoc bs b) = snoc (Fin.append as bs) b 
goal: Fin.append as (Fin.snoc bs b) = Fin.snoc (Fin.append as bs) b

full_name: Fin.comp_init
code: theorem comp_init {α : Type*} {β : Type*} (g : α → β) (q : Fin n.succ → α) :
    g ∘ init q = init (g ∘ q) 
goal: g ∘ Fin.init q = Fin.init (g ∘ q)

full_name: Fin.snocCases
code: /-- Recurse on an `n+1`-tuple by splitting it its initial `n`-tuple and its last element. -/
@[elab_as_elim, inline]
def snocCases {P : (∀ i : Fin n.succ, α i) → Sort*}
    (h : ∀ xs x, P (Fin.snoc xs x))
    (x : ∀ i : Fin n.succ, α i) : P x 
goal: P x

full_name: Fin.snocCases_snoc
code: @[simp] lemma snocCases_snoc
    {P : (∀ i : Fin (n+1), α i) → Sort*} (h : ∀ x x₀, P (Fin.snoc x x₀))
    (x : ∀ i : Fin n, (Fin.init α) i) (x₀ : α (Fin.last _)) :
    snocCases h (Fin.snoc x x₀) = h x x₀ 
goal: Fin.snocCases h (Fin.snoc x x₀) = h x x₀

full_name: Fin.snocInduction
code: /-- Recurse on a tuple by splitting into `Fin.elim0` and `Fin.snoc`. -/
@[elab_as_elim]
def snocInduction {α : Type*}
    {P : ∀ {n : ℕ}, (Fin n → α) → Sort*}
    (h0 : P Fin.elim0)
    (h : ∀ {n} (x : Fin n → α) (x₀), P x → P (Fin.snoc x x₀)) : ∀ {n : ℕ} (x : Fin n → α), P x
  
goal: P x

full_name: Fin.succAboveCases
code: /-- Define a function on `Fin (n + 1)` from a value on `i : Fin (n + 1)` and values on each
`Fin.succAbove i j`, `j : Fin n`. This version is elaborated as eliminator and works for
propositions, see also `Fin.insertNth` for a version without an `@[elab_as_elim]`
attribute. -/
@[elab_as_elim]
def succAboveCases {α : Fin (n + 1) → Sort u} (i : Fin (n + 1)) (x : α i)
    (p : ∀ j : Fin n, α (i.succAbove j)) (j : Fin (n + 1)) : α j 
goal: α j

full_name: Fin.forall_iff_succAbove
code: theorem forall_iff_succAbove {p : Fin (n + 1) → Prop} (i : Fin (n + 1)) :
    (∀ j, p j) ↔ p i ∧ ∀ j, p (i.succAbove j) 
goal: (∀ (j : Fin (n + 1)), p j) ↔ p i ∧ ∀ (j : Fin n), p (i.succAbove j)

full_name: Fin.removeNth
code: /-- Remove the `p`-th entry of a tuple. -/
def removeNth (p : Fin (n + 1)) (f : ∀ i, α i) : ∀ i, α (p.succAbove i) 
goal: α (p.succAbove i)

full_name: Fin.insertNth
code: /-- Insert an element into a tuple at a given position. For `i = 0` see `Fin.cons`,
for `i = Fin.last n` see `Fin.snoc`. See also `Fin.succAboveCases` for a version elaborated
as an eliminator. -/
def insertNth (i : Fin (n + 1)) (x : α i) (p : ∀ j : Fin n, α (i.succAbove j)) (j : Fin (n + 1)) :
    α j 
goal: α j

full_name: Fin.insertNth_apply_same
code: @[simp]
theorem insertNth_apply_same (i : Fin (n + 1)) (x : α i) (p : ∀ j, α (i.succAbove j)) :
    insertNth i x p i = x 
goal: i.insertNth x p i = x

full_name: Fin.insertNth_apply_succAbove
code: @[simp]
theorem insertNth_apply_succAbove (i : Fin (n + 1)) (x : α i) (p : ∀ j, α (i.succAbove j))
    (j : Fin n) : insertNth i x p (i.succAbove j) = p j 
goal: i.insertNth x p (i.succAbove j) = p j

full_name: Fin.succAbove_cases_eq_insertNth
code: @[simp]
theorem succAbove_cases_eq_insertNth : @succAboveCases.{u + 1} = @insertNth.{u} 
goal: @Fin.succAboveCases = @Fin.insertNth

full_name: Fin.removeNth_insertNth
code: @[simp] lemma removeNth_insertNth (p : Fin (n + 1)) (a : α p) (f : ∀ i, α (succAbove p i)) :
    removeNth p (insertNth p a f) = f 
goal: p.removeNth (p.insertNth a f) = f

full_name: Fin.removeNth_zero
code: @[simp] lemma removeNth_zero (f : ∀ i, α i) : removeNth 0 f = tail f 
goal: Fin.removeNth 0 f = Fin.tail f

full_name: Fin.removeNth_last
code: @[simp] lemma removeNth_last {α : Type*} (f : Fin (n + 1) → α) : removeNth (last n) f = init f 
goal: (Fin.last n).removeNth f = Fin.init f

full_name: Fin.insertNth_comp_succAbove
code: @[simp]
theorem insertNth_comp_succAbove (i : Fin (n + 1)) (x : β) (p : Fin n → β) :
    insertNth i x p ∘ i.succAbove = p 
goal: i.insertNth x p ∘ i.succAbove = p

full_name: Fin.insertNth_eq_iff
code: theorem insertNth_eq_iff {p : Fin (n + 1)} {a : α p} {f : ∀ i, α (p.succAbove i)} {g : ∀ j, α j} :
    insertNth p a f = g ↔ a = g p ∧ f = removeNth p g 
goal: p.insertNth a f = g ↔ a = g p ∧ f = p.removeNth g

full_name: Fin.eq_insertNth_iff
code: theorem eq_insertNth_iff {p : Fin (n + 1)} {a : α p} {f : ∀ i, α (p.succAbove i)} {g : ∀ j, α j} :
    g = insertNth p a f ↔ g p = a ∧ removeNth p g = f 
goal: g = p.insertNth a f ↔ g p = a ∧ p.removeNth g = f

full_name: Fin.insertNth_apply_below
code: theorem insertNth_apply_below {i j : Fin (n + 1)} (h : j < i) (x : α i)
    (p : ∀ k, α (i.succAbove k)) :
    i.insertNth x p j = @Eq.recOn _ _ (fun x _ ↦ α x) _
    (succAbove_castPred_of_lt _ _ h) (p <| j.castPred _) 
goal: i.insertNth x p j = Eq.recOn ⋯ (p (j.castPred ⋯))

full_name: Fin.insertNth_apply_above
code: theorem insertNth_apply_above {i j : Fin (n + 1)} (h : i < j) (x : α i)
    (p : ∀ k, α (i.succAbove k)) :
    i.insertNth x p j = @Eq.recOn _ _ (fun x _ ↦ α x) _
    (succAbove_pred_of_lt _ _ h) (p <| j.pred _) 
goal: i.insertNth x p j = Eq.recOn ⋯ (p (j.pred ⋯))

full_name: Fin.insertNth_zero
code: theorem insertNth_zero (x : α 0) (p : ∀ j : Fin n, α (succAbove 0 j)) :
    insertNth 0 x p =
      cons x fun j ↦ _root_.cast (congr_arg α (congr_fun succAbove_zero j)) (p j) 
goal: Fin.insertNth 0 x p = Fin.cons x fun j => cast ⋯ (p j)

full_name: Fin.insertNth_zero'
code: @[simp]
theorem insertNth_zero' (x : β) (p : Fin n → β) : @insertNth _ (fun _ ↦ β) 0 x p = cons x p 
goal: Fin.insertNth 0 x p = Fin.cons x p

full_name: Fin.insertNth_last
code: theorem insertNth_last (x : α (last n)) (p : ∀ j : Fin n, α ((last n).succAbove j)) :
    insertNth (last n) x p =
      snoc (fun j ↦ _root_.cast (congr_arg α (succAbove_last_apply j)) (p j)) x 
goal: (Fin.last n).insertNth x p = Fin.snoc (fun j => cast ⋯ (p j)) x

full_name: Fin.insertNth_last'
code: @[simp]
theorem insertNth_last' (x : β) (p : Fin n → β) :
    @insertNth _ (fun _ ↦ β) (last n) x p = snoc p x 
goal: (Fin.last n).insertNth x p = Fin.snoc p x

full_name: Fin.insertNth_rev
code: lemma insertNth_rev {α : Type*} (i : Fin (n + 1)) (a : α) (f : Fin n → α) (j : Fin (n + 1)) :
    insertNth (α := fun _ ↦ α) i a f (rev j) = insertNth (α := fun _ ↦ α) i.rev a (f ∘ rev) j 
goal: i.insertNth a f j.rev = i.rev.insertNth a (f ∘ Fin.rev) j

full_name: Fin.insertNth_comp_rev
code: theorem insertNth_comp_rev {α} (i : Fin (n + 1)) (x : α) (p : Fin n → α) :
    (Fin.insertNth i x p) ∘ Fin.rev = Fin.insertNth (Fin.rev i) x (p ∘ Fin.rev) 
goal: i.insertNth x p ∘ Fin.rev = i.rev.insertNth x (p ∘ Fin.rev)

full_name: Fin.cons_rev
code: theorem cons_rev {α n} (a : α) (f : Fin n → α) (i : Fin <| n + 1) :
    cons (α := fun _ => α) a f i.rev = snoc (α := fun _ => α) (f ∘ Fin.rev : Fin _ → α) a i 
goal: Fin.cons a f i.rev = Fin.snoc (f ∘ Fin.rev) a i

full_name: Fin.cons_comp_rev
code: theorem cons_comp_rev {α n} (a : α) (f : Fin n → α) :
    Fin.cons a f ∘ Fin.rev = Fin.snoc (f ∘ Fin.rev) a 
goal: Fin.cons a f ∘ Fin.rev = Fin.snoc (f ∘ Fin.rev) a

full_name: Fin.snoc_rev
code: theorem snoc_rev {α n} (a : α) (f : Fin n → α) (i : Fin <| n + 1) :
    snoc (α := fun _ => α) f a i.rev = cons (α := fun _ => α) a (f ∘ Fin.rev : Fin _ → α) i 
goal: Fin.snoc f a i.rev = Fin.cons a (f ∘ Fin.rev) i

full_name: Fin.snoc_comp_rev
code: theorem snoc_comp_rev {α n} (a : α) (f : Fin n → α) :
    Fin.snoc f a ∘ Fin.rev = Fin.cons a (f ∘ Fin.rev) 
goal: Fin.snoc f a ∘ Fin.rev = Fin.cons a (f ∘ Fin.rev)

full_name: Fin.insertNth_binop
code: theorem insertNth_binop (op : ∀ j, α j → α j → α j) (i : Fin (n + 1)) (x y : α i)
    (p q : ∀ j, α (i.succAbove j)) :
    (i.insertNth (op i x y) fun j ↦ op _ (p j) (q j)) = fun j ↦
      op j (i.insertNth x p j) (i.insertNth y q j) 
goal: (i.insertNth (op i x y) fun j => op (i.succAbove j) (p j) (q j)) = fun j => op j (i.insertNth x p j) (i.insertNth y q j)

full_name: Fin.insertNth_le_iff
code: theorem insertNth_le_iff {i : Fin (n + 1)} {x : α i} {p : ∀ j, α (i.succAbove j)} {q : ∀ j, α j} :
    i.insertNth x p ≤ q ↔ x ≤ q i ∧ p ≤ fun j ↦ q (i.succAbove j) 
goal: i.insertNth x p ≤ q ↔ x ≤ q i ∧ p ≤ fun j => q (i.succAbove j)

full_name: Fin.le_insertNth_iff
code: theorem le_insertNth_iff {i : Fin (n + 1)} {x : α i} {p : ∀ j, α (i.succAbove j)} {q : ∀ j, α j} :
    q ≤ i.insertNth x p ↔ q i ≤ x ∧ (fun j ↦ q (i.succAbove j)) ≤ p 
goal: q ≤ i.insertNth x p ↔ q i ≤ x ∧ (fun j => q (i.succAbove j)) ≤ p

full_name: Fin.removeNth_update
code: @[simp] lemma removeNth_update (p : Fin (n + 1)) (x) (f : ∀ j, α j) :
    removeNth p (update f p x) = removeNth p f 
goal: p.removeNth (Function.update f p x) = p.removeNth f

full_name: Fin.insertNth_removeNth
code: @[simp] lemma insertNth_removeNth (p : Fin (n + 1)) (x) (f : ∀ j, α j) :
    insertNth p x (removeNth p f) = update f p x 
goal: p.insertNth x (p.removeNth f) = Function.update f p x

full_name: Fin.insertNth_self_removeNth
code: lemma insertNth_self_removeNth (p : Fin (n + 1)) (f : ∀ j, α j) :
    insertNth p (f p) (removeNth p f) = f 
goal: p.insertNth (f p) (p.removeNth f) = f

full_name: Fin.extractNth
code: /-- Separates an `n+1`-tuple, returning a selected index and then the rest of the tuple.
Functional form of `Equiv.piFinSuccAbove`. -/
@[deprecated removeNth (since := "2024-06-19")]
def extractNth (i : Fin (n + 1)) (f : (∀ j, α j)) :
    α i × ∀ j, α (i.succAbove j) 
goal: α i × ((j : Fin n) → α (i.succAbove j))

full_name: Fin.find
code: /-- `find p` returns the first index `n` where `p n` is satisfied, and `none` if it is never
satisfied. -/
def find : ∀ {n : ℕ} (p : Fin n → Prop) [DecidablePred p], Option (Fin n)
  
goal: Option (Fin n)

full_name: Fin.find_spec
code: /-- If `find p = some i`, then `p i` holds -/
theorem find_spec :
    ∀ {n : ℕ} (p : Fin n → Prop) [DecidablePred p] {i : Fin n} (_ : i ∈ Fin.find p), p i
  
goal: i ∈ Fin.find p → p i

full_name: Fin.isSome_find_iff
code: /-- `find p` does not return `none` if and only if `p i` holds at some index `i`. -/
theorem isSome_find_iff :
    ∀ {n : ℕ} {p : Fin n → Prop} [DecidablePred p], (find p).isSome ↔ ∃ i, p i
  
goal: (Fin.find p).isSome = true ↔ ∃ i, p i

full_name: Fin.find_eq_none_iff
code: /-- `find p` returns `none` if and only if `p i` never holds. -/
theorem find_eq_none_iff {n : ℕ} {p : Fin n → Prop} [DecidablePred p] :
    find p = none ↔ ∀ i, ¬p i 
goal: Fin.find p = none ↔ ∀ (i : Fin n), ¬p i

full_name: Fin.find_min
code: /-- If `find p` returns `some i`, then `p j` does not hold for `j < i`, i.e., `i` is minimal among
the indices where `p` holds. -/
theorem find_min :
    ∀ {n : ℕ} {p : Fin n → Prop} [DecidablePred p] {i : Fin n} (_ : i ∈ Fin.find p) {j : Fin n}
      (_ : j < i), ¬p j
  
goal: i ∈ Fin.find p → ∀ {j : Fin n}, j < i → ¬p j

full_name: Fin.find_min'
code: theorem find_min' {p : Fin n → Prop} [DecidablePred p] {i : Fin n} (h : i ∈ Fin.find p) {j : Fin n}
    (hj : p j) : i ≤ j 
goal: i ≤ j

full_name: Fin.nat_find_mem_find
code: theorem nat_find_mem_find {p : Fin n → Prop} [DecidablePred p]
    (h : ∃ i, ∃ hin : i < n, p ⟨i, hin⟩) :
    (⟨Nat.find h, (Nat.find_spec h).fst⟩ : Fin n) ∈ find p 
goal: ⟨Nat.find h, ⋯⟩ ∈ Fin.find p

full_name: Fin.mem_find_iff
code: theorem mem_find_iff {p : Fin n → Prop} [DecidablePred p] {i : Fin n} :
    i ∈ Fin.find p ↔ p i ∧ ∀ j, p j → i ≤ j 
goal: i ∈ Fin.find p ↔ p i ∧ ∀ (j : Fin n), p j → i ≤ j

full_name: Fin.find_eq_some_iff
code: theorem find_eq_some_iff {p : Fin n → Prop} [DecidablePred p] {i : Fin n} :
    Fin.find p = some i ↔ p i ∧ ∀ j, p j → i ≤ j 
goal: Fin.find p = some i ↔ p i ∧ ∀ (j : Fin n), p j → i ≤ j

full_name: Fin.mem_find_of_unique
code: theorem mem_find_of_unique {p : Fin n → Prop} [DecidablePred p] (h : ∀ i j, p i → p j → i = j)
    {i : Fin n} (hi : p i) : i ∈ Fin.find p 
goal: i ∈ Fin.find p

full_name: Fin.contractNth
code: /-- Sends `(g₀, ..., gₙ)` to `(g₀, ..., op gⱼ gⱼ₊₁, ..., gₙ)`. -/
def contractNth (j : Fin (n + 1)) (op : α → α → α) (g : Fin (n + 1) → α) (k : Fin n) : α 
goal: α

full_name: Fin.contractNth_apply_of_lt
code: theorem contractNth_apply_of_lt (j : Fin (n + 1)) (op : α → α → α) (g : Fin (n + 1) → α) (k : Fin n)
    (h : (k : ℕ) < j) : contractNth j op g k = g (Fin.castSucc k) 
goal: j.contractNth op g k = g k.castSucc

full_name: Fin.contractNth_apply_of_eq
code: theorem contractNth_apply_of_eq (j : Fin (n + 1)) (op : α → α → α) (g : Fin (n + 1) → α) (k : Fin n)
    (h : (k : ℕ) = j) : contractNth j op g k = op (g (Fin.castSucc k)) (g k.succ) 
goal: j.contractNth op g k = op (g k.castSucc) (g k.succ)

full_name: Fin.contractNth_apply_of_gt
code: theorem contractNth_apply_of_gt (j : Fin (n + 1)) (op : α → α → α) (g : Fin (n + 1) → α) (k : Fin n)
    (h : (j : ℕ) < k) : contractNth j op g k = g k.succ 
goal: j.contractNth op g k = g k.succ

full_name: Fin.contractNth_apply_of_ne
code: theorem contractNth_apply_of_ne (j : Fin (n + 1)) (op : α → α → α) (g : Fin (n + 1) → α) (k : Fin n)
    (hjk : (j : ℕ) ≠ k) : contractNth j op g k = g (j.succAbove k) 
goal: j.contractNth op g k = g (j.succAbove k)

full_name: Fin.sigma_eq_of_eq_comp_cast
code: /-- To show two sigma pairs of tuples agree, it to show the second elements are related via
`Fin.cast`. -/
theorem sigma_eq_of_eq_comp_cast {α : Type*} :
    ∀ {a b : Σii, Fin ii → α} (h : a.fst = b.fst), a.snd = b.snd ∘ Fin.cast h → a = b
  
goal: a.snd = b.snd ∘ Fin.cast h → a = b

full_name: Fin.sigma_eq_iff_eq_comp_cast
code: /-- `Fin.sigma_eq_of_eq_comp_cast` as an `iff`. -/
theorem sigma_eq_iff_eq_comp_cast {α : Type*} {a b : Σii, Fin ii → α} :
    a = b ↔ ∃ h : a.fst = b.fst, a.snd = b.snd ∘ Fin.cast h 
goal: a = b ↔ ∃ (h : a.fst = b.fst), a.snd = b.snd ∘ Fin.cast h