/-- 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
    · 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]
      

Proof state:
case zero.succ
𝕜 : 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 : ℕ
IH :
  ∀ (hi : i < length b),
    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)))
hi : Nat.succ i < length b
hj : Nat.zero < blocksFun b { val := Nat.succ i, isLt := hi }
A : i < length b
B : i < List.length (List.map sum (splitWrtComposition a.blocks b))
C : 0 < blocksFun b { val := i, isLt := A }
this :
  take (sum (take i b.blocks)) a.blocks = take (sum (take i b.blocks)) (take (sum (take (i + 1) b.blocks)) a.blocks)
⊢ sum (take (sum (take i b.blocks)) (take (sum (take (Nat.succ i) b.blocks)) a.blocks)) +
      sum (drop (sum (take i b.blocks)) (take (sum (take (Nat.succ i) b.blocks)) a.blocks)) =
    sum
        (take (sum (take i b.blocks))
          (take (sum (take i b.blocks)) (take (sum (take (Nat.succ i) b.blocks)) a.blocks) ++
            drop (sum (take i b.blocks)) (take (sum (take (Nat.succ i) b.blocks)) a.blocks))) +
      sum
        (drop
          (sizeUpTo b
            ↑{ val := ↑{ val := i, isLt := B },
                isLt := (_ : ↑{ val := i, isLt := B } < List.length (splitWrtComposition a.blocks b)) })
          (take
            (sizeUpTo b
              (↑{ val := ↑{ val := i, isLt := B },
                    isLt := (_ : ↑{ val := i, isLt := B } < List.length (splitWrtComposition a.blocks b)) } +
                1))
            a.blocks))

Next tactic:
congr