Module docstring
{"# Additional theorems and definitions about the Vector type
This file introduces the infix notation ::ᵥ for Vector.cons.
"}
{"# Additional theorems and definitions about the Vector type
This file introduces the infix notation ::ᵥ for Vector.cons.
"}
List.Vector.term_::ᵥ_
      definition
     : Lean.TrailingParserDescr✝
        @[inherit_doc]
infixr:67 " ::ᵥ " => Vector.cons
        List.Vector.instInhabited
      instance
     [Inhabited α] : Inhabited (Vector α n)
        instance [Inhabited α] : Inhabited (Vector α n) :=
  ⟨ofFn default⟩
        List.Vector.toList_injective
      theorem
     : Function.Injective (@toList α n)
        theorem toList_injective : Function.Injective (@toList α n) :=
  Subtype.val_injective
        List.Vector.ext
      theorem
     : ∀ {v w : Vector α n} (_ : ∀ m : Fin n, Vector.get v m = Vector.get w m), v = w
        /-- Two `v w : Vector α n` are equal iff they are equal at every single index. -/
@[ext]
theorem ext : ∀ {v w : Vector α n} (_ : ∀ m : Fin n, Vector.get v m = Vector.get w m), v = w
  | ⟨v, hv⟩, ⟨w, hw⟩, h =>
    Subtype.eq (List.ext_get (by rw [hv, hw]) fun m hm _ => h ⟨m, hv ▸ hm⟩)
        List.Vector.zero_subsingleton
      instance
     : Subsingleton (Vector α 0)
        /-- The empty `Vector` is a `Subsingleton`. -/
instance zero_subsingleton : Subsingleton (Vector α 0) :=
  ⟨fun _ _ => Vector.ext fun m => Fin.elim0 m⟩
        List.Vector.cons_val
      theorem
     (a : α) : ∀ v : Vector α n, (a ::ᵥ v).val = a :: v.val
        @[simp]
theorem cons_val (a : α) : ∀ v : Vector α n, (a ::ᵥ v).val = a :: v.val
  | ⟨_, _⟩ => rfl
        List.Vector.ne_cons_iff
      theorem
     (a : α) (v : Vector α n.succ) (v' : Vector α n) : v ≠ a ::ᵥ v' ↔ v.head ≠ a ∨ v.tail ≠ v'
        theorem ne_cons_iff (a : α) (v : Vector α n.succ) (v' : Vector α n) :
    v ≠ a ::ᵥ v'v ≠ a ::ᵥ v' ↔ v.head ≠ a ∨ v.tail ≠ v' := by rw [Ne, eq_cons_iff a v v', not_and_or]
        List.Vector.exists_eq_cons
      theorem
     (v : Vector α n.succ) : ∃ (a : α) (as : Vector α n), v = a ::ᵥ as
        theorem exists_eq_cons (v : Vector α n.succ) : ∃ (a : α) (as : Vector α n), v = a ::ᵥ as :=
  ⟨v.head, v.tail, (eq_cons_iff v.head v v.tail).2 ⟨rfl, rfl⟩⟩
        List.Vector.toList_ofFn
      theorem
     : ∀ {n} (f : Fin n → α), toList (ofFn f) = List.ofFn f
        @[simp]
theorem toList_ofFn : ∀ {n} (f : Fin n → α), toList (ofFn f) = List.ofFn f
  | 0, f => by rw [ofFn, List.ofFn_zero, toList, nil]
  | n + 1, f => by rw [ofFn, List.ofFn_succ, toList_cons, toList_ofFn]
        List.Vector.mk_toList
      theorem
     : ∀ (v : Vector α n) (h), (⟨toList v, h⟩ : Vector α n) = v
        @[simp]
theorem mk_toList : ∀ (v : Vector α n) (h), (⟨toList v, h⟩ : Vector α n) = v
  | ⟨_, _⟩, _ => rfl
        List.Vector.length_val
      theorem
     (v : Vector α n) : v.val.length = n
        @[simp] theorem length_val (v : Vector α n) : v.val.length = n := v.2
        List.Vector.pmap_cons
      theorem
     {p : α → Prop} (f : (a : α) → p a → β) (a : α) (v : Vector α n) (hp : ∀ x ∈ (cons a v).toList, p x) :
  (cons a v).pmap f hp =
    cons
      (f a
        (by
          simp only [Nat.succ_eq_add_one, toList_cons, List.mem_cons, forall_eq_or_imp] at hp
          exact hp.1))
      (v.pmap f
        (by
          simp only [Nat.succ_eq_add_one, toList_cons, List.mem_cons, forall_eq_or_imp] at hp
          exact hp.2))
        @[simp]
theorem pmap_cons {p : α → Prop} (f : (a : α) → p a → β) (a : α) (v : Vector α n)
    (hp : ∀ x ∈ (cons a v).toList, p x) :
    (cons a v).pmap f hp = cons (f a (by
      simp only [Nat.succ_eq_add_one, toList_cons, List.mem_cons, forall_eq_or_imp] at hp
      exact hp.1))
      (v.pmap f (by
        simp only [Nat.succ_eq_add_one, toList_cons, List.mem_cons, forall_eq_or_imp] at hp
        exact hp.2)) := rfl
        List.Vector.pmap_cons'
      theorem
     {p : α → Prop} (f : (a : α) → p a → β) (a : α) (v : Vector α n) (ha : p a) (hp : ∀ x ∈ v.toList, p x) :
  cons (f a ha) (v.pmap f hp) = (cons a v).pmap f (by simpa [ha])
        /-- Opposite direction of `Vector.pmap_cons` -/
theorem pmap_cons' {p : α → Prop} (f : (a : α) → p a → β) (a : α) (v : Vector α n)
    (ha : p a) (hp : ∀ x ∈ v.toList, p x) :
    cons (f a ha) (v.pmap f hp) = (cons a v).pmap f (by simpa [ha]) := rfl
        List.Vector.toList_map
      theorem
     {β : Type*} (v : Vector α n) (f : α → β) : (v.map f).toList = v.toList.map f
        
      List.Vector.head_map
      theorem
     {β : Type*} (v : Vector α (n + 1)) (f : α → β) : (v.map f).head = f v.head
        
      List.Vector.tail_map
      theorem
     {β : Type*} (v : Vector α (n + 1)) (f : α → β) : (v.map f).tail = v.tail.map f
        
      List.Vector.getElem_map
      theorem
     {β : Type*} (v : Vector α n) (f : α → β) {i : ℕ} (hi : i < n) : (v.map f)[i] = f v[i]
        @[simp]
theorem getElem_map {β : Type*} (v : Vector α n) (f : α → β) {i : ℕ} (hi : i < n) :
    (v.map f)[i] = f v[i] := by
  simp only [getElem_def, toList_map, List.getElem_map]
        List.Vector.toList_pmap
      theorem
     {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α n) (hp : ∀ x ∈ v.toList, p x) :
  (v.pmap f hp).toList = v.toList.pmap f hp
        @[simp]
theorem toList_pmap {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α n)
    (hp : ∀ x ∈ v.toList, p x) :
    (v.pmap f hp).toList = v.toList.pmap f hp := by cases v; rfl
        List.Vector.head_pmap
      theorem
     {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α (n + 1)) (hp : ∀ x ∈ v.toList, p x) :
  (v.pmap f hp).head =
    f v.head (hp _ <| by rw [← cons_head_tail v, toList_cons, head_cons, List.mem_cons]; exact .inl rfl)
        @[simp]
theorem head_pmap {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α (n + 1))
    (hp : ∀ x ∈ v.toList, p x) :
    (v.pmap f hp).head = f v.head (hp _ <| by
      rw [← cons_head_tail v, toList_cons, head_cons, List.mem_cons]; exact .inl rfl) := by
  obtain ⟨a, v', h⟩ := Vector.exists_eq_cons v
  simp_rw [h, pmap_cons, head_cons]
        List.Vector.tail_pmap
      theorem
     {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α (n + 1)) (hp : ∀ x ∈ v.toList, p x) :
  (v.pmap f hp).tail =
    v.tail.pmap f (fun x hx ↦ hp _ <| by rw [← cons_head_tail v, toList_cons, List.mem_cons]; exact .inr hx)
        @[simp]
theorem tail_pmap {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α (n + 1))
    (hp : ∀ x ∈ v.toList, p x) :
    (v.pmap f hp).tail = v.tail.pmap f (fun x hx ↦ hp _ <| by
      rw [← cons_head_tail v, toList_cons, List.mem_cons]; exact .inr hx) := by
  obtain ⟨a, v', h⟩ := Vector.exists_eq_cons v
  simp_rw [h, pmap_cons, tail_cons]
        List.Vector.getElem_pmap
      theorem
     {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α n) (hp : ∀ x ∈ v.toList, p x) {i : ℕ} (hi : i < n) :
  (v.pmap f hp)[i] = f v[i] (hp _ (by simp [getElem_def, List.getElem_mem]))
        @[simp]
theorem getElem_pmap {p : α → Prop} (f : (a : α) → p a → β) (v : Vector α n)
    (hp : ∀ x ∈ v.toList, p x) {i : ℕ} (hi : i < n) :
    (v.pmap f hp)[i] = f v[i] (hp _ (by simp [getElem_def, List.getElem_mem])) := by
  simp only [getElem_def, toList_pmap, List.getElem_pmap]
        List.Vector.get_eq_get_toList
      theorem
     (v : Vector α n) (i : Fin n) : v.get i = v.toList.get (Fin.cast v.toList_length.symm i)
        theorem get_eq_get_toList (v : Vector α n) (i : Fin n) :
    v.get i = v.toList.get (Fin.cast v.toList_length.symm i) :=
  rfl
        List.Vector.get_replicate
      theorem
     (a : α) (i : Fin n) : (Vector.replicate n a).get i = a
        @[simp]
theorem get_replicate (a : α) (i : Fin n) : (Vector.replicate n a).get i = a := by
  apply List.getElem_replicate
        List.Vector.get_map
      theorem
     {β : Type*} (v : Vector α n) (f : α → β) (i : Fin n) : (v.map f).get i = f (v.get i)
        @[simp]
theorem get_map {β : Type*} (v : Vector α n) (f : α → β) (i : Fin n) :
    (v.map f).get i = f (v.get i) := by
  cases v; simp [Vector.map, get_eq_get_toList]
        List.Vector.map₂_nil
      theorem
     (f : α → β → γ) : Vector.map₂ f nil nil = nil
        
      List.Vector.map₂_cons
      theorem
     (hd₁ : α) (tl₁ : Vector α n) (hd₂ : β) (tl₂ : Vector β n) (f : α → β → γ) :
  Vector.map₂ f (hd₁ ::ᵥ tl₁) (hd₂ ::ᵥ tl₂) = f hd₁ hd₂ ::ᵥ (Vector.map₂ f tl₁ tl₂)
        @[simp]
theorem map₂_cons (hd₁ : α) (tl₁ : Vector α n) (hd₂ : β) (tl₂ : Vector β n) (f : α → β → γ) :
    Vector.map₂ f (hd₁ ::ᵥ tl₁) (hd₂ ::ᵥ tl₂) = f hd₁ hd₂ ::ᵥ (Vector.map₂ f tl₁ tl₂) :=
  rfl
        List.Vector.get_ofFn
      theorem
     {n} (f : Fin n → α) (i) : get (ofFn f) i = f i
        @[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f i := by
  conv_rhs => erw [← List.get_ofFn f ⟨i, by simp⟩]
  simp only [get_eq_get_toList]
  congr <;> simp [Fin.heq_ext_iff]
        List.Vector.ofFn_get
      theorem
     (v : Vector α n) : ofFn (get v) = v
        @[simp]
theorem ofFn_get (v : Vector α n) : ofFn (get v) = v := by
  rcases v with ⟨l, rfl⟩
  apply toList_injective
  dsimp
  simpa only [toList_ofFn] using List.ofFn_get _
        Equiv.vectorEquivFin
      definition
     (α : Type*) (n : ℕ) : Vector α n ≃ (Fin n → α)
        /-- The natural equivalence between length-`n` vectors and functions from `Fin n`. -/
def _root_.Equiv.vectorEquivFin (α : Type*) (n : ℕ) : VectorVector α n ≃ (Fin n → α) :=
  ⟨Vector.get, Vector.ofFn, Vector.ofFn_get, fun f => funext <| Vector.get_ofFn f⟩
        List.Vector.get_tail
      theorem
     (x : Vector α n) (i) : x.tail.get i = x.get ⟨i.1 + 1, by omega⟩
        theorem get_tail (x : Vector α n) (i) : x.tail.get i = x.get ⟨i.1 + 1, by omega⟩ := by
  obtain ⟨i, ih⟩ := i; dsimp
  rcases x with ⟨_ | _, h⟩ <;> try rfl
  rw [List.length] at h
  rw [← h] at ih
  contradiction
        List.Vector.get_tail_succ
      theorem
     : ∀ (v : Vector α n.succ) (i : Fin n), get (tail v) i = get v i.succ
        @[simp]
theorem get_tail_succ : ∀ (v : Vector α n.succ) (i : Fin n), get (tail v) i = get v i.succ
  | ⟨a :: l, e⟩, ⟨i, h⟩ => by simp [get_eq_get_toList]; rfl
        List.Vector.tail_val
      theorem
     : ∀ v : Vector α n.succ, v.tail.val = v.val.tail
        
      List.Vector.tail_nil
      theorem
     : (@nil α).tail = nil
        
      List.Vector.singleton_tail
      theorem
     : ∀ (v : Vector α 1), v.tail = Vector.nil
        /-- The `tail` of a vector made up of one element is `nil`. -/
@[simp]
theorem singleton_tail : ∀ (v : Vector α 1), v.tail = Vector.nil
  | ⟨[_], _⟩ => rfl
        List.Vector.tail_ofFn
      theorem
     {n : ℕ} (f : Fin n.succ → α) : tail (ofFn f) = ofFn fun i => f i.succ
        
      List.Vector.toList_empty
      theorem
     (v : Vector α 0) : v.toList = []
        @[simp]
theorem toList_empty (v : Vector α 0) : v.toList = [] :=
  List.length_eq_zero_iff.mp v.2
        List.Vector.toList_singleton
      theorem
     (v : Vector α 1) : v.toList = [v.head]
        /-- The list that makes up a `Vector` made up of a single element,
retrieved via `toList`, is equal to the list of that single element. -/
@[simp]
theorem toList_singleton (v : Vector α 1) : v.toList = [v.head] := by
  rw [← v.cons_head_tail]
  simp only [toList_cons, toList_nil, head_cons, eq_self_iff_true, and_self_iff, singleton_tail]
        List.Vector.empty_toList_eq_ff
      theorem
     (v : Vector α (n + 1)) : v.toList.isEmpty = false
        
      List.Vector.not_empty_toList
      theorem
     (v : Vector α (n + 1)) : ¬v.toList.isEmpty
        theorem not_empty_toList (v : Vector α (n + 1)) : ¬v.toList.isEmpty := by
  simp only [empty_toList_eq_ff, Bool.coe_sort_false, not_false_iff]
        List.Vector.map_id
      theorem
     {n : ℕ} (v : Vector α n) : Vector.map id v = v
        /-- Mapping under `id` does not change a vector. -/
@[simp]
theorem map_id {n : ℕ} (v : Vector α n) : Vector.map id v = v :=
  Vector.eq _ _ (by simp only [List.map_id, Vector.toList_map])
        List.Vector.nodup_iff_injective_get
      theorem
     {v : Vector α n} : v.toList.Nodup ↔ Function.Injective v.get
        theorem nodup_iff_injective_get {v : Vector α n} : v.toList.Nodup ↔ Function.Injective v.get := by
  obtain ⟨l, hl⟩ := v
  subst hl
  exact List.nodup_iff_injective_get
        List.Vector.head?_toList
      theorem
     : ∀ v : Vector α n.succ, (toList v).head? = some (head v)
        
      List.Vector.reverse
      definition
     (v : Vector α n) : Vector α n
        /-- Reverse a vector. -/
def reverse (v : Vector α n) : Vector α n :=
  ⟨v.toList.reverse, by simp⟩
        List.Vector.toList_reverse
      theorem
     {v : Vector α n} : v.reverse.toList = v.toList.reverse
        
      List.Vector.reverse_reverse
      theorem
     {v : Vector α n} : v.reverse.reverse = v
        @[simp]
theorem reverse_reverse {v : Vector α n} : v.reverse.reverse = v := by
  cases v
  simp [Vector.reverse]
        List.Vector.get_zero
      theorem
     : ∀ v : Vector α n.succ, get v 0 = head v
        
      List.Vector.head_ofFn
      theorem
     {n : ℕ} (f : Fin n.succ → α) : head (ofFn f) = f 0
        
      List.Vector.get_cons_zero
      theorem
     (a : α) (v : Vector α n) : get (a ::ᵥ v) 0 = a
        theorem get_cons_zero (a : α) (v : Vector α n) : get (a ::ᵥ v) 0 = a := by simp [get_zero]
        List.Vector.get_cons_nil
      theorem
     : ∀ {ix : Fin 1} (x : α), get (x ::ᵥ nil) ix = x
        /-- Accessing the nth element of a vector made up
of one element `x : α` is `x` itself. -/
@[simp]
theorem get_cons_nil : ∀ {ix : Fin 1} (x : α), get (x ::ᵥ nil) ix = x
  | ⟨0, _⟩, _ => rfl
        List.Vector.get_cons_succ
      theorem
     (a : α) (v : Vector α n) (i : Fin n) : get (a ::ᵥ v) i.succ = get v i
        @[simp]
theorem get_cons_succ (a : α) (v : Vector α n) (i : Fin n) : get (a ::ᵥ v) i.succ = get v i := by
  rw [← get_tail_succ, tail_cons]
        List.Vector.last
      definition
     (v : Vector α (n + 1)) : α
        
      List.Vector.last_def
      theorem
     {v : Vector α (n + 1)} : v.last = v.get (Fin.last n)
        
      List.Vector.reverse_get_zero
      theorem
     {v : Vector α (n + 1)} : v.reverse.head = v.last
        /-- The `last` element of a vector is the `head` of the `reverse` vector. -/
theorem reverse_get_zero {v : Vector α (n + 1)} : v.reverse.head = v.last := by
  rw [← get_zero, last_def, get_eq_get_toList, get_eq_get_toList]
  simp_rw [toList_reverse]
  rw [List.get_eq_getElem, List.get_eq_getElem, ← Option.some_inj, Fin.cast, Fin.cast,
    ← List.getElem?_eq_getElem, ← List.getElem?_eq_getElem, List.getElem?_reverse]
  · congr
    simp
  · simp
        List.Vector.scanl
      definition
     : Vector β (n + 1)
        /-- Construct a `Vector β (n + 1)` from a `Vector α n` by scanning `f : β → α → β`
from the "left", that is, from 0 to `Fin.last n`, using `b : β` as the starting value.
-/
def scanl : Vector β (n + 1) :=
  ⟨List.scanl f b v.toList, by rw [List.length_scanl, toList_length]⟩
        List.Vector.scanl_nil
      theorem
     : scanl f b nil = b ::ᵥ nil
        
      List.Vector.scanl_cons
      theorem
     (x : α) : scanl f b (x ::ᵥ v) = b ::ᵥ scanl f (f b x) v
        /-- The recursive step of `scanl` splits a vector `x ::ᵥ v : Vector α (n + 1)`
into the provided starting value `b : β` and the recursed `scanl`
`f b x : β` as the starting value.
This lemma is the `cons` version of `scanl_get`.
-/
@[simp]
theorem scanl_cons (x : α) : scanl f b (x ::ᵥ v) = b ::ᵥ scanl f (f b x) v := by
  simp only [scanl, toList_cons, List.scanl]; dsimp
  simp only [cons]
        List.Vector.scanl_val
      theorem
     : ∀ {v : Vector α n}, (scanl f b v).val = List.scanl f b v.val
        
      List.Vector.toList_scanl
      theorem
     : (scanl f b v).toList = List.scanl f b v.toList
        /-- The `toList` of a `Vector` after a `scanl` is the `List.scanl`
of the `toList` of the original `Vector`.
-/
@[simp]
theorem toList_scanl : (scanl f b v).toList = List.scanl f b v.toList :=
  rfl
        List.Vector.scanl_singleton
      theorem
     (v : Vector α 1) : scanl f b v = b ::ᵥ f b v.head ::ᵥ nil
        /-- The recursive step of `scanl` splits a vector made up of a single element
`x ::ᵥ nil : Vector α 1` into a `Vector` of the provided starting value `b : β`
and the mapped `f b x : β` as the last value.
-/
@[simp]
theorem scanl_singleton (v : Vector α 1) : scanl f b v = b ::ᵥ f b v.head ::ᵥ nil := by
  rw [← cons_head_tail v]
  simp only [scanl_cons, scanl_nil, head_cons, singleton_tail]
        List.Vector.scanl_head
      theorem
     : (scanl f b v).head = b
        /-- The first element of `scanl` of a vector `v : Vector α n`,
retrieved via `head`, is the starting value `b : β`.
-/
@[simp]
theorem scanl_head : (scanl f b v).head = b := by
  cases n
  · have : v = nil := by simp only [eq_iff_true_of_subsingleton]
    simp only [this, scanl_nil, head_cons]
  · rw [← cons_head_tail v]
    simp [← get_zero, get_eq_get_toList]
        List.Vector.scanl_get
      theorem
     (i : Fin n) : (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i)
        /-- For an index `i : Fin n`, the nth element of `scanl` of a
vector `v : Vector α n` at `i.succ`, is equal to the application
function `f : β → α → β` of the `castSucc i` element of
`scanl f b v` and `get v i`.
This lemma is the `get` version of `scanl_cons`.
-/
@[simp]
theorem scanl_get (i : Fin n) :
    (scanl f b v).get i.succ = f ((scanl f b v).get (Fin.castSucc i)) (v.get i) := by
  rcases n with - | n
  · exact i.elim0
  induction' n with n hn generalizing b
  · have i0 : i = 0 := Fin.eq_zero _
    simp [scanl_singleton, i0, get_zero]; simp [get_eq_get_toList, List.get]
  · rw [← cons_head_tail v, scanl_cons, get_cons_succ]
    refine Fin.cases ?_ ?_ i
    · simp only [get_zero, scanl_head, Fin.castSucc_zero, head_cons]
    · intro i'
      simp only [hn, Fin.castSucc_fin_succ, get_cons_succ]
        List.Vector.mOfFn
      definition
     {m} [Monad m] {α : Type u} : ∀ {n}, (Fin n → m α) → m (Vector α n)
        /-- Monadic analog of `Vector.ofFn`.
Given a monadic function on `Fin n`, return a `Vector α n` inside the monad. -/
def mOfFn {m} [Monad m] {α : Type u} : ∀ {n}, (Fin n → m α) → m (Vector α n)
  | 0, _ => pure nil
  | _ + 1, f => do
    let a ← f 0
    let v ← mOfFn fun i => f i.succ
    pure (a ::ᵥ v)
        List.Vector.mOfFn_pure
      theorem
     {m} [Monad m] [LawfulMonad m] {α} : ∀ {n} (f : Fin n → α), (@mOfFn m _ _ _ fun i => pure (f i)) = pure (ofFn f)
        theorem mOfFn_pure {m} [Monad m] [LawfulMonad m] {α} :
    ∀ {n} (f : Fin n → α), (@mOfFn m _ _ _ fun i => pure (f i)) = pure (ofFn f)
  | 0, _ => rfl
  | n + 1, f => by
    rw [mOfFn, @mOfFn_pure m _ _ _ n _, ofFn]
    simp
        List.Vector.mmap
      definition
     {m} [Monad m] {α} {β : Type u} (f : α → m β) : ∀ {n}, Vector α n → m (Vector β n)
        
      List.Vector.mmap_nil
      theorem
     {m} [Monad m] {α β} (f : α → m β) : mmap f nil = pure nil
        
      List.Vector.mmap_cons
      theorem
     {m} [Monad m] {α β} (f : α → m β) (a) :
  ∀ {n} (v : Vector α n),
    mmap f (a ::ᵥ v) = do
      let h' ← f a
      let t' ← mmap f v
      pure (h' ::ᵥ t')
        @[simp]
theorem mmap_cons {m} [Monad m] {α β} (f : α → m β) (a) :
    ∀ {n} (v : Vector α n),
      mmap f (a ::ᵥ v) = do
        let h' ← f a
        let t' ← mmap f v
        pure (h' ::ᵥ t')
  | _, ⟨_, rfl⟩ => rfl
        List.Vector.inductionOn
      definition
     {C : ∀ {n : ℕ}, Vector α n → Sort*} {n : ℕ} (v : Vector α n) (nil : C nil)
  (cons : ∀ {n : ℕ} {x : α} {w : Vector α n}, C w → C (x ::ᵥ w)) : C v
        /--
Define `C v` by induction on `v : Vector α n`.
This function has two arguments: `nil` handles the base case on `C nil`,
and `cons` defines the inductive step using `∀ x : α, C w → C (x ::ᵥ w)`.
It is used as the default induction principle for the `induction` tactic.
-/
@[elab_as_elim, induction_eliminator]
def inductionOn {C : ∀ {n : ℕ}, Vector α n → Sort*} {n : ℕ} (v : Vector α n)
    (nil : C nil) (cons : ∀ {n : ℕ} {x : α} {w : Vector α n}, C w → C (x ::ᵥ w)) : C v := by
  induction' n with n ih
  · rcases v with ⟨_ | ⟨-, -⟩, - | -⟩
    exact nil
  · rcases v with ⟨_ | ⟨a, v⟩, v_property⟩
    cases v_property
    exact cons (ih ⟨v, (add_left_inj 1).mp v_property⟩)
        List.Vector.inductionOn_nil
      theorem
     {C : ∀ {n : ℕ}, Vector α n → Sort*} (nil : C nil) (cons : ∀ {n : ℕ} {x : α} {w : Vector α n}, C w → C (x ::ᵥ w)) :
  Vector.nil.inductionOn nil cons = nil
        @[simp]
theorem inductionOn_nil {C : ∀ {n : ℕ}, Vector α n → Sort*}
    (nil : C nil) (cons : ∀ {n : ℕ} {x : α} {w : Vector α n}, C w → C (x ::ᵥ w)) :
    Vector.nil.inductionOn nil cons = nil :=
  rfl
        List.Vector.inductionOn_cons
      theorem
     {C : ∀ {n : ℕ}, Vector α n → Sort*} {n : ℕ} (x : α) (v : Vector α n) (nil : C nil)
  (cons : ∀ {n : ℕ} {x : α} {w : Vector α n}, C w → C (x ::ᵥ w)) :
  (x ::ᵥ v).inductionOn nil cons = cons (v.inductionOn nil cons : C v)
        @[simp]
theorem inductionOn_cons {C : ∀ {n : ℕ}, Vector α n → Sort*} {n : ℕ} (x : α) (v : Vector α n)
    (nil : C nil) (cons : ∀ {n : ℕ} {x : α} {w : Vector α n}, C w → C (x ::ᵥ w)) :
    (x ::ᵥ v).inductionOn nil cons = cons (v.inductionOn nil cons : C v) :=
  rfl
        List.Vector.inductionOn₂
      definition
     {C : ∀ {n}, Vector α n → Vector β n → Sort*} (v : Vector α n) (w : Vector β n) (nil : C nil nil)
  (cons : ∀ {n a b} {x : Vector α n} {y}, C x y → C (a ::ᵥ x) (b ::ᵥ y)) : C v w
        /-- Define `C v w` by induction on a pair of vectors `v : Vector α n` and `w : Vector β n`. -/
@[elab_as_elim]
def inductionOn₂ {C : ∀ {n}, Vector α n → Vector β n → Sort*}
    (v : Vector α n) (w : Vector β n)
    (nil : C nil nil) (cons : ∀ {n a b} {x : Vector α n} {y}, C x y → C (a ::ᵥ x) (b ::ᵥ y)) :
    C v w := by
  induction' n with n ih
  · rcases v with ⟨_ | ⟨-, -⟩, - | -⟩
    rcases w with ⟨_ | ⟨-, -⟩, - | -⟩
    exact nil
  · rcases v with ⟨_ | ⟨a, v⟩, v_property⟩
    cases v_property
    rcases w with ⟨_ | ⟨b, w⟩, w_property⟩
    cases w_property
    apply @cons n _ _ ⟨v, (add_left_inj 1).mp v_property⟩ ⟨w, (add_left_inj 1).mp w_property⟩
    apply ih
        List.Vector.inductionOn₃
      definition
     {C : ∀ {n}, Vector α n → Vector β n → Vector γ n → Sort*} (u : Vector α n) (v : Vector β n) (w : Vector γ n)
  (nil : C nil nil nil) (cons : ∀ {n a b c} {x : Vector α n} {y z}, C x y z → C (a ::ᵥ x) (b ::ᵥ y) (c ::ᵥ z)) : C u v w
        /-- Define `C u v w` by induction on a triplet of vectors
`u : Vector α n`, `v : Vector β n`, and `w : Vector γ b`. -/
@[elab_as_elim]
def inductionOn₃ {C : ∀ {n}, Vector α n → Vector β n → Vector γ n → Sort*}
    (u : Vector α n) (v : Vector β n) (w : Vector γ n) (nil : C nil nil nil)
    (cons : ∀ {n a b c} {x : Vector α n} {y z}, C x y z → C (a ::ᵥ x) (b ::ᵥ y) (c ::ᵥ z)) :
    C u v w := by
  induction' n with n ih
  · rcases u with ⟨_ | ⟨-, -⟩, - | -⟩
    rcases v with ⟨_ | ⟨-, -⟩, - | -⟩
    rcases w with ⟨_ | ⟨-, -⟩, - | -⟩
    exact nil
  · rcases u with ⟨_ | ⟨a, u⟩, u_property⟩
    cases u_property
    rcases v with ⟨_ | ⟨b, v⟩, v_property⟩
    cases v_property
    rcases w with ⟨_ | ⟨c, w⟩, w_property⟩
    cases w_property
    apply
      @cons n _ _ _ ⟨u, (add_left_inj 1).mp u_property⟩ ⟨v, (add_left_inj 1).mp v_property⟩
        ⟨w, (add_left_inj 1).mp w_property⟩
    apply ih
        List.Vector.casesOn
      definition
     {motive : ∀ {n}, Vector α n → Sort*} (v : Vector α m) (nil : motive nil)
  (cons : ∀ {n}, (hd : α) → (tl : Vector α n) → motive (Vector.cons hd tl)) : motive v
        /-- Define `motive v` by case-analysis on `v : Vector α n`. -/
def casesOn {motive : ∀ {n}, Vector α n → Sort*} (v : Vector α m)
    (nil : motive nil)
    (cons : ∀ {n}, (hd : α) → (tl : Vector α n) → motive (Vector.cons hd tl)) :
    motive v :=
  inductionOn (C := motive) v nil @fun _ hd tl _ => cons hd tl
        List.Vector.casesOn₂
      definition
     {motive : ∀ {n}, Vector α n → Vector β n → Sort*} (v₁ : Vector α m) (v₂ : Vector β m) (nil : motive nil nil)
  (cons : ∀ {n}, (x : α) → (y : β) → (xs : Vector α n) → (ys : Vector β n) → motive (x ::ᵥ xs) (y ::ᵥ ys)) :
  motive v₁ v₂
        /-- Define `motive v₁ v₂` by case-analysis on `v₁ : Vector α n` and `v₂ : Vector β n`. -/
def casesOn₂ {motive : ∀ {n}, Vector α n → Vector β n → Sort*} (v₁ : Vector α m) (v₂ : Vector β m)
    (nil : motive nil nil)
    (cons : ∀ {n}, (x : α) → (y : β) → (xs : Vector α n) → (ys : Vector β n)
      → motive (x ::ᵥ xs) (y ::ᵥ ys)) :
    motive v₁ v₂ :=
  inductionOn₂ (C := motive) v₁ v₂ nil @fun _ x y xs ys _ => cons x y xs ys
        List.Vector.casesOn₃
      definition
     {motive : ∀ {n}, Vector α n → Vector β n → Vector γ n → Sort*} (v₁ : Vector α m) (v₂ : Vector β m) (v₃ : Vector γ m)
  (nil : motive nil nil nil)
  (cons :
    ∀ {n},
      (x : α) →
        (y : β) →
          (z : γ) →
            (xs : Vector α n) → (ys : Vector β n) → (zs : Vector γ n) → motive (x ::ᵥ xs) (y ::ᵥ ys) (z ::ᵥ zs)) :
  motive v₁ v₂ v₃
        /-- Define `motive v₁ v₂ v₃` by case-analysis on `v₁ : Vector α n`, `v₂ : Vector β n`, and
    `v₃ : Vector γ n`. -/
def casesOn₃ {motive : ∀ {n}, Vector α n → Vector β n → Vector γ n → Sort*} (v₁ : Vector α m)
    (v₂ : Vector β m) (v₃ : Vector γ m) (nil : motive nil nil nil)
    (cons : ∀ {n}, (x : α) → (y : β) → (z : γ) → (xs : Vector α n) → (ys : Vector β n)
      → (zs : Vector γ n) → motive (x ::ᵥ xs) (y ::ᵥ ys) (z ::ᵥ zs)) :
    motive v₁ v₂ v₃ :=
  inductionOn₃ (C := motive) v₁ v₂ v₃ nil @fun _ x y z xs ys zs _ => cons x y z xs ys zs
        List.Vector.toArray
      definition
     : Vector α n → Array α
        
      List.Vector.insertIdx
      definition
     (a : α) (i : Fin (n + 1)) (v : Vector α n) : Vector α (n + 1)
        /-- `v.insertIdx a i` inserts `a` into the vector `v` at position `i`
(and shifting later components to the right). -/
def insertIdx (a : α) (i : Fin (n + 1)) (v : Vector α n) : Vector α (n + 1) :=
  ⟨v.1.insertIdx i a, by
    rw [List.length_insertIdx, v.2]
    split <;> omega⟩
        List.Vector.insertIdx_val
      theorem
     {i : Fin (n + 1)} {v : Vector α n} : (v.insertIdx a i).val = v.val.insertIdx i.1 a
        
      List.Vector.eraseIdx_val
      theorem
     {i : Fin n} : ∀ {v : Vector α n}, (eraseIdx i v).val = v.val.eraseIdx i
        
      List.Vector.eraseIdx_insertIdx
      theorem
     {v : Vector α n} {i : Fin (n + 1)} : eraseIdx i (insertIdx a i v) = v
        theorem eraseIdx_insertIdx {v : Vector α n} {i : Fin (n + 1)} :
    eraseIdx i (insertIdx a i v) = v :=
  Subtype.eq (List.eraseIdx_insertIdx ..)
        List.Vector.eraseIdx_insertIdx'
      theorem
     {v : Vector α (n + 1)} :
  ∀ {i : Fin (n + 1)} {j : Fin (n + 2)},
    eraseIdx (j.succAbove i) (insertIdx a j v) = insertIdx a (i.predAbove j) (eraseIdx i v)
        /-- Erasing an element after inserting an element, at different indices. -/
theorem eraseIdx_insertIdx' {v : Vector α (n + 1)} :
    ∀ {i : Fin (n + 1)} {j : Fin (n + 2)},
      eraseIdx (j.succAbove i) (insertIdx a j v) = insertIdx a (i.predAbove j) (eraseIdx i v)
  | ⟨i, hi⟩, ⟨j, hj⟩ => by
    dsimp [insertIdx, eraseIdx, Fin.succAbove, Fin.predAbove]
    rw [Subtype.mk_eq_mk]
    simp only [Fin.lt_iff_val_lt_val]
    split_ifs with hij
    · rcases Nat.exists_eq_succ_of_ne_zero
        (Nat.pos_iff_ne_zero.1 (lt_of_le_of_lt (Nat.zero_le _) hij)) with ⟨j, rfl⟩
      rw [← List.insertIdx_eraseIdx_of_ge]
      · simp; rfl
      · simpa
      · simpa [Nat.lt_succ_iff] using hij
    · dsimp
      rw [← List.insertIdx_eraseIdx_of_le]
      · rfl
      · simpa
      · simpa [not_lt] using hij
        List.Vector.insertIdx_comm
      theorem
     (a b : α) (i j : Fin (n + 1)) (h : i ≤ j) :
  ∀ v : Vector α n, (v.insertIdx a i).insertIdx b j.succ = (v.insertIdx b j).insertIdx a (Fin.castSucc i)
        theorem insertIdx_comm (a b : α) (i j : Fin (n + 1)) (h : i ≤ j) :
    ∀ v : Vector α n,
      (v.insertIdx a i).insertIdx b j.succ = (v.insertIdx b j).insertIdx a (Fin.castSucc i)
  | ⟨l, hl⟩ => by
    refine Subtype.eq ?_
    simp only [insertIdx_val, Fin.val_succ, Fin.castSucc, Fin.coe_castAdd]
    apply List.insertIdx_comm
    · assumption
    · rw [hl]
      exact Nat.le_of_succ_le_succ j.2
        List.Vector.set
      definition
     (v : Vector α n) (i : Fin n) (a : α) : Vector α n
        /-- `set v n a` replaces the `n`th element of `v` with `a`. -/
def set (v : Vector α n) (i : Fin n) (a : α) : Vector α n :=
  ⟨v.1.set i.1 a, by simp⟩
        List.Vector.toList_set
      theorem
     (v : Vector α n) (i : Fin n) (a : α) : (v.set i a).toList = v.toList.set i a
        
      List.Vector.get_set_same
      theorem
     (v : Vector α n) (i : Fin n) (a : α) : (v.set i a).get i = a
        @[simp]
theorem get_set_same (v : Vector α n) (i : Fin n) (a : α) : (v.set i a).get i = a := by
  cases v; cases i; simp [Vector.set, get_eq_get_toList]
        List.Vector.get_set_of_ne
      theorem
     {v : Vector α n} {i j : Fin n} (h : i ≠ j) (a : α) : (v.set i a).get j = v.get j
        theorem get_set_of_ne {v : Vector α n} {i j : Fin n} (h : i ≠ j) (a : α) :
    (v.set i a).get j = v.get j := by
  cases v; cases i; cases j
  simp only [get_eq_get_toList, toList_set, toList_mk, Fin.cast_mk, List.get_eq_getElem]
  rw [List.getElem_set_of_ne]
  · simpa using h
        List.Vector.get_set_eq_if
      theorem
     {v : Vector α n} {i j : Fin n} (a : α) : (v.set i a).get j = if i = j then a else v.get j
        theorem get_set_eq_if {v : Vector α n} {i j : Fin n} (a : α) :
    (v.set i a).get j = if i = j then a else v.get j := by
  split_ifs <;> (try simp [*]); rwa [get_set_of_ne]
        List.Vector.prod_set
      theorem
     [Monoid α] (v : Vector α n) (i : Fin n) (a : α) :
  (v.set i a).toList.prod = (v.take i).toList.prod * a * (v.drop (i + 1)).toList.prod
        
      List.Vector.prod_set'
      theorem
     [CommGroup α] (v : Vector α n) (i : Fin n) (a : α) : (v.set i a).toList.prod = v.toList.prod * (v.get i)⁻¹ * a
        /-- Variant of `List.Vector.prod_set` that multiplies by the inverse of the replaced element -/
@[to_additive
  "Variant of `List.Vector.sum_set` that subtracts the inverse of the replaced element"]
theorem prod_set' [CommGroup α] (v : Vector α n) (i : Fin n) (a : α) :
    (v.set i a).toList.prod = v.toList.prod * (v.get i)⁻¹ * a := by
  refine (List.prod_set' v.toList i a).trans ?_
  simp [get_eq_get_toList, mul_assoc]
        List.Vector.traverse
      definition
     {α β : Type u} (f : α → F β) : Vector α n → F (Vector β n)
        
      List.Vector.traverse_def
      theorem
     (f : α → F β) (x : α) : ∀ xs : Vector α n, (x ::ᵥ xs).traverse f = cons <$> f x <*> xs.traverse f
        @[simp]
protected theorem traverse_def (f : α → F β) (x : α) :
    ∀ xs : Vector α n, (x ::ᵥ xs).traverse f = conscons <$> f xcons <$> f x <*> xs.traverse f := by
  rintro ⟨xs, rfl⟩; rfl
        List.Vector.id_traverse
      theorem
     : ∀ x : Vector α n, x.traverse (pure : _ → Id _) = x
        protected theorem id_traverse : ∀ x : Vector α n, x.traverse (pure : _ → Id _) = x := by
  rintro ⟨x, rfl⟩; dsimp [Vector.traverse, cast]
  induction' x with x xs IH; · rfl
  simp! [IH]; rfl
        List.Vector.comp_traverse
      theorem
     (f : β → F γ) (g : α → G β) (x : Vector α n) :
  Vector.traverse (Comp.mk ∘ Functor.map f ∘ g) x = Comp.mk (Vector.traverse f <$> Vector.traverse g x)
        @[nolint unusedArguments]
protected theorem comp_traverse (f : β → F γ) (g : α → G β) (x : Vector α n) :
    Vector.traverse (Comp.mkComp.mk ∘ Functor.map f ∘ g) x =
      Comp.mk (Vector.traverseVector.traverse f <$> Vector.traverse g x) := by
  induction' x with n x xs ih
  · simp! [cast, *, functor_norm]
    rfl
  · rw [Vector.traverse_def, ih]
    simp [functor_norm, Function.comp_def]
        List.Vector.traverse_eq_map_id
      theorem
     {α β} (f : α → β) : ∀ x : Vector α n, x.traverse ((pure : _ → Id _) ∘ f) = (pure : _ → Id _) (map f x)
        protected theorem traverse_eq_map_id {α β} (f : α → β) :
    ∀ x : Vector α n, x.traverse ((pure : _ → Id _) ∘ f) = (pure : _ → Id _) (map f x) := by
  rintro ⟨x, rfl⟩; simp!; induction x <;> simp! [*, functor_norm] <;> rfl
        List.Vector.naturality
      theorem
     {α β : Type u} (f : α → F β) (x : Vector α n) : η (x.traverse f) = x.traverse (@η _ ∘ f)
        protected theorem naturality {α β : Type u} (f : α → F β) (x : Vector α n) :
    η (x.traverse f) = x.traverse (@η _ ∘ f) := by
  induction' x with n x xs ih
  · simp! [functor_norm, cast, η.preserves_pure]
  · rw [Vector.traverse_def, Vector.traverse_def, ← ih, η.preserves_seq, η.preserves_map]
    rfl
        List.Vector.instTraversableFlipNat
      instance
     : Traversable.{u} (flip Vector n)
        instance : Traversable.{u} (flip Vector n) where
  traverse := @Vector.traverse n
  map {α β} := @Vector.map.{u, u} α β n
        List.Vector.instLawfulTraversableFlipNat
      instance
     : LawfulTraversable.{u} (flip Vector n)
        instance : LawfulTraversable.{u} (flip Vector n) where
  id_traverse := @Vector.id_traverse n
  comp_traverse := Vector.comp_traverse
  traverse_eq_map_id := @Vector.traverse_eq_map_id n
  naturality := Vector.naturality
  id_map := by intro _ x; cases x; simp! [(· <$> ·)]
  comp_map := by intro _ _ _ _ _ x; cases x; simp! [(· <$> ·)]
  map_const := rfl
        List.Vector.replicate_succ
      theorem
     (val : α) : replicate (n + 1) val = val ::ᵥ (replicate n val)
        @[simp]
theorem replicate_succ (val : α) :
    replicate (n+1) val = val ::ᵥ (replicate n val) :=
  rfl
        List.Vector.get_append_cons_zero
      theorem
     : get (append (x ::ᵥ xs) ys) 0 = x
        @[simp] lemma get_append_cons_zero : get (append (x ::ᵥ xs) ys) 0 = x := rfl
        List.Vector.get_append_cons_succ
      theorem
     {i : Fin (n + m)} {h} : get (append (x ::ᵥ xs) ys) ⟨i + 1, h⟩ = get (append xs ys) i
        
      List.Vector.append_nil
      theorem
     : append xs nil = xs
        @[simp]
theorem append_nil : append xs nil = xs := by
  cases xs; simp [append]
        List.Vector.get_map₂
      theorem
     (v₁ : Vector α n) (v₂ : Vector β n) (f : α → β → γ) (i : Fin n) : get (map₂ f v₁ v₂) i = f (get v₁ i) (get v₂ i)
        @[simp]
theorem get_map₂ (v₁ : Vector α n) (v₂ : Vector β n) (f : α → β → γ) (i : Fin n) :
    get (map₂ f v₁ v₂) i = f (get v₁ i) (get v₂ i) := by
  clear * - v₁ v₂
  induction v₁, v₂ using inductionOn₂ with
  | nil =>
    exact Fin.elim0 i
  | cons ih =>
    rw [map₂_cons]
    cases i using Fin.cases
    · simp only [get_zero, head_cons]
    · simp only [get_cons_succ, ih]
        List.Vector.mapAccumr_cons
      theorem
     {f : α → σ → σ × β} :
  mapAccumr f (x ::ᵥ xs) s =
    let r := mapAccumr f xs s
    let q := f x r.1
    (q.1, q.2 ::ᵥ r.2)
        @[simp]
theorem mapAccumr_cons {f : α → σ → σ × β} :
    mapAccumr f (x ::ᵥ xs) s
    = let r := mapAccumr f xs s
      let q := f x r.1
      (q.1, q.2 ::ᵥ r.2) :=
  rfl
        List.Vector.mapAccumr₂_cons
      theorem
     {f : α → β → σ → σ × φ} :
  mapAccumr₂ f (x ::ᵥ xs) (y ::ᵥ ys) s =
    let r := mapAccumr₂ f xs ys s
    let q := f x y r.1
    (q.1, q.2 ::ᵥ r.2)
        @[simp]
theorem mapAccumr₂_cons {f : α → β → σ → σ × φ} :
    mapAccumr₂ f (x ::ᵥ xs) (y ::ᵥ ys) s
    = let r := mapAccumr₂ f xs ys s
      let q := f x y r.1
      (q.1, q.2 ::ᵥ r.2) :=
  rfl