l3lab/ntp-mathlib huggingface dataset:
/-- When `a` is a composition of `n` and `b` is a composition of `a.length`, `a.gather b` is the
composition of `n` obtained by gathering all the blocks of `a` corresponding to a block of `b`.
For instance, if `a = [6, 5, 3, 5, 2]` and `b = [2, 3]`, one should gather together
the first two blocks of `a` and its last three blocks, giving `a.gather b = [11, 10]`. -/
def gather (a : Composition n) (b : Composition a.length) : Composition n where
  blocks := (a.blocks.splitWrtComposition b).map sum
  blocks_pos := by
    rw [forall_mem_map_iff]
    intro j hj
    suffices H : ∀ i ∈ j, 1 ≤ i;
    exact
      calc
        0 < j.length := length_pos_of_mem_splitWrtComposition hj
        _ ≤ j.sum := length_le_sum_of_one_le _ H
    intro i hi
    apply a.one_le_blocks
    rw [← a.blocks.join_splitWrtComposition b]
    

Proof state:
case H
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
j : List ℕ
hj : j ∈ splitWrtComposition a.blocks b
i : ℕ
hi : i ∈ j
⊢ i ∈ List.join (splitWrtComposition a.blocks b)

Next tactic:
exact mem_join_of_mem hj hi
/-- When `a` is a composition of `n` and `b` is a composition of `a.length`, `a.gather b` is the
composition of `n` obtained by gathering all the blocks of `a` corresponding to a block of `b`.
For instance, if `a = [6, 5, 3, 5, 2]` and `b = [2, 3]`, one should gather together
the first two blocks of `a` and its last three blocks, giving `a.gather b = [11, 10]`. -/
def gather (a : Composition n) (b : Composition a.length) : Composition n where
  blocks := (a.blocks.splitWrtComposition b).map sum
  blocks_pos := by
    rw [forall_mem_map_iff]
    intro j hj
    suffices H : ∀ i ∈ j, 1 ≤ i;
    exact
      calc
        0 < j.length := length_pos_of_mem_splitWrtComposition hj
        _ ≤ j.sum := length_le_sum_of_one_le _ H
    intro i hi
    apply a.one_le_blocks
    rw [← a.blocks.join_splitWrtComposition b]
    exact mem_join_of_mem hj hi
  blocks_sum := by 

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
⊢ sum (List.map sum (splitWrtComposition a.blocks b)) = n

Next tactic:
rw [← sum_join, join_splitWrtComposition, a.blocks_sum]
theorem length_gather (a : Composition n) (b : Composition a.length) :
    length (a.gather b) = b.length :=
  show (map List.sum (a.blocks.splitWrtComposition b)).length = b.blocks.length by
    

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
⊢ List.length (List.map sum (splitWrtComposition a.blocks b)) = List.length b.blocks

Next tactic:
rw [length_map, length_splitWrtComposition]
/-- An auxiliary function used in the definition of `sigmaEquivSigmaPi` below, associating to
two compositions `a` of `n` and `b` of `a.length`, and an index `i` bounded by the length of
`a.gather b`, the subcomposition of `a` made of those blocks belonging to the `i`-th block of
`a.gather b`. -/
def sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin (a.gather b).length) : Composition ((a.gather b).blocksFun i) where
  blocks :=
    List.get (a.blocks.splitWrtComposition b)
      ⟨i.val, (by 

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : Fin (length (gather a b))
⊢ ↑i < List.length (splitWrtComposition a.blocks b)

Next tactic:
rw [length_splitWrtComposition, ← length_gather]
/-- An auxiliary function used in the definition of `sigmaEquivSigmaPi` below, associating to
two compositions `a` of `n` and `b` of `a.length`, and an index `i` bounded by the length of
`a.gather b`, the subcomposition of `a` made of those blocks belonging to the `i`-th block of
`a.gather b`. -/
def sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin (a.gather b).length) : Composition ((a.gather b).blocksFun i) where
  blocks :=
    List.get (a.blocks.splitWrtComposition b)
      ⟨i.val, (by rw [length_splitWrtComposition, ← length_gather]; 

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : Fin (length (gather a b))
⊢ ↑i < length (gather a b)

Next tactic:
exact i.2
/-- An auxiliary function used in the definition of `sigmaEquivSigmaPi` below, associating to
two compositions `a` of `n` and `b` of `a.length`, and an index `i` bounded by the length of
`a.gather b`, the subcomposition of `a` made of those blocks belonging to the `i`-th block of
`a.gather b`. -/
def sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin (a.gather b).length) : Composition ((a.gather b).blocksFun i) where
  blocks :=
    List.get (a.blocks.splitWrtComposition b)
      ⟨i.val, (by rw [length_splitWrtComposition, ← length_gather]; exact i.2)⟩
  blocks_pos {i} hi :=
    a.blocks_pos
      (by
        

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i✝ : Fin (length (gather a b))
i : ℕ
hi :
  i ∈
    List.get (splitWrtComposition a.blocks b)
      { val := ↑i✝, isLt := (_ : ↑i✝ < List.length (splitWrtComposition a.blocks b)) }
⊢ i ∈ a.blocks

Next tactic:
rw [← a.blocks.join_splitWrtComposition b]
/-- An auxiliary function used in the definition of `sigmaEquivSigmaPi` below, associating to
two compositions `a` of `n` and `b` of `a.length`, and an index `i` bounded by the length of
`a.gather b`, the subcomposition of `a` made of those blocks belonging to the `i`-th block of
`a.gather b`. -/
def sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin (a.gather b).length) : Composition ((a.gather b).blocksFun i) where
  blocks :=
    List.get (a.blocks.splitWrtComposition b)
      ⟨i.val, (by rw [length_splitWrtComposition, ← length_gather]; exact i.2)⟩
  blocks_pos {i} hi :=
    a.blocks_pos
      (by
        rw [← a.blocks.join_splitWrtComposition b]
        

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i✝ : Fin (length (gather a b))
i : ℕ
hi :
  i ∈
    List.get (splitWrtComposition a.blocks b)
      { val := ↑i✝, isLt := (_ : ↑i✝ < List.length (splitWrtComposition a.blocks b)) }
⊢ i ∈ List.join (splitWrtComposition a.blocks b)

Next tactic:
exact mem_join_of_mem (List.get_mem _ _ _) hi
/-- An auxiliary function used in the definition of `sigmaEquivSigmaPi` below, associating to
two compositions `a` of `n` and `b` of `a.length`, and an index `i` bounded by the length of
`a.gather b`, the subcomposition of `a` made of those blocks belonging to the `i`-th block of
`a.gather b`. -/
def sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin (a.gather b).length) : Composition ((a.gather b).blocksFun i) where
  blocks :=
    List.get (a.blocks.splitWrtComposition b)
      ⟨i.val, (by rw [length_splitWrtComposition, ← length_gather]; exact i.2)⟩
  blocks_pos {i} hi :=
    a.blocks_pos
      (by
        rw [← a.blocks.join_splitWrtComposition b]
        exact mem_join_of_mem (List.get_mem _ _ _) hi)
  blocks_sum := by 

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : Fin (length (gather a b))
⊢ sum
      (List.get (splitWrtComposition a.blocks b)
        { val := ↑i, isLt := (_ : ↑i < List.length (splitWrtComposition a.blocks b)) }) =
    blocksFun (gather a b) i

Next tactic:
simp only [Composition.blocksFun, get_map, Composition.gather]
theorem length_sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin b.length) :
    Composition.length (Composition.sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ i.2⟩) =
      Composition.blocksFun b i :=
  show List.length ((splitWrtComposition a.blocks b).get ⟨i, _⟩) = blocksFun b i by
    

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : Fin (length b)
⊢ List.length
      (List.get (splitWrtComposition a.blocks b)
        { val := ↑i,
          isLt :=
            (_ :
              ↑{ val := ↑i, isLt := (_ : ↑i < length (gather a b)) } <
                List.length (splitWrtComposition a.blocks b)) }) =
    blocksFun b i

Next tactic:
rw [get_map_rev List.length, get_of_eq (map_length_splitWrtComposition _ _)]
theorem length_sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin b.length) :
    Composition.length (Composition.sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ i.2⟩) =
      Composition.blocksFun b i :=
  show List.length ((splitWrtComposition a.blocks b).get ⟨i, _⟩) = blocksFun b i by
    rw [get_map_rev List.length, get_of_eq (map_length_splitWrtComposition _ _)]; 

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : Fin (length b)
⊢ List.get b.blocks
      {
        val :=
          ↑{
              val :=
                ↑{ val := ↑i,
                    isLt :=
                      (_ :
                        ↑{ val := ↑i, isLt := (_ : ↑i < length (gather a b)) } <
                          List.length (splitWrtComposition a.blocks b)) },
              isLt :=
                (_ :
                  ↑{ val := ↑i,
                        isLt :=
                          (_ :
                            ↑{ val := ↑i, isLt := (_ : ↑i < length (gather a b)) } <
                              List.length (splitWrtComposition a.blocks b)) } <
                    List.length (List.map List.length (splitWrtComposition a.blocks b))) },
        isLt :=
          (_ :
            ↑{
                  val :=
                    ↑{ val := ↑i,
                        isLt :=
                          (_ :
                            ↑{ val := ↑i, isLt := (_ : ↑i < length (gather a b)) } <
                              List.length (splitWrtComposition a.blocks b)) },
                  isLt :=
                    (_ :
                      ↑{ val := ↑i,
                            isLt :=
                              (_ :
                                ↑{ val := ↑i, isLt := (_ : ↑i < length (gather a b)) } <
                                  List.length (splitWrtComposition a.blocks b)) } <
                        List.length (List.map List.length (splitWrtComposition a.blocks b))) } <
              List.length b.blocks) } =
    blocksFun b i

Next tactic:
rfl
theorem blocksFun_sigmaCompositionAux (a : Composition n) (b : Composition a.length)
    (i : Fin b.length) (j : Fin (blocksFun b i)) :
    blocksFun (sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ i.2⟩)
        ⟨j, (length_sigmaCompositionAux a b i).symm ▸ j.2⟩ =
      blocksFun a (embedding b i j) :=
  show get (get _ ⟨_, _⟩) ⟨_, _⟩  = a.blocks.get ⟨_, _⟩ by
    

Proof state:
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : Fin (length b)
j : Fin (blocksFun b i)
⊢ List.get
      (List.get (splitWrtComposition a.blocks b)
        { val := ↑{ val := ↑i, isLt := (_ : ↑i < length (gather a b)) },
          isLt :=
            (_ :
              ↑{ val := ↑i, isLt := (_ : ↑i < length (gather a b)) } < List.length (splitWrtComposition a.blocks b)) })
      { val := ↑j,
        isLt := (_ : ↑j < length (sigmaCompositionAux a b { val := ↑i, isLt := (_ : ↑i < length (gather a b)) })) } =
    List.get a.blocks
      { val := ↑((Fin.natAddEmb (sizeUpTo b ↑i)).toEmbedding j),
        isLt := (_ : ↑((Fin.natAddEmb (sizeUpTo b ↑i)).toEmbedding j) < length a) }

Next tactic:
rw [get_of_eq (get_splitWrtComposition _ _ _), get_drop', get_take']
/-- Auxiliary lemma to prove that the composition of formal multilinear series is associative.

Consider a composition `a` of `n` and a composition `b` of `a.length`. Grouping together some
blocks of `a` according to `b` as in `a.gather b`, one can compute the total size of the blocks
of `a` up to an index `size_up_to b i + j` (where the `j` corresponds to a set of blocks of `a`
that do not fill a whole block of `a.gather b`). The first part corresponds to a sum of blocks
in `a.gather b`, and the second one to a sum of blocks in the next block of
`sigma_composition_aux a b`. This is the content of this lemma. -/
theorem sizeUpTo_sizeUpTo_add (a : Composition n) (b : Composition a.length) {i j : ℕ}
    (hi : i < b.length) (hj : j < blocksFun b ⟨i, hi⟩) :
    sizeUpTo a (sizeUpTo b i + j) =
      sizeUpTo (a.gather b) i +
        sizeUpTo (sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ hi⟩) j := by
  -- Porting note: `induction'` left a spurious `hj` in the context
  induction j with
  

Proof state:
case zero
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : ℕ
hi : i < length b
hj : Nat.zero < blocksFun b { val := i, isLt := hi }
⊢ sizeUpTo a (sizeUpTo b i + Nat.zero) =
    sizeUpTo (gather a b) i +
      sizeUpTo (sigmaCompositionAux a b { val := i, isLt := (_ : i < length (gather a b)) }) Nat.zero

Next tactic:
| zero =>
    show
      sum (take (b.blocks.take i).sum a.blocks) =
        sum (take i (map sum (splitWrtComposition a.blocks b)))
    induction' i with i IH
    · rfl
    · have A : i < b.length := Nat.lt_of_succ_lt hi
      have B : i < List.length (map List.sum (splitWrtComposition a.blocks b)) := by simp [A]
      have C : 0 < blocksFun b ⟨i, A⟩ := Composition.blocks_pos' _ _ _
      rw [sum_take_succ _ _ B, ← IH A C]
      have :
        take (sum (take i b.blocks)) a.blocks =
          take (sum (take i b.blocks)) (take (sum (take (i + 1) b.blocks)) a.blocks) := by
        rw [take_take, min_eq_left]
        apply monotone_sum_take _ (Nat.le_succ _)
      rw [this, get_map, get_splitWrtComposition, ←
        take_append_drop (sum (take i b.blocks)) (take (sum (take (Nat.succ i) b.blocks)) a.blocks),
        sum_append]
      congr
      rw [take_append_drop]
/-- Auxiliary lemma to prove that the composition of formal multilinear series is associative.

Consider a composition `a` of `n` and a composition `b` of `a.length`. Grouping together some
blocks of `a` according to `b` as in `a.gather b`, one can compute the total size of the blocks
of `a` up to an index `size_up_to b i + j` (where the `j` corresponds to a set of blocks of `a`
that do not fill a whole block of `a.gather b`). The first part corresponds to a sum of blocks
in `a.gather b`, and the second one to a sum of blocks in the next block of
`sigma_composition_aux a b`. This is the content of this lemma. -/
theorem sizeUpTo_sizeUpTo_add (a : Composition n) (b : Composition a.length) {i j : ℕ}
    (hi : i < b.length) (hj : j < blocksFun b ⟨i, hi⟩) :
    sizeUpTo a (sizeUpTo b i + j) =
      sizeUpTo (a.gather b) i +
        sizeUpTo (sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ hi⟩) j := by
  -- Porting note: `induction'` left a spurious `hj` in the context
  induction j with
  | zero =>
    

Proof state:
case zero
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : ℕ
hi : i < length b
hj : Nat.zero < blocksFun b { val := i, isLt := hi }
⊢ sizeUpTo a (sizeUpTo b i + Nat.zero) =
    sizeUpTo (gather a b) i +
      sizeUpTo (sigmaCompositionAux a b { val := i, isLt := (_ : i < length (gather a b)) }) Nat.zero

Next tactic:
show
      sum (take (b.blocks.take i).sum a.blocks) =
        sum (take i (map sum (splitWrtComposition a.blocks b)))
/-- Auxiliary lemma to prove that the composition of formal multilinear series is associative.

Consider a composition `a` of `n` and a composition `b` of `a.length`. Grouping together some
blocks of `a` according to `b` as in `a.gather b`, one can compute the total size of the blocks
of `a` up to an index `size_up_to b i + j` (where the `j` corresponds to a set of blocks of `a`
that do not fill a whole block of `a.gather b`). The first part corresponds to a sum of blocks
in `a.gather b`, and the second one to a sum of blocks in the next block of
`sigma_composition_aux a b`. This is the content of this lemma. -/
theorem sizeUpTo_sizeUpTo_add (a : Composition n) (b : Composition a.length) {i j : ℕ}
    (hi : i < b.length) (hj : j < blocksFun b ⟨i, hi⟩) :
    sizeUpTo a (sizeUpTo b i + j) =
      sizeUpTo (a.gather b) i +
        sizeUpTo (sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ hi⟩) j := by
  -- Porting note: `induction'` left a spurious `hj` in the context
  induction j with
  | zero =>
    show
      sum (take (b.blocks.take i).sum a.blocks) =
        sum (take i (map sum (splitWrtComposition a.blocks b)))
    

Proof state:
case zero
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
i : ℕ
hi : i < length b
hj : Nat.zero < blocksFun b { val := i, isLt := hi }
⊢ sum (take (sum (take i b.blocks)) a.blocks) = sum (take i (List.map sum (splitWrtComposition a.blocks b)))

Next tactic:
induction' i with i IH
/-- Auxiliary lemma to prove that the composition of formal multilinear series is associative.

Consider a composition `a` of `n` and a composition `b` of `a.length`. Grouping together some
blocks of `a` according to `b` as in `a.gather b`, one can compute the total size of the blocks
of `a` up to an index `size_up_to b i + j` (where the `j` corresponds to a set of blocks of `a`
that do not fill a whole block of `a.gather b`). The first part corresponds to a sum of blocks
in `a.gather b`, and the second one to a sum of blocks in the next block of
`sigma_composition_aux a b`. This is the content of this lemma. -/
theorem sizeUpTo_sizeUpTo_add (a : Composition n) (b : Composition a.length) {i j : ℕ}
    (hi : i < b.length) (hj : j < blocksFun b ⟨i, hi⟩) :
    sizeUpTo a (sizeUpTo b i + j) =
      sizeUpTo (a.gather b) i +
        sizeUpTo (sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ hi⟩) j := by
  -- Porting note: `induction'` left a spurious `hj` in the context
  induction j with
  | zero =>
    show
      sum (take (b.blocks.take i).sum a.blocks) =
        sum (take i (map sum (splitWrtComposition a.blocks b)))
    induction' i with i IH
    · 

Proof state:
case zero.zero
𝕜 : Type u_1
E : Type u_2
F : Type u_3
G : Type u_4
H : Type u_5
inst✝⁸ : NontriviallyNormedField 𝕜
inst✝⁷ : NormedAddCommGroup E
inst✝⁶ : NormedSpace 𝕜 E
inst✝⁵ : NormedAddCommGroup F
inst✝⁴ : NormedSpace 𝕜 F
inst✝³ : NormedAddCommGroup G
inst✝² : NormedSpace 𝕜 G
inst✝¹ : NormedAddCommGroup H
inst✝ : NormedSpace 𝕜 H
n : ℕ
a : Composition n
b : Composition (length a)
hi : Nat.zero < length b
hj : Nat.zero < blocksFun b { val := Nat.zero, isLt := hi }
⊢ sum (take (sum (take Nat.zero b.blocks)) a.blocks) =
    sum (take Nat.zero (List.map sum (splitWrtComposition a.blocks b)))

Next tactic:
rfl