File: Mathlib/Combinatorics/Enumerative/Composition.lean

full_name: Composition.blocks_sum
code: /-- A composition of `n` is a list of positive integers summing to `n`. -/
@[ext]
structure Composition (n : ℕ) where
  /-- List of positive integers summing to `n`-/
  blocks : List ℕ
  /-- Proof of positivity for `blocks`-/
  blocks_pos : ∀ {i}, i ∈ blocks → 0 < i
  /-- Proof that `blocks` sums to `n`-/
  blocks_sum : blocks.sum = n
goal: self.blocks.sum = n

full_name: Composition.blocks_pos
code: /-- A composition of `n` is a list of positive integers summing to `n`. -/
@[ext]
structure Composition (n : ℕ) where
  /-- List of positive integers summing to `n`-/
  blocks : List ℕ
  /-- Proof of positivity for `blocks`-/
  blocks_pos : ∀ {i}, i ∈ blocks → 0 < i
  /-- Proof that `blocks` sums to `n`-/
  blocks_sum : blocks.sum = n
goal: i ∈ self.blocks → 0 < i

full_name: Composition.blocks
code: /-- A composition of `n` is a list of positive integers summing to `n`. -/
@[ext]
structure Composition (n : ℕ) where
  /-- List of positive integers summing to `n`-/
  blocks : List ℕ
  /-- Proof of positivity for `blocks`-/
  blocks_pos : ∀ {i}, i ∈ blocks → 0 < i
  /-- Proof that `blocks` sums to `n`-/
  blocks_sum : blocks.sum = n
goal: List ℕ

full_name: Composition
code: /-- A composition of `n` is a list of positive integers summing to `n`. -/
@[ext]
structure Composition (n : ℕ) where
  /-- List of positive integers summing to `n`-/
  blocks : List ℕ
  /-- Proof of positivity for `blocks`-/
  blocks_pos : ∀ {i}, i ∈ blocks → 0 < i
  /-- Proof that `blocks` sums to `n`-/
  blocks_sum : blocks.sum = n
goal: Type

full_name: CompositionAsSet.boundaries
code: /-- Combinatorial viewpoint on a composition of `n`, by seeing it as non-empty blocks of
consecutive integers in `{0, ..., n-1}`. We register every block by its left end-point, yielding
a finset containing `0`. As this does not make sense for `n = 0`, we add `n` to this finset, and
get a finset of `{0, ..., n}` containing `0` and `n`. This is the data in the structure
`CompositionAsSet n`. -/
@[ext]
structure CompositionAsSet (n : ℕ) where
  /-- Combinatorial viewpoint on a composition of `n` as consecutive integers `{0, ..., n-1}`-/
  boundaries : Finset (Fin n.succ)
  /-- Proof that `0` is a member of `boundaries`-/
  zero_mem : (0 : Fin n.succ) ∈ boundaries
  /-- Last element of the composition-/
  getLast_mem : Fin.last n ∈ boundaries
goal: Finset (Fin n.succ)

full_name: CompositionAsSet.getLast_mem
code: /-- Combinatorial viewpoint on a composition of `n`, by seeing it as non-empty blocks of
consecutive integers in `{0, ..., n-1}`. We register every block by its left end-point, yielding
a finset containing `0`. As this does not make sense for `n = 0`, we add `n` to this finset, and
get a finset of `{0, ..., n}` containing `0` and `n`. This is the data in the structure
`CompositionAsSet n`. -/
@[ext]
structure CompositionAsSet (n : ℕ) where
  /-- Combinatorial viewpoint on a composition of `n` as consecutive integers `{0, ..., n-1}`-/
  boundaries : Finset (Fin n.succ)
  /-- Proof that `0` is a member of `boundaries`-/
  zero_mem : (0 : Fin n.succ) ∈ boundaries
  /-- Last element of the composition-/
  getLast_mem : Fin.last n ∈ boundaries
goal: Fin.last n ∈ self.boundaries

full_name: CompositionAsSet.zero_mem
code: /-- Combinatorial viewpoint on a composition of `n`, by seeing it as non-empty blocks of
consecutive integers in `{0, ..., n-1}`. We register every block by its left end-point, yielding
a finset containing `0`. As this does not make sense for `n = 0`, we add `n` to this finset, and
get a finset of `{0, ..., n}` containing `0` and `n`. This is the data in the structure
`CompositionAsSet n`. -/
@[ext]
structure CompositionAsSet (n : ℕ) where
  /-- Combinatorial viewpoint on a composition of `n` as consecutive integers `{0, ..., n-1}`-/
  boundaries : Finset (Fin n.succ)
  /-- Proof that `0` is a member of `boundaries`-/
  zero_mem : (0 : Fin n.succ) ∈ boundaries
  /-- Last element of the composition-/
  getLast_mem : Fin.last n ∈ boundaries
goal: 0 ∈ self.boundaries

full_name: CompositionAsSet
code: /-- Combinatorial viewpoint on a composition of `n`, by seeing it as non-empty blocks of
consecutive integers in `{0, ..., n-1}`. We register every block by its left end-point, yielding
a finset containing `0`. As this does not make sense for `n = 0`, we add `n` to this finset, and
get a finset of `{0, ..., n}` containing `0` and `n`. This is the data in the structure
`CompositionAsSet n`. -/
@[ext]
structure CompositionAsSet (n : ℕ) where
  /-- Combinatorial viewpoint on a composition of `n` as consecutive integers `{0, ..., n-1}`-/
  boundaries : Finset (Fin n.succ)
  /-- Proof that `0` is a member of `boundaries`-/
  zero_mem : (0 : Fin n.succ) ∈ boundaries
  /-- Last element of the composition-/
  getLast_mem : Fin.last n ∈ boundaries
goal: Type

full_name: instInhabitedCompositionAsSet
code: instance {n : ℕ} : Inhabited (CompositionAsSet n) 
goal: Inhabited (CompositionAsSet n)

full_name: Composition.instToString
code: instance (n : ℕ) : ToString (Composition n) 
goal: ToString (Composition n)

full_name: Composition.length
code: /-- The length of a composition, i.e., the number of blocks in the composition. -/
abbrev length : ℕ 
goal: ℕ

full_name: Composition.blocks_length
code: theorem blocks_length : c.blocks.length = c.length 
goal: c.blocks.length = c.length

full_name: Composition.blocksFun
code: /-- The blocks of a composition, seen as a function on `Fin c.length`. When composing analytic
functions using compositions, this is the main player. -/
def blocksFun : Fin c.length → ℕ 
goal: Fin c.length → ℕ

full_name: Composition.ofFn_blocksFun
code: theorem ofFn_blocksFun : ofFn c.blocksFun = c.blocks 
goal: List.ofFn c.blocksFun = c.blocks

full_name: Composition.sum_blocksFun
code: theorem sum_blocksFun : ∑ i, c.blocksFun i = n 
goal: ∑ i : Fin c.length, c.blocksFun i = n

full_name: Composition.blocksFun_mem_blocks
code: theorem blocksFun_mem_blocks (i : Fin c.length) : c.blocksFun i ∈ c.blocks 
goal: c.blocksFun i ∈ c.blocks

full_name: Composition.one_le_blocks
code: @[simp]
theorem one_le_blocks {i : ℕ} (h : i ∈ c.blocks) : 1 ≤ i 
goal: 1 ≤ i

full_name: Composition.one_le_blocks'
code: @[simp]
theorem one_le_blocks' {i : ℕ} (h : i < c.length) : 1 ≤ c.blocks[i] 
goal: 1 ≤ c.blocks[i]

full_name: Composition.blocks_pos'
code: @[simp]
theorem blocks_pos' (i : ℕ) (h : i < c.length) : 0 < c.blocks[i] 
goal: 0 < c.blocks[i]

full_name: Composition.one_le_blocksFun
code: theorem one_le_blocksFun (i : Fin c.length) : 1 ≤ c.blocksFun i 
goal: 1 ≤ c.blocksFun i

full_name: Composition.length_le
code: theorem length_le : c.length ≤ n 
goal: c.length ≤ n

full_name: Composition.length_pos_of_pos
code: theorem length_pos_of_pos (h : 0 < n) : 0 < c.length 
goal: 0 < c.length

full_name: Composition.sizeUpTo
code: /-- The sum of the sizes of the blocks in a composition up to `i`. -/
def sizeUpTo (i : ℕ) : ℕ 
goal: ℕ

full_name: Composition.sizeUpTo_zero
code: @[simp]
theorem sizeUpTo_zero : c.sizeUpTo 0 = 0 
goal: c.sizeUpTo 0 = 0

full_name: Composition.sizeUpTo_ofLength_le
code: theorem sizeUpTo_ofLength_le (i : ℕ) (h : c.length ≤ i) : c.sizeUpTo i = n 
goal: c.sizeUpTo i = n

full_name: Composition.sizeUpTo_length
code: @[simp]
theorem sizeUpTo_length : c.sizeUpTo c.length = n 
goal: c.sizeUpTo c.length = n

full_name: Composition.sizeUpTo_le
code: theorem sizeUpTo_le (i : ℕ) : c.sizeUpTo i ≤ n 
goal: c.sizeUpTo i ≤ n

full_name: Composition.sizeUpTo_succ
code: theorem sizeUpTo_succ {i : ℕ} (h : i < c.length) :
    c.sizeUpTo (i + 1) = c.sizeUpTo i + c.blocks[i] 
goal: c.sizeUpTo (i + 1) = c.sizeUpTo i + c.blocks[i]

full_name: Composition.sizeUpTo_succ'
code: theorem sizeUpTo_succ' (i : Fin c.length) :
    c.sizeUpTo ((i : ℕ) + 1) = c.sizeUpTo i + c.blocksFun i 
goal: c.sizeUpTo (↑i + 1) = c.sizeUpTo ↑i + c.blocksFun i

full_name: Composition.sizeUpTo_strict_mono
code: theorem sizeUpTo_strict_mono {i : ℕ} (h : i < c.length) : c.sizeUpTo i < c.sizeUpTo (i + 1) 
goal: c.sizeUpTo i < c.sizeUpTo (i + 1)

full_name: Composition.monotone_sizeUpTo
code: theorem monotone_sizeUpTo : Monotone c.sizeUpTo 
goal: Monotone c.sizeUpTo

full_name: Composition.boundary
code: /-- The `i`-th boundary of a composition, i.e., the leftmost point of the `i`-th block. We include
a virtual point at the right of the last block, to make for a nice equiv with
`CompositionAsSet n`. -/
def boundary : Fin (c.length + 1) ↪o Fin (n + 1) 
goal: Fin (c.length + 1) ↪o Fin (n + 1)

full_name: Composition.boundary_zero
code: @[simp]
theorem boundary_zero : c.boundary 0 = 0 
goal: c.boundary 0 = 0

full_name: Composition.boundary_last
code: @[simp]
theorem boundary_last : c.boundary (Fin.last c.length) = Fin.last n 
goal: c.boundary (Fin.last c.length) = Fin.last n

full_name: Composition.boundaries
code: /-- The boundaries of a composition, i.e., the leftmost point of all the blocks. We include
a virtual point at the right of the last block, to make for a nice equiv with
`CompositionAsSet n`. -/
def boundaries : Finset (Fin (n + 1)) 
goal: Finset (Fin (n + 1))

full_name: Composition.card_boundaries_eq_succ_length
code: theorem card_boundaries_eq_succ_length : c.boundaries.card = c.length + 1 
goal: c.boundaries.card = c.length + 1

full_name: Composition.toCompositionAsSet
code: /-- To `c : Composition n`, one can associate a `CompositionAsSet n` by registering the leftmost
point of each block, and adding a virtual point at the right of the last block. -/
def toCompositionAsSet : CompositionAsSet n 
goal: CompositionAsSet n

full_name: Composition.orderEmbOfFin_boundaries
code: /-- The canonical increasing bijection between `Fin (c.length + 1)` and `c.boundaries` is
exactly `c.boundary`. -/
theorem orderEmbOfFin_boundaries :
    c.boundaries.orderEmbOfFin c.card_boundaries_eq_succ_length = c.boundary 
goal: c.boundaries.orderEmbOfFin ⋯ = c.boundary

full_name: Composition.embedding
code: /-- Embedding the `i`-th block of a composition (identified with `Fin (c.blocks_fun i)`) into
`Fin n` at the relevant position. -/
def embedding (i : Fin c.length) : Fin (c.blocksFun i) ↪o Fin n 
goal: Fin (c.blocksFun i) ↪o Fin n

full_name: Composition.coe_embedding
code: @[simp]
theorem coe_embedding (i : Fin c.length) (j : Fin (c.blocksFun i)) :
    (c.embedding i j : ℕ) = c.sizeUpTo i + j 
goal: ↑((c.embedding i) j) = c.sizeUpTo ↑i + ↑j

full_name: Composition.index_exists
code: /-- `index_exists` asserts there is some `i` with `j < c.size_up_to (i+1)`.
In the next definition `index` we use `Nat.find` to produce the minimal such index.
-/
theorem index_exists {j : ℕ} (h : j < n) : ∃ i : ℕ, j < c.sizeUpTo (i + 1) ∧ i < c.length 
goal: ∃ i, j < c.sizeUpTo (i + 1) ∧ i < c.length

full_name: Composition.index
code: /-- `c.index j` is the index of the block in the composition `c` containing `j`. -/
def index (j : Fin n) : Fin c.length 
goal: Fin c.length

full_name: Composition.lt_sizeUpTo_index_succ
code: theorem lt_sizeUpTo_index_succ (j : Fin n) : (j : ℕ) < c.sizeUpTo (c.index j).succ 
goal: ↑j < c.sizeUpTo ↑(c.index j).succ

full_name: Composition.sizeUpTo_index_le
code: theorem sizeUpTo_index_le (j : Fin n) : c.sizeUpTo (c.index j) ≤ j 
goal: c.sizeUpTo ↑(c.index j) ≤ ↑j

full_name: Composition.invEmbedding
code: /-- Mapping an element `j` of `Fin n` to the element in the block containing it, identified with
`Fin (c.blocks_fun (c.index j))` through the canonical increasing bijection. -/
def invEmbedding (j : Fin n) : Fin (c.blocksFun (c.index j)) 
goal: Fin (c.blocksFun (c.index j))

full_name: Composition.coe_invEmbedding
code: @[simp]
theorem coe_invEmbedding (j : Fin n) : (c.invEmbedding j : ℕ) = j - c.sizeUpTo (c.index j) 
goal: ↑(c.invEmbedding j) = ↑j - c.sizeUpTo ↑(c.index j)

full_name: Composition.embedding_comp_inv
code: theorem embedding_comp_inv (j : Fin n) : c.embedding (c.index j) (c.invEmbedding j) = j 
goal: (c.embedding (c.index j)) (c.invEmbedding j) = j

full_name: Composition.mem_range_embedding_iff
code: theorem mem_range_embedding_iff {j : Fin n} {i : Fin c.length} :
    j ∈ Set.range (c.embedding i) ↔ c.sizeUpTo i ≤ j ∧ (j : ℕ) < c.sizeUpTo (i : ℕ).succ 
goal: j ∈ Set.range ⇑(c.embedding i) ↔ c.sizeUpTo ↑i ≤ ↑j ∧ ↑j < c.sizeUpTo (↑i).succ

full_name: Composition.disjoint_range
code: /-- The embeddings of different blocks of a composition are disjoint. -/
theorem disjoint_range {i₁ i₂ : Fin c.length} (h : i₁ ≠ i₂) :
    Disjoint (Set.range (c.embedding i₁)) (Set.range (c.embedding i₂)) 
goal: Disjoint (Set.range ⇑(c.embedding i₁)) (Set.range ⇑(c.embedding i₂))

full_name: Composition.mem_range_embedding
code: theorem mem_range_embedding (j : Fin n) : j ∈ Set.range (c.embedding (c.index j)) 
goal: j ∈ Set.range ⇑(c.embedding (c.index j))

full_name: Composition.mem_range_embedding_iff'
code: theorem mem_range_embedding_iff' {j : Fin n} {i : Fin c.length} :
    j ∈ Set.range (c.embedding i) ↔ i = c.index j 
goal: j ∈ Set.range ⇑(c.embedding i) ↔ i = c.index j

full_name: Composition.index_embedding
code: theorem index_embedding (i : Fin c.length) (j : Fin (c.blocksFun i)) :
    c.index (c.embedding i j) = i 
goal: c.index ((c.embedding i) j) = i

full_name: Composition.invEmbedding_comp
code: theorem invEmbedding_comp (i : Fin c.length) (j : Fin (c.blocksFun i)) :
    (c.invEmbedding (c.embedding i j) : ℕ) = j 
goal: ↑(c.invEmbedding ((c.embedding i) j)) = ↑j

full_name: Composition.blocksFinEquiv
code: /-- Equivalence between the disjoint union of the blocks (each of them seen as
`Fin (c.blocks_fun i)`) with `Fin n`. -/
def blocksFinEquiv : (Σi : Fin c.length, Fin (c.blocksFun i)) ≃ Fin n 
goal: (i : Fin c.length) × Fin (c.blocksFun i) ≃ Fin n

full_name: Composition.blocksFun_congr
code: theorem blocksFun_congr {n₁ n₂ : ℕ} (c₁ : Composition n₁) (c₂ : Composition n₂) (i₁ : Fin c₁.length)
    (i₂ : Fin c₂.length) (hn : n₁ = n₂) (hc : c₁.blocks = c₂.blocks) (hi : (i₁ : ℕ) = i₂) :
    c₁.blocksFun i₁ = c₂.blocksFun i₂ 
goal: c₁.blocksFun i₁ = c₂.blocksFun i₂

full_name: Composition.sigma_eq_iff_blocks_eq
code: /-- Two compositions (possibly of different integers) coincide if and only if they have the
same sequence of blocks. -/
theorem sigma_eq_iff_blocks_eq {c : Σn, Composition n} {c' : Σn, Composition n} :
    c = c' ↔ c.2.blocks = c'.2.blocks 
goal: c = c' ↔ c.snd.blocks = c'.snd.blocks

full_name: Composition.ones
code: /-- The composition made of blocks all of size `1`. -/
def ones (n : ℕ) : Composition n 
goal: Composition n

full_name: Composition.instInhabited
code: instance {n : ℕ} : Inhabited (Composition n) 
goal: Inhabited (Composition n)

full_name: Composition.ones_length
code: @[simp]
theorem ones_length (n : ℕ) : (ones n).length = n 
goal: (Composition.ones n).length = n

full_name: Composition.ones_blocks
code: @[simp]
theorem ones_blocks (n : ℕ) : (ones n).blocks = replicate n (1 : ℕ) 
goal: (Composition.ones n).blocks = List.replicate n 1

full_name: Composition.ones_blocksFun
code: @[simp]
theorem ones_blocksFun (n : ℕ) (i : Fin (ones n).length) : (ones n).blocksFun i = 1 
goal: (Composition.ones n).blocksFun i = 1

full_name: Composition.ones_sizeUpTo
code: @[simp]
theorem ones_sizeUpTo (n : ℕ) (i : ℕ) : (ones n).sizeUpTo i = min i n 
goal: (Composition.ones n).sizeUpTo i = min i n

full_name: Composition.ones_embedding
code: @[simp]
theorem ones_embedding (i : Fin (ones n).length) (h : 0 < (ones n).blocksFun i) :
    (ones n).embedding i ⟨0, h⟩ = ⟨i, lt_of_lt_of_le i.2 (ones n).length_le⟩ 
goal: ((Composition.ones n).embedding i) ⟨0, h⟩ = ⟨↑i, ⋯⟩

full_name: Composition.eq_ones_iff
code: theorem eq_ones_iff {c : Composition n} : c = ones n ↔ ∀ i ∈ c.blocks, i = 1 
goal: c = Composition.ones n ↔ ∀ i ∈ c.blocks, i = 1

full_name: Composition.ne_ones_iff
code: theorem ne_ones_iff {c : Composition n} : c ≠ ones n ↔ ∃ i ∈ c.blocks, 1 < i 
goal: c ≠ Composition.ones n ↔ ∃ i ∈ c.blocks, 1 < i

full_name: Composition.eq_ones_iff_length
code: theorem eq_ones_iff_length {c : Composition n} : c = ones n ↔ c.length = n 
goal: c = Composition.ones n ↔ c.length = n

full_name: Composition.eq_ones_iff_le_length
code: theorem eq_ones_iff_le_length {c : Composition n} : c = ones n ↔ n ≤ c.length 
goal: c = Composition.ones n ↔ n ≤ c.length

full_name: Composition.single
code: /-- The composition made of a single block of size `n`. -/
def single (n : ℕ) (h : 0 < n) : Composition n 
goal: Composition n

full_name: Composition.single_length
code: @[simp]
theorem single_length {n : ℕ} (h : 0 < n) : (single n h).length = 1 
goal: (Composition.single n h).length = 1

full_name: Composition.single_blocks
code: @[simp]
theorem single_blocks {n : ℕ} (h : 0 < n) : (single n h).blocks = [n] 
goal: (Composition.single n h).blocks = [n]

full_name: Composition.single_blocksFun
code: @[simp]
theorem single_blocksFun {n : ℕ} (h : 0 < n) (i : Fin (single n h).length) :
    (single n h).blocksFun i = n 
goal: (Composition.single n h).blocksFun i = n

full_name: Composition.single_embedding
code: @[simp]
theorem single_embedding {n : ℕ} (h : 0 < n) (i : Fin n) :
    ((single n h).embedding (0 : Fin 1)) i = i 
goal: ((Composition.single n h).embedding 0) i = i

full_name: Composition.eq_single_iff_length
code: theorem eq_single_iff_length {n : ℕ} (h : 0 < n) {c : Composition n} :
    c = single n h ↔ c.length = 1 
goal: c = Composition.single n h ↔ c.length = 1

full_name: Composition.ne_single_iff
code: theorem ne_single_iff {n : ℕ} (hn : 0 < n) {c : Composition n} :
    c ≠ single n hn ↔ ∀ i, c.blocksFun i < n 
goal: c ≠ Composition.single n hn ↔ ∀ (i : Fin c.length), c.blocksFun i < n

full_name: List.splitWrtCompositionAux
code: /-- Auxiliary for `List.splitWrtComposition`. -/
def splitWrtCompositionAux : List α → List ℕ → List (List α)
  
goal: List α → List ℕ → List (List α)

full_name: List.splitWrtComposition
code: /-- Given a list of length `n` and a composition `[i₁, ..., iₖ]` of `n`, split `l` into a list of
`k` lists corresponding to the blocks of the composition, of respective lengths `i₁`, ..., `iₖ`.
This makes sense mostly when `n = l.length`, but this is not necessary for the definition. -/
def splitWrtComposition (l : List α) (c : Composition n) : List (List α) 
goal: List (List α)

full_name: List.splitWrtCompositionAux_cons
code: @[local simp]
theorem splitWrtCompositionAux_cons (l : List α) (n ns) :
    l.splitWrtCompositionAux (n::ns) = take n l::(drop n l).splitWrtCompositionAux ns 
goal: l.splitWrtCompositionAux (n :: ns) = List.take n l :: (List.drop n l).splitWrtCompositionAux ns

full_name: List.length_splitWrtCompositionAux
code: theorem length_splitWrtCompositionAux (l : List α) (ns) :
    length (l.splitWrtCompositionAux ns) = ns.length 
goal: (l.splitWrtCompositionAux ns).length = ns.length

full_name: List.length_splitWrtComposition
code: /-- When one splits a list along a composition `c`, the number of sublists thus created is
`c.length`. -/
@[simp]
theorem length_splitWrtComposition (l : List α) (c : Composition n) :
    length (l.splitWrtComposition c) = c.length 
goal: (l.splitWrtComposition c).length = c.length

full_name: List.map_length_splitWrtCompositionAux
code: theorem map_length_splitWrtCompositionAux {ns : List ℕ} :
    ∀ {l : List α}, ns.sum ≤ l.length → map length (l.splitWrtCompositionAux ns) = ns 
goal: ns.sum ≤ l.length → List.map List.length (l.splitWrtCompositionAux ns) = ns

full_name: List.map_length_splitWrtComposition
code: /-- When one splits a list along a composition `c`, the lengths of the sublists thus created are
given by the block sizes in `c`. -/
theorem map_length_splitWrtComposition (l : List α) (c : Composition l.length) :
    map length (l.splitWrtComposition c) = c.blocks 
goal: List.map List.length (l.splitWrtComposition c) = c.blocks

full_name: List.length_pos_of_mem_splitWrtComposition
code: theorem length_pos_of_mem_splitWrtComposition {l l' : List α} {c : Composition l.length}
    (h : l' ∈ l.splitWrtComposition c) : 0 < length l' 
goal: 0 < l'.length

full_name: List.sum_take_map_length_splitWrtComposition
code: theorem sum_take_map_length_splitWrtComposition (l : List α) (c : Composition l.length) (i : ℕ) :
    (((l.splitWrtComposition c).map length).take i).sum = c.sizeUpTo i 
goal: (List.take i (List.map List.length (l.splitWrtComposition c))).sum = c.sizeUpTo i

full_name: List.getElem_splitWrtCompositionAux
code: theorem getElem_splitWrtCompositionAux (l : List α) (ns : List ℕ) {i : ℕ}
    (hi : i < (l.splitWrtCompositionAux ns).length) :
    (l.splitWrtCompositionAux ns)[i] =
      (l.take (ns.take (i + 1)).sum).drop (ns.take i).sum 
goal: (l.splitWrtCompositionAux ns)[i] = List.drop (List.take i ns).sum (List.take (List.take (i + 1) ns).sum l)

full_name: List.getElem_splitWrtComposition'
code: /-- The `i`-th sublist in the splitting of a list `l` along a composition `c`, is the slice of `l`
between the indices `c.sizeUpTo i` and `c.sizeUpTo (i+1)`, i.e., the indices in the `i`-th
block of the composition. -/
theorem getElem_splitWrtComposition' (l : List α) (c : Composition n) {i : ℕ}
    (hi : i < (l.splitWrtComposition c).length) :
    (l.splitWrtComposition c)[i] = (l.take (c.sizeUpTo (i + 1))).drop (c.sizeUpTo i) 
goal: (l.splitWrtComposition c)[i] = List.drop (c.sizeUpTo i) (List.take (c.sizeUpTo (i + 1)) l)

full_name: List.getElem_splitWrtComposition
code: theorem getElem_splitWrtComposition (l : List α) (c : Composition n)
    (i : Nat) (h : i < (l.splitWrtComposition c).length) :
    (l.splitWrtComposition c)[i] = (l.take (c.sizeUpTo (i + 1))).drop (c.sizeUpTo i) 
goal: (l.splitWrtComposition c)[i] = List.drop (c.sizeUpTo i) (List.take (c.sizeUpTo (i + 1)) l)

full_name: List.get_splitWrtCompositionAux
code: @[deprecated getElem_splitWrtCompositionAux (since := "2024-06-12")]
theorem get_splitWrtCompositionAux (l : List α) (ns : List ℕ) {i : ℕ} (hi) :
    (l.splitWrtCompositionAux ns).get ⟨i, hi⟩  =
      (l.take (ns.take (i + 1)).sum).drop (ns.take i).sum 
goal: (l.splitWrtCompositionAux ns).get ⟨i, hi⟩ = List.drop (List.take i ns).sum (List.take (List.take (i + 1) ns).sum l)

full_name: List.get_splitWrtComposition'
code: /-- The `i`-th sublist in the splitting of a list `l` along a composition `c`, is the slice of `l`
between the indices `c.sizeUpTo i` and `c.sizeUpTo (i+1)`, i.e., the indices in the `i`-th
block of the composition. -/
@[deprecated getElem_splitWrtComposition' (since := "2024-06-12")]
theorem get_splitWrtComposition' (l : List α) (c : Composition n) {i : ℕ}
    (hi : i < (l.splitWrtComposition c).length) :
    (l.splitWrtComposition c).get ⟨i, hi⟩ = (l.take (c.sizeUpTo (i + 1))).drop (c.sizeUpTo i) 
goal: (l.splitWrtComposition c).get ⟨i, hi⟩ = List.drop (c.sizeUpTo i) (List.take (c.sizeUpTo (i + 1)) l)

full_name: List.get_splitWrtComposition
code: @[deprecated getElem_splitWrtComposition (since := "2024-06-12")]
theorem get_splitWrtComposition (l : List α) (c : Composition n)
    (i : Fin (l.splitWrtComposition c).length) :
    get (l.splitWrtComposition c) i = (l.take (c.sizeUpTo (i + 1))).drop (c.sizeUpTo i) 
goal: (l.splitWrtComposition c).get i = List.drop (c.sizeUpTo ↑i) (List.take (c.sizeUpTo (↑i + 1)) l)

full_name: List.join_splitWrtCompositionAux
code: theorem join_splitWrtCompositionAux {ns : List ℕ} :
    ∀ {l : List α}, ns.sum = l.length → (l.splitWrtCompositionAux ns).join = l 
goal: ns.sum = l.length → (l.splitWrtCompositionAux ns).join = l

full_name: List.join_splitWrtComposition
code: /-- If one splits a list along a composition, and then joins the sublists, one gets back the
original list. -/
@[simp]
theorem join_splitWrtComposition (l : List α) (c : Composition l.length) :
    (l.splitWrtComposition c).join = l 
goal: (l.splitWrtComposition c).join = l

full_name: List.splitWrtComposition_join
code: /-- If one joins a list of lists and then splits the join along the right composition, one gets
back the original list of lists. -/
@[simp]
theorem splitWrtComposition_join (L : List (List α)) (c : Composition L.join.length)
    (h : map length L = c.blocks) : splitWrtComposition (join L) c = L 
goal: L.join.splitWrtComposition c = L

full_name: compositionAsSetEquiv
code: /-- Bijection between compositions of `n` and subsets of `{0, ..., n-2}`, defined by
considering the restriction of the subset to `{1, ..., n-1}` and shifting to the left by one. -/
def compositionAsSetEquiv (n : ℕ) : CompositionAsSet n ≃ Finset (Fin (n - 1)) 
goal: CompositionAsSet n ≃ Finset (Fin (n - 1))

full_name: compositionAsSetFintype
code: instance compositionAsSetFintype (n : ℕ) : Fintype (CompositionAsSet n) 
goal: Fintype (CompositionAsSet n)

full_name: compositionAsSet_card
code: theorem compositionAsSet_card (n : ℕ) : Fintype.card (CompositionAsSet n) = 2 ^ (n - 1) 
goal: Fintype.card (CompositionAsSet n) = 2 ^ (n - 1)

full_name: CompositionAsSet.boundaries_nonempty
code: theorem boundaries_nonempty : c.boundaries.Nonempty 
goal: c.boundaries.Nonempty

full_name: CompositionAsSet.card_boundaries_pos
code: theorem card_boundaries_pos : 0 < Finset.card c.boundaries 
goal: 0 < c.boundaries.card

full_name: CompositionAsSet.length
code: /-- Number of blocks in a `CompositionAsSet`. -/
def length : ℕ 
goal: ℕ

full_name: CompositionAsSet.card_boundaries_eq_succ_length
code: theorem card_boundaries_eq_succ_length : c.boundaries.card = c.length + 1 
goal: c.boundaries.card = c.length + 1

full_name: CompositionAsSet.length_lt_card_boundaries
code: theorem length_lt_card_boundaries : c.length < c.boundaries.card 
goal: c.length < c.boundaries.card

full_name: CompositionAsSet.lt_length
code: theorem lt_length (i : Fin c.length) : (i : ℕ) + 1 < c.boundaries.card 
goal: ↑i + 1 < c.boundaries.card

full_name: CompositionAsSet.lt_length'
code: theorem lt_length' (i : Fin c.length) : (i : ℕ) < c.boundaries.card 
goal: ↑i < c.boundaries.card

full_name: CompositionAsSet.boundary
code: /-- Canonical increasing bijection from `Fin c.boundaries.card` to `c.boundaries`. -/
def boundary : Fin c.boundaries.card ↪o Fin (n + 1) 
goal: Fin c.boundaries.card ↪o Fin (n + 1)

full_name: CompositionAsSet.boundary_zero
code: @[simp]
theorem boundary_zero : (c.boundary ⟨0, c.card_boundaries_pos⟩ : Fin (n + 1)) = 0 
goal: c.boundary ⟨0, ⋯⟩ = 0

full_name: CompositionAsSet.boundary_length
code: @[simp]
theorem boundary_length : c.boundary ⟨c.length, c.length_lt_card_boundaries⟩ = Fin.last n 
goal: c.boundary ⟨c.length, ⋯⟩ = Fin.last n

full_name: CompositionAsSet.blocksFun
code: /-- Size of the `i`-th block in a `CompositionAsSet`, seen as a function on `Fin c.length`. -/
def blocksFun (i : Fin c.length) : ℕ 
goal: ℕ

full_name: CompositionAsSet.blocksFun_pos
code: theorem blocksFun_pos (i : Fin c.length) : 0 < c.blocksFun i 
goal: 0 < c.blocksFun i

full_name: CompositionAsSet.blocks
code: /-- List of the sizes of the blocks in a `CompositionAsSet`. -/
def blocks (c : CompositionAsSet n) : List ℕ 
goal: List ℕ

full_name: CompositionAsSet.blocks_length
code: @[simp]
theorem blocks_length : c.blocks.length = c.length 
goal: c.blocks.length = c.length

full_name: CompositionAsSet.blocks_partial_sum
code: theorem blocks_partial_sum {i : ℕ} (h : i < c.boundaries.card) :
    (c.blocks.take i).sum = c.boundary ⟨i, h⟩ 
goal: (List.take i c.blocks).sum = ↑(c.boundary ⟨i, h⟩)

full_name: CompositionAsSet.mem_boundaries_iff_exists_blocks_sum_take_eq
code: theorem mem_boundaries_iff_exists_blocks_sum_take_eq {j : Fin (n + 1)} :
    j ∈ c.boundaries ↔ ∃ i < c.boundaries.card, (c.blocks.take i).sum = j 
goal: j ∈ c.boundaries ↔ ∃ i < c.boundaries.card, (List.take i c.blocks).sum = ↑j

full_name: CompositionAsSet.blocks_sum
code: theorem blocks_sum : c.blocks.sum = n 
goal: c.blocks.sum = n

full_name: CompositionAsSet.toComposition
code: /-- Associating a `Composition n` to a `CompositionAsSet n`, by registering the sizes of the
blocks as a list of positive integers. -/
def toComposition : Composition n 
goal: Composition n

full_name: Composition.toCompositionAsSet_length
code: @[simp]
theorem Composition.toCompositionAsSet_length (c : Composition n) :
    c.toCompositionAsSet.length = c.length 
goal: c.toCompositionAsSet.length = c.length

full_name: CompositionAsSet.toComposition_length
code: @[simp]
theorem CompositionAsSet.toComposition_length (c : CompositionAsSet n) :
    c.toComposition.length = c.length 
goal: c.toComposition.length = c.length

full_name: Composition.toCompositionAsSet_blocks
code: @[simp]
theorem Composition.toCompositionAsSet_blocks (c : Composition n) :
    c.toCompositionAsSet.blocks = c.blocks 
goal: c.toCompositionAsSet.blocks = c.blocks

full_name: CompositionAsSet.toComposition_blocks
code: @[simp]
theorem CompositionAsSet.toComposition_blocks (c : CompositionAsSet n) :
    c.toComposition.blocks = c.blocks 
goal: c.toComposition.blocks = c.blocks

full_name: CompositionAsSet.toComposition_boundaries
code: @[simp]
theorem CompositionAsSet.toComposition_boundaries (c : CompositionAsSet n) :
    c.toComposition.boundaries = c.boundaries 
goal: c.toComposition.boundaries = c.boundaries

full_name: Composition.toCompositionAsSet_boundaries
code: @[simp]
theorem Composition.toCompositionAsSet_boundaries (c : Composition n) :
    c.toCompositionAsSet.boundaries = c.boundaries 
goal: c.toCompositionAsSet.boundaries = c.boundaries

full_name: compositionEquiv
code: /-- Equivalence between `Composition n` and `CompositionAsSet n`. -/
def compositionEquiv (n : ℕ) : Composition n ≃ CompositionAsSet n 
goal: Composition n ≃ CompositionAsSet n

full_name: compositionFintype
code: instance compositionFintype (n : ℕ) : Fintype (Composition n) 
goal: Fintype (Composition n)

full_name: composition_card
code: theorem composition_card (n : ℕ) : Fintype.card (Composition n) = 2 ^ (n - 1) 
goal: Fintype.card (Composition n) = 2 ^ (n - 1)