doc-next-gen

Mathlib.Combinatorics.Enumerative.Composition

Module docstring

{"# Compositions

A composition of a natural number n is a decomposition n = i₀ + ... + i_{k-1} of n into a sum of positive integers. Combinatorially, it corresponds to a decomposition of {0, ..., n-1} into non-empty blocks of consecutive integers, where the iⱼ are the lengths of the blocks. This notion is closely related to that of a partition of n, but in a composition of n the order of the iⱼs matters.

We implement two different structures covering these two viewpoints on compositions. The first one, made of a list of positive integers summing to n, is the main one and is called Composition n. The second one is useful for combinatorial arguments (for instance to show that the number of compositions of n is 2^(n-1)). It is given by a subset of {0, ..., n} containing 0 and n, where the elements of the subset (other than n) correspond to the leftmost points of each block. The main API is built on Composition n, and we provide an equivalence between the two types.

Main functions

  • c : Composition n is a structure, made of a list of integers which are all positive and add up to n.
  • composition_card states that the cardinality of Composition n is exactly 2^(n-1), which is proved by constructing an equiv with CompositionAsSet n (see below), which is itself in bijection with the subsets of Fin (n-1) (this holds even for n = 0, where - is nat subtraction).

Let c : Composition n be a composition of n. Then * c.blocks is the list of blocks in c. * c.length is the number of blocks in the composition. * c.blocksFun : Fin c.length → ℕ is the realization of c.blocks as a function on Fin c.length. This is the main object when using compositions to understand the composition of analytic functions. * c.sizeUpTo : ℕ → ℕ is the sum of the size of the blocks up to i.; * c.embedding i : Fin (c.blocksFun i) → Fin n is the increasing embedding of the i-th block in Fin n; * c.index j, for j : Fin n, is the index of the block containing j.

  • Composition.ones n is the composition of n made of ones, i.e., [1, ..., 1].
  • Composition.single n (hn : 0 < n) is the composition of n made of a single block of size n.

Compositions can also be used to split lists. Let l be a list of length n and c a composition of n. * l.splitWrtComposition c is a list of lists, made of the slices of l corresponding to the blocks of c. * join_splitWrtComposition states that splitting a list and then joining it gives back the original list. * splitWrtComposition_join states that joining a list of lists, and then splitting it back according to the right composition, gives back the original list of lists.

We turn to the second viewpoint on compositions, that we realize as a finset of Fin (n+1). c : CompositionAsSet n is a structure made of a finset of Fin (n+1) called c.boundaries and proofs that it contains 0 and n. (Taking a finset of Fin n containing 0 would not make sense in the edge case n = 0, while the previous description works in all cases). The elements of this set (other than n) correspond to leftmost points of blocks. Thus, there is an equiv between Composition n and CompositionAsSet n. We only construct basic API on CompositionAsSet (notably c.length and c.blocks) to be able to construct this equiv, called compositionEquiv n. Since there is a straightforward equiv between CompositionAsSet n and finsets of {1, ..., n-1} (obtained by removing 0 and n from a CompositionAsSet and called compositionAsSetEquiv n), we deduce that CompositionAsSet n and Composition n are both fintypes of cardinality 2^(n - 1) (see compositionAsSet_card and composition_card).

Implementation details

The main motivation for this structure and its API is in the construction of the composition of formal multilinear series, and the proof that the composition of analytic functions is analytic.

The representation of a composition as a list is very handy as lists are very flexible and already have a well-developed API.

Tags

Composition, partition

References

https://en.wikipedia.org/wiki/Composition_(combinatorics) ","### Compositions

A composition of an integer n is a decomposition n = i₀ + ... + i_{k-1} of n into a sum of positive integers. ","### The composition Composition.ones ","### The composition Composition.single ","### Splitting a list

Given a list of length n and a composition c of n, one can split l into c.length sublists of respective lengths c.blocksFun 0, ..., c.blocksFun (c.length-1). This is inverse to the join operation. ","### Compositions as sets

Combinatorial viewpoints on compositions, seen as finite subsets of Fin (n+1) containing 0 and n, where the points of the set (other than n) correspond to the leftmost points of each block. ","### Equivalence between compositions and compositions as sets

In this section, we explain how to go back and forth between a Composition and a CompositionAsSet, by showing that their blocks and length and boundaries correspond to each other, and construct an equivalence between them called compositionEquiv. "}

Composition structure
(n : ℕ)
Full source
/-- 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
  deriving DecidableEq
Composition of a natural number
Informal description
A composition of a natural number $n$ is a list of positive integers $(i_0, \ldots, i_{k-1})$ such that $i_0 + \cdots + i_{k-1} = n$. Combinatorially, it corresponds to a decomposition of the set $\{0, \ldots, n-1\}$ into $k$ non-empty blocks of consecutive integers, where each $i_j$ is the size of the $j$-th block.
instDecidableEqComposition instance
{n✝} : DecidableEq✝ (@Composition✝ n✝)
Full source
DecidableEq
Decidable Equality for Compositions of Natural Numbers
Informal description
For any natural number $n$, there is a decidable equality on the type of compositions of $n$. That is, given two compositions $c_1$ and $c_2$ of $n$, we can algorithmically determine whether $c_1 = c_2$.
CompositionAsSet structure
(n : ℕ)
Full source
/-- 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.lastFin.last n ∈ boundaries
  deriving DecidableEq
Composition as a Set
Informal description
A combinatorial structure representing a composition of a natural number `n`, viewed as a finite subset of `{0, ..., n}` containing both `0` and `n`. The elements of this subset (excluding `n`) correspond to the leftmost points of consecutive non-empty blocks in `{0, ..., n-1}`. This structure is used to provide an alternative combinatorial perspective on compositions, particularly useful for counting arguments.
instDecidableEqCompositionAsSet instance
{n✝} : DecidableEq✝ (@CompositionAsSet✝ n✝)
Full source
DecidableEq
Decidable Equality for Set-Based Compositions
Informal description
For any natural number $n$, there is a decidable equality on the type of compositions of $n$ viewed as sets. That is, given two set-based compositions $c_1$ and $c_2$ of $n$, we can algorithmically determine whether $c_1 = c_2$.
Composition.instToString instance
(n : ℕ) : ToString (Composition n)
Full source
instance (n : ) : ToString (Composition n) :=
  ⟨fun c => toString c.blocks⟩
String Representation of Compositions
Informal description
For any natural number $n$, the type `Composition n` has a string representation. This allows compositions of $n$ to be displayed as strings, typically showing the list of blocks in the composition.
Composition.length abbrev
: ℕ
Full source
/-- The length of a composition, i.e., the number of blocks in the composition. -/
abbrev length :  :=
  c.blocks.length
Number of Blocks in a Composition
Informal description
For a composition $c$ of a natural number $n$, the length of $c$ is the number of blocks in the composition, i.e., the number of positive integers in the decomposition $n = i_0 + \cdots + i_{k-1}$.
Composition.blocks_length theorem
: c.blocks.length = c.length
Full source
theorem blocks_length : c.blocks.length = c.length :=
  rfl
Length of Blocks List Equals Composition Length
Informal description
For any composition $c$ of a natural number $n$, the length of the list of blocks $c.\mathrm{blocks}$ is equal to the number of blocks $c.\mathrm{length}$ in the composition.
Composition.blocksFun definition
: Fin c.length → ℕ
Full source
/-- 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 := c.blocks.get
Block sizes as a function
Informal description
For a composition \( c \) of a natural number \( n \), the function \( c.\mathrm{blocksFun} \) maps each index \( i \in \mathrm{Fin}\, c.\mathrm{length} \) (i.e., \( i \) ranges from \( 0 \) to \( c.\mathrm{length} - 1 \)) to the size of the \( i \)-th block in the composition. This provides a functional representation of the list of blocks \( c.\mathrm{blocks} \), where \( c.\mathrm{blocksFun}\, i \) gives the \( i \)-th element of the list.
Composition.ofFn_blocksFun theorem
: ofFn c.blocksFun = c.blocks
Full source
@[simp]
theorem ofFn_blocksFun : ofFn c.blocksFun = c.blocks :=
  ofFn_get _
List of Block Sizes Equals Blocks List in Composition
Informal description
For a composition $c$ of a natural number $n$, the list obtained by evaluating the block size function $c.\mathrm{blocksFun}$ at all indices $i \in \mathrm{Fin}\, c.\mathrm{length}$ is equal to the list of blocks $c.\mathrm{blocks}$.
Composition.sum_blocksFun theorem
: ∑ i, c.blocksFun i = n
Full source
@[simp]
theorem sum_blocksFun : ∑ i, c.blocksFun i = n := by
  conv_rhs => rw [← c.blocks_sum, ← ofFn_blocksFun, sum_ofFn]
Sum of Block Sizes Equals Original Number in Composition
Informal description
For any composition $c$ of a natural number $n$, the sum of the block sizes $c.\mathrm{blocksFun}\, i$ over all indices $i \in \mathrm{Fin}\, c.\mathrm{length}$ equals $n$.
Composition.blocksFun_mem_blocks theorem
(i : Fin c.length) : c.blocksFun i ∈ c.blocks
Full source
@[simp]
theorem blocksFun_mem_blocks (i : Fin c.length) : c.blocksFun i ∈ c.blocks :=
  get_mem _ _
Block Size Function Yields Elements of Blocks List in Composition
Informal description
For any composition $c$ of a natural number $n$ and any index $i$ in the finite set $\{0, \ldots, c.\mathrm{length}-1\}$, the $i$-th block size $c.\mathrm{blocksFun}\, i$ is an element of the list of blocks $c.\mathrm{blocks}$.
Composition.one_le_blocks theorem
{i : ℕ} (h : i ∈ c.blocks) : 1 ≤ i
Full source
theorem one_le_blocks {i : } (h : i ∈ c.blocks) : 1 ≤ i :=
  c.blocks_pos h
Positivity of Block Sizes in Composition
Informal description
For any composition $c$ of a natural number $n$, and for any block size $i$ in the list of blocks of $c$, we have $1 \leq i$.
Composition.blocks_le theorem
{i : ℕ} (h : i ∈ c.blocks) : i ≤ n
Full source
theorem blocks_le {i : } (h : i ∈ c.blocks) : i ≤ n := by
  rw [← c.blocks_sum]
  exact List.le_sum_of_mem h
Block Size Bound in Composition
Informal description
For any composition $c$ of a natural number $n$, and for any block size $i$ in the list of blocks of $c$, we have $i \leq n$.
Composition.one_le_blocks' theorem
{i : ℕ} (h : i < c.length) : 1 ≤ c.blocks[i]
Full source
@[simp]
theorem one_le_blocks' {i : } (h : i < c.length) : 1 ≤ c.blocks[i] :=
  c.one_le_blocks (get_mem (blocks c) _)
Positivity of Block Sizes in Composition by Index
Informal description
For any composition $c$ of a natural number $n$ and any index $i$ such that $i < c.\text{length}$, the $i$-th block size satisfies $1 \leq c.\text{blocks}[i]$.
Composition.blocks_pos' theorem
(i : ℕ) (h : i < c.length) : 0 < c.blocks[i]
Full source
@[simp]
theorem blocks_pos' (i : ) (h : i < c.length) : 0 < c.blocks[i] :=
  c.one_le_blocks' h
Positivity of Block Sizes in Composition by Index: $0 < c.\text{blocks}[i]$
Informal description
For any composition $c$ of a natural number $n$ and any index $i$ such that $i < c.\text{length}$, the $i$-th block size satisfies $0 < c.\text{blocks}[i]$.
Composition.one_le_blocksFun theorem
(i : Fin c.length) : 1 ≤ c.blocksFun i
Full source
@[simp]
theorem one_le_blocksFun (i : Fin c.length) : 1 ≤ c.blocksFun i :=
  c.one_le_blocks (c.blocksFun_mem_blocks i)
Positivity of Block Sizes in Composition via Index Function
Informal description
For any composition $c$ of a natural number $n$ and any index $i$ in the finite set $\{0, \ldots, c.\mathrm{length} - 1\}$, the size of the $i$-th block satisfies $1 \leq c.\mathrm{blocksFun}\, i$.
Composition.blocksFun_le theorem
{n} (c : Composition n) (i : Fin c.length) : c.blocksFun i ≤ n
Full source
@[simp]
theorem blocksFun_le {n} (c : Composition n) (i : Fin c.length) :
    c.blocksFun i ≤ n :=
  c.blocks_le <| getElem_mem _
Block Size Bound in Composition: $c.\mathrm{blocksFun}\, i \leq n$
Informal description
For any composition $c$ of a natural number $n$ and any index $i$ in the finite set $\{0, \ldots, c.\mathrm{length} - 1\}$, the size of the $i$-th block in $c$ satisfies $c.\mathrm{blocksFun}\, i \leq n$.
Composition.length_le theorem
: c.length ≤ n
Full source
@[simp]
theorem length_le : c.length ≤ n := by
  conv_rhs => rw [← c.blocks_sum]
  exact length_le_sum_of_one_le _ fun i hi => c.one_le_blocks hi
Upper Bound on Number of Blocks in a Composition
Informal description
For any composition $c$ of a natural number $n$, the number of blocks in $c$ is at most $n$, i.e., $c.\text{length} \leq n$.
Composition.length_eq_zero theorem
: c.length = 0 ↔ n = 0
Full source
protected theorem length_eq_zero : c.length = 0 ↔ n = 0 := by
  simp
Zero Length Composition iff Zero Sum
Informal description
For a composition $c$ of a natural number $n$, the number of blocks $c.\text{length}$ is zero if and only if $n = 0$.
Composition.length_pos_iff theorem
: 0 < c.length ↔ 0 < n
Full source
@[simp]
theorem length_pos_iff : 0 < c.length ↔ 0 < n := by
  simp [pos_iff_ne_zero]
Positive Length Composition iff Positive Sum
Informal description
For a composition $c$ of a natural number $n$, the composition has at least one block (i.e., $0 < c.\text{length}$) if and only if $n$ is positive (i.e., $0 < n$).
Composition.sizeUpTo definition
(i : ℕ) : ℕ
Full source
/-- The sum of the sizes of the blocks in a composition up to `i`. -/
def sizeUpTo (i : ) :  :=
  (c.blocks.take i).sum
Sum of first $i$ blocks in a composition
Informal description
Given a composition $c$ of a natural number $n$ and an index $i$, the function $\text{sizeUpTo}$ computes the sum of the sizes of the first $i$ blocks in the composition. More precisely, if $c$ is represented by the list of positive integers $[i_0, \ldots, i_{k-1}]$ summing to $n$, then $\text{sizeUpTo}(i) = i_0 + \cdots + i_{\min(i, k)-1}$.
Composition.sizeUpTo_zero theorem
: c.sizeUpTo 0 = 0
Full source
@[simp]
theorem sizeUpTo_zero : c.sizeUpTo 0 = 0 := by simp [sizeUpTo]
Sum of Zero Blocks is Zero in Composition
Informal description
For any composition $c$ of a natural number $n$, the sum of the sizes of the first $0$ blocks is $0$, i.e., $c.\text{sizeUpTo}(0) = 0$.
Composition.sizeUpTo_ofLength_le theorem
(i : ℕ) (h : c.length ≤ i) : c.sizeUpTo i = n
Full source
theorem sizeUpTo_ofLength_le (i : ) (h : c.length ≤ i) : c.sizeUpTo i = n := by
  dsimp [sizeUpTo]
  convert c.blocks_sum
  exact take_of_length_le h
Sum of All Blocks Equals $n$ When Index Exceeds Composition Length
Informal description
For any composition $c$ of a natural number $n$ and any natural number $i$ such that the number of blocks in $c$ is at most $i$, the sum of the sizes of the first $i$ blocks equals $n$. In other words, if $c.\text{length} \leq i$, then $c.\text{sizeUpTo}(i) = n$.
Composition.sizeUpTo_length theorem
: c.sizeUpTo c.length = n
Full source
@[simp]
theorem sizeUpTo_length : c.sizeUpTo c.length = n :=
  c.sizeUpTo_ofLength_le c.length le_rfl
Total Sum of Composition Blocks Equals $n$
Informal description
For any composition $c$ of a natural number $n$, the sum of the sizes of all blocks in $c$ equals $n$, i.e., $\sum_{i=0}^{c.\text{length}-1} c.\text{blocks}[i] = n$.
Composition.sizeUpTo_le theorem
(i : ℕ) : c.sizeUpTo i ≤ n
Full source
theorem sizeUpTo_le (i : ) : c.sizeUpTo i ≤ n := by
  conv_rhs => rw [← c.blocks_sum, ← sum_take_add_sum_drop _ i]
  exact Nat.le_add_right _ _
Partial Sum of Composition Blocks is Bounded by $n$
Informal description
For any composition $c$ of a natural number $n$ and any natural number $i$, the sum of the sizes of the first $i$ blocks in $c$ is less than or equal to $n$, i.e., $\text{sizeUpTo}(c, i) \leq n$.
Composition.sizeUpTo_succ theorem
{i : ℕ} (h : i < c.length) : c.sizeUpTo (i + 1) = c.sizeUpTo i + c.blocks[i]
Full source
theorem sizeUpTo_succ {i : } (h : i < c.length) :
    c.sizeUpTo (i + 1) = c.sizeUpTo i + c.blocks[i] := by
  simp only [sizeUpTo]
  rw [sum_take_succ _ _ h]
Recursive Formula for Partial Sum of Composition Blocks
Informal description
Let $c$ be a composition of a natural number $n$, and let $i$ be a natural number such that $i$ is less than the number of blocks in $c$. Then the sum of the sizes of the first $i+1$ blocks is equal to the sum of the sizes of the first $i$ blocks plus the size of the $(i+1)$-th block, i.e., \[ \text{sizeUpTo}(c, i+1) = \text{sizeUpTo}(c, i) + c.\text{blocks}[i]. \]
Composition.sizeUpTo_succ' theorem
(i : Fin c.length) : c.sizeUpTo ((i : ℕ) + 1) = c.sizeUpTo i + c.blocksFun i
Full source
theorem sizeUpTo_succ' (i : Fin c.length) :
    c.sizeUpTo ((i : ) + 1) = c.sizeUpTo i + c.blocksFun i :=
  c.sizeUpTo_succ i.2
Recursive Formula for Partial Sum of Composition Blocks (Indexed Version)
Informal description
Let $c$ be a composition of a natural number $n$, and let $i$ be an index of a block in $c$ (i.e., $i \in \mathrm{Fin}\, c.\mathrm{length}$). Then the sum of the sizes of the first $i+1$ blocks is equal to the sum of the sizes of the first $i$ blocks plus the size of the $(i+1)$-th block, i.e., \[ \mathrm{sizeUpTo}(i + 1) = \mathrm{sizeUpTo}(i) + c.\mathrm{blocksFun}(i). \]
Composition.sizeUpTo_strict_mono theorem
{i : ℕ} (h : i < c.length) : c.sizeUpTo i < c.sizeUpTo (i + 1)
Full source
theorem sizeUpTo_strict_mono {i : } (h : i < c.length) : c.sizeUpTo i < c.sizeUpTo (i + 1) := by
  rw [c.sizeUpTo_succ h]
  simp
Strict Monotonicity of Partial Sums in a Composition
Informal description
For any composition $c$ of a natural number $n$ and any natural number $i$ such that $i$ is less than the number of blocks in $c$, the partial sum of the first $i$ blocks is strictly less than the partial sum of the first $i+1$ blocks, i.e., \[ \text{sizeUpTo}(c, i) < \text{sizeUpTo}(c, i+1). \]
Composition.monotone_sizeUpTo theorem
: Monotone c.sizeUpTo
Full source
theorem monotone_sizeUpTo : Monotone c.sizeUpTo :=
  monotone_sum_take _
Monotonicity of Partial Sums in a Composition
Informal description
For any composition $c$ of a natural number $n$, the function $\mathrm{sizeUpTo}$ is monotone. That is, for any natural numbers $i \leq j$, we have $\mathrm{sizeUpTo}(i) \leq \mathrm{sizeUpTo}(j)$.
Composition.boundary definition
: Fin (c.length + 1) ↪o Fin (n + 1)
Full source
/-- 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 : FinFin (c.length + 1) ↪o Fin (n + 1) :=
  (OrderEmbedding.ofStrictMono fun i => ⟨c.sizeUpTo i, Nat.lt_succ_of_le (c.sizeUpTo_le i)⟩) <|
    Fin.strictMono_iff_lt_succ.2 fun ⟨_, hi⟩ => c.sizeUpTo_strict_mono hi
Boundary points of a composition
Informal description
For a composition $c$ of a natural number $n$, the boundary function maps each index $i$ (where $0 \leq i \leq c.\text{length}$) to the leftmost point of the $i$-th block in the decomposition of $\{0, \ldots, n-1\}$. This is realized as an order-embedding from $\text{Fin}(c.\text{length} + 1)$ to $\text{Fin}(n + 1)$, where the virtual point at the right of the last block is included. Specifically, the boundary at index $i$ is given by the partial sum $\text{sizeUpTo}(i)$ of the first $i$ blocks.
Composition.boundary_zero theorem
: c.boundary 0 = 0
Full source
@[simp]
theorem boundary_zero : c.boundary 0 = 0 := by simp [boundary, Fin.ext_iff]
Initial Boundary Condition for Compositions: $c.\text{boundary}(0) = 0$
Informal description
For any composition $c$ of a natural number $n$, the boundary function evaluated at the initial index $0$ yields $0$, i.e., $c.\text{boundary}(0) = 0$.
Composition.boundary_last theorem
: c.boundary (Fin.last c.length) = Fin.last n
Full source
@[simp]
theorem boundary_last : c.boundary (Fin.last c.length) = Fin.last n := by
  simp [boundary, Fin.ext_iff]
Last Boundary Point of a Composition Equals $n$
Informal description
For a composition $c$ of a natural number $n$, the boundary function evaluated at the last index (i.e., $c.\text{length}$) equals the last element of $\text{Fin}(n + 1)$. In other words, the rightmost boundary point of the composition corresponds to the endpoint $n$ in the decomposition of $\{0, \ldots, n-1\}$.
Composition.boundaries definition
: Finset (Fin (n + 1))
Full source
/-- 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)) :=
  Finset.univ.map c.boundary.toEmbedding
Boundaries of a composition
Informal description
The boundaries of a composition $c$ of a natural number $n$ is the finset consisting of the leftmost points of all blocks in the decomposition of $\{0, \ldots, n-1\}$, together with a virtual point at the right of the last block. This is constructed as the image of the order-embedding `c.boundary` from $\text{Fin}(c.\text{length} + 1)$ to $\text{Fin}(n + 1)$ under the canonical embedding into the finset of all points.
Composition.card_boundaries_eq_succ_length theorem
: c.boundaries.card = c.length + 1
Full source
theorem card_boundaries_eq_succ_length : c.boundaries.card = c.length + 1 := by simp [boundaries]
Cardinality of Boundaries Equals Length Plus One
Informal description
For a composition $c$ of a natural number $n$, the number of boundary points in $c$ is equal to the number of blocks plus one, i.e., $|c.\text{boundaries}| = c.\text{length} + 1$.
Composition.toCompositionAsSet definition
: CompositionAsSet n
Full source
/-- 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 where
  boundaries := c.boundaries
  zero_mem := by
    simp only [boundaries, Finset.mem_univ, exists_prop_of_true, Finset.mem_map]
    exact ⟨0, And.intro True.intro rfl⟩
  getLast_mem := by
    simp only [boundaries, Finset.mem_univ, exists_prop_of_true, Finset.mem_map]
    exact ⟨Fin.last c.length, And.intro True.intro c.boundary_last⟩
Conversion from Composition to CompositionAsSet
Informal description
Given a composition $c$ of a natural number $n$, the function `Composition.toCompositionAsSet` constructs a `CompositionAsSet n` by taking the boundaries of $c$ (the leftmost points of each block together with a virtual endpoint) and verifying that $0$ and $n$ are included in these boundaries. More precisely, the boundaries are defined as the image of the order-embedding `c.boundary` from $\text{Fin}(c.\text{length} + 1)$ to $\text{Fin}(n + 1)$, ensuring that the first boundary is $0$ and the last boundary corresponds to $n$.
Composition.orderEmbOfFin_boundaries theorem
: c.boundaries.orderEmbOfFin c.card_boundaries_eq_succ_length = c.boundary
Full source
/-- 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 := by
  refine (Finset.orderEmbOfFin_unique' _ ?_).symm
  exact fun i => (Finset.mem_map' _).2 (Finset.mem_univ _)
Canonical Order-Embedding of Composition Boundaries Matches Boundary Function
Informal description
For a composition $c$ of a natural number $n$, the canonical order-embedding of the finite set $\text{Fin}(c.\text{length} + 1)$ into the boundaries of $c$ (which is a finset of $\text{Fin}(n + 1)$) coincides with the boundary function $c.\text{boundary}$ of the composition.
Composition.embedding definition
(i : Fin c.length) : Fin (c.blocksFun i) ↪o Fin n
Full source
/-- Embedding the `i`-th block of a composition (identified with `Fin (c.blocksFun i)`) into
`Fin n` at the relevant position. -/
def embedding (i : Fin c.length) : FinFin (c.blocksFun i) ↪o Fin n :=
  (Fin.natAddOrderEmb <| c.sizeUpTo i).trans <| Fin.castLEOrderEmb <|
    calc
      c.sizeUpTo i + c.blocksFun i = c.sizeUpTo (i + 1) := (c.sizeUpTo_succ i.2).symm
      _ ≤ c.sizeUpTo c.length := monotone_sum_take _ i.2
      _ = n := c.sizeUpTo_length
Order embedding of a block in a composition
Informal description
For a composition \( c \) of a natural number \( n \) and an index \( i \) (representing the \( i \)-th block of the composition), the embedding \( c.\text{embedding}\, i \) is an order-preserving injection from the finite set \( \text{Fin}\, (c.\text{blocksFun}\, i) \) (representing the indices within the \( i \)-th block) into \( \text{Fin}\, n \) (representing the indices of the overall composition). More concretely, this embedding maps each element \( j \in \text{Fin}\, (c.\text{blocksFun}\, i) \) to the position \( c.\text{sizeUpTo}\, i + j \) in \( \text{Fin}\, n \), where \( c.\text{sizeUpTo}\, i \) is the sum of the sizes of the first \( i \) blocks. The embedding preserves the order, meaning that if \( j_1 \leq j_2 \) in \( \text{Fin}\, (c.\text{blocksFun}\, i) \), then \( c.\text{embedding}\, i\, j_1 \leq c.\text{embedding}\, i\, j_2 \) in \( \text{Fin}\, n \).
Composition.coe_embedding theorem
(i : Fin c.length) (j : Fin (c.blocksFun i)) : (c.embedding i j : ℕ) = c.sizeUpTo i + j
Full source
@[simp]
theorem coe_embedding (i : Fin c.length) (j : Fin (c.blocksFun i)) :
    (c.embedding i j : ) = c.sizeUpTo i + j :=
  rfl
Embedding Formula for Composition Blocks: $c.\text{embedding}\, i\, j = c.\text{sizeUpTo}\, i + j$
Informal description
For a composition $c$ of a natural number $n$, an index $i$ of a block in $c$, and an element $j$ within the $i$-th block, the embedding function $c.\text{embedding}\, i\, j$ maps $j$ to the natural number $c.\text{sizeUpTo}\, i + j$, where $\text{sizeUpTo}\, i$ is the sum of the sizes of the first $i$ blocks in $c$.
Composition.index_exists theorem
{j : ℕ} (h : j < n) : ∃ i : ℕ, j < c.sizeUpTo (i + 1) ∧ i < c.length
Full source
/-- `index_exists` asserts there is some `i` with `j < c.sizeUpTo (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 := by
  have n_pos : 0 < n := lt_of_le_of_lt (zero_le j) h
  have : 0 < c.blocks.sum := by rwa [← c.blocks_sum] at n_pos
  have length_pos : 0 < c.blocks.length := length_pos_of_sum_pos (blocks c) this
  refine ⟨c.length - 1, ?_, Nat.pred_lt (ne_of_gt length_pos)⟩
  have : c.length - 1 + 1 = c.length := Nat.succ_pred_eq_of_pos length_pos
  simp [this, h]
Existence of Block Index in Composition
Informal description
For any composition $c$ of a natural number $n$ and any natural number $j < n$, there exists an index $i$ such that $j < c.\text{sizeUpTo}(i + 1)$ and $i < c.\text{length}$.
Composition.index definition
(j : Fin n) : Fin c.length
Full source
/-- `c.index j` is the index of the block in the composition `c` containing `j`. -/
def index (j : Fin n) : Fin c.length :=
  ⟨Nat.find (c.index_exists j.2), (Nat.find_spec (c.index_exists j.2)).2⟩
Index of the block containing an element in a composition
Informal description
For a composition $c$ of a natural number $n$ and an element $j \in \{0, \ldots, n-1\}$, the function $\text{index}$ returns the index $i$ of the block in $c$ that contains $j$. More precisely, if $c$ is represented by the list of positive integers $[i_0, \ldots, i_{k-1}]$ summing to $n$, then $\text{index}(j)$ is the unique $i$ such that $i_0 + \cdots + i_{i-1} \leq j < i_0 + \cdots + i_i$.
Composition.lt_sizeUpTo_index_succ theorem
(j : Fin n) : (j : ℕ) < c.sizeUpTo (c.index j).succ
Full source
theorem lt_sizeUpTo_index_succ (j : Fin n) : (j : ) < c.sizeUpTo (c.index j).succ :=
  (Nat.find_spec (c.index_exists j.2)).1
Strict Upper Bound on Element Position in Composition Block
Informal description
For any composition $c$ of a natural number $n$ and any element $j \in \{0, \ldots, n-1\}$, the value of $j$ is strictly less than the sum of the sizes of the first $i+1$ blocks, where $i$ is the index of the block containing $j$. In other words, if $i$ is the index of the block containing $j$ (i.e., $i = c.\text{index}(j)$), then $j < c.\text{sizeUpTo}(i + 1)$.
Composition.sizeUpTo_index_le theorem
(j : Fin n) : c.sizeUpTo (c.index j) ≤ j
Full source
theorem sizeUpTo_index_le (j : Fin n) : c.sizeUpTo (c.index j) ≤ j := by
  by_contra H
  set i := c.index j
  push_neg at H
  have i_pos : (0 : ) < i := by
    by_contra! i_pos
    revert H
    simp [nonpos_iff_eq_zero.1 i_pos, c.sizeUpTo_zero]
  let i₁ := (i : ).pred
  have i₁_lt_i : i₁ < i := Nat.pred_lt (ne_of_gt i_pos)
  have i₁_succ : i₁ + 1 = i := Nat.succ_pred_eq_of_pos i_pos
  have := Nat.find_min (c.index_exists j.2) i₁_lt_i
  simp [lt_trans i₁_lt_i (c.index j).2, i₁_succ] at this
  exact Nat.lt_le_asymm H this
Lower Bound on Block Sum in Composition: $\text{sizeUpTo}(\text{index}(j)) \leq j$
Informal description
For any composition $c$ of a natural number $n$ and any element $j \in \{0, \ldots, n-1\}$, the sum of the sizes of the blocks up to the index of $j$ is less than or equal to $j$. In other words, if $i$ is the index of the block containing $j$, then $c.\text{sizeUpTo}(i) \leq j$.
Composition.invEmbedding definition
(j : Fin n) : Fin (c.blocksFun (c.index j))
Full source
/-- Mapping an element `j` of `Fin n` to the element in the block containing it, identified with
`Fin (c.blocksFun (c.index j))` through the canonical increasing bijection. -/
def invEmbedding (j : Fin n) : Fin (c.blocksFun (c.index j)) :=
  ⟨j - c.sizeUpTo (c.index j), by
    rw [tsub_lt_iff_right, add_comm, ← sizeUpTo_succ']
    · exact lt_sizeUpTo_index_succ _ _
    · exact sizeUpTo_index_le _ _⟩
Relative position within a block in a composition
Informal description
For a composition \( c \) of a natural number \( n \) and an element \( j \in \{0, \ldots, n-1\} \), the function \( \text{invEmbedding} \) maps \( j \) to its position within its block, identified as an element of \( \text{Fin}(c.\text{blocksFun}(c.\text{index} j)) \). More precisely, if \( j \) belongs to the \( i \)-th block of \( c \), then \( \text{invEmbedding}(j) \) is the relative position of \( j \) within that block, i.e., \( j - c.\text{sizeUpTo} i \).
Composition.coe_invEmbedding theorem
(j : Fin n) : (c.invEmbedding j : ℕ) = j - c.sizeUpTo (c.index j)
Full source
@[simp]
theorem coe_invEmbedding (j : Fin n) : (c.invEmbedding j : ) = j - c.sizeUpTo (c.index j) :=
  rfl
Relative position formula: $\text{invEmbedding}(j) = j - \text{sizeUpTo}(\text{index}(j))$
Informal description
For any composition $c$ of a natural number $n$ and any element $j \in \{0, \ldots, n-1\}$, the natural number value of the relative position of $j$ within its block equals $j$ minus the sum of the sizes of all preceding blocks. More precisely, if $j$ belongs to the $i$-th block of $c$, then the position of $j$ within its block is given by $j - \sum_{k=0}^{i-1} c_k$, where $c_k$ is the size of the $k$-th block.
Composition.embedding_comp_inv theorem
(j : Fin n) : c.embedding (c.index j) (c.invEmbedding j) = j
Full source
theorem embedding_comp_inv (j : Fin n) : c.embedding (c.index j) (c.invEmbedding j) = j := by
  rw [Fin.ext_iff]
  apply add_tsub_cancel_of_le (c.sizeUpTo_index_le j)
Embedding-Retraction Property of Compositions: $c.\text{embedding}(c.\text{index}(j))(c.\text{invEmbedding}(j)) = j$
Informal description
For any composition $c$ of a natural number $n$ and any element $j \in \{0, \ldots, n-1\}$, the embedding of the block containing $j$ maps the relative position of $j$ within its block back to $j$ itself. More precisely, if $i$ is the index of the block containing $j$ and $k$ is the relative position of $j$ within that block, then the embedding function satisfies $c.\text{embedding}\, i\, k = j$.
Composition.mem_range_embedding_iff theorem
{j : Fin n} {i : Fin c.length} : j ∈ Set.range (c.embedding i) ↔ c.sizeUpTo i ≤ j ∧ (j : ℕ) < c.sizeUpTo (i : ℕ).succ
Full source
theorem mem_range_embedding_iff {j : Fin n} {i : Fin c.length} :
    j ∈ Set.range (c.embedding i)j ∈ Set.range (c.embedding i) ↔ c.sizeUpTo i ≤ j ∧ (j : ℕ) < c.sizeUpTo (i : ℕ).succ := by
  constructor
  · intro h
    rcases Set.mem_range.2 h with ⟨k, hk⟩
    rw [Fin.ext_iff] at hk
    dsimp at hk
    rw [← hk]
    simp [sizeUpTo_succ', k.is_lt]
  · intro h
    apply Set.mem_range.2
    refine ⟨⟨j - c.sizeUpTo i, ?_⟩, ?_⟩
    · rw [tsub_lt_iff_left, ← sizeUpTo_succ']
      · exact h.2
      · exact h.1
    · rw [Fin.ext_iff]
      exact add_tsub_cancel_of_le h.1
Characterization of Range Membership in Composition Embedding
Informal description
For a composition $c$ of a natural number $n$, an element $j \in \{0, \ldots, n-1\}$, and an index $i$ of a block in $c$, the element $j$ belongs to the range of the embedding of the $i$-th block if and only if $j$ lies between the sum of the sizes of the first $i$ blocks and the sum of the sizes of the first $i+1$ blocks. More precisely, $j$ is in the range of $c.\text{embedding}\, i$ if and only if: \[ c.\text{sizeUpTo}\, i \leq j < c.\text{sizeUpTo}\, (i + 1). \]
Composition.disjoint_range theorem
{i₁ i₂ : Fin c.length} (h : i₁ ≠ i₂) : Disjoint (Set.range (c.embedding i₁)) (Set.range (c.embedding i₂))
Full source
/-- 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₂)) := by
  classical
    wlog h' : i₁ < i₂
    · exact (this c h.symm (h.lt_or_lt.resolve_left h')).symm
    by_contra d
    obtain ⟨x, hx₁, hx₂⟩ :
      ∃ x : Fin n, x ∈ Set.range (c.embedding i₁) ∧ x ∈ Set.range (c.embedding i₂) :=
      Set.not_disjoint_iff.1 d
    have A : (i₁ : ).succ ≤ i₂ := Nat.succ_le_of_lt h'
    apply lt_irrefl (x : )
    calc
      (x : ) < c.sizeUpTo (i₁ : ).succ := (c.mem_range_embedding_iff.1 hx₁).2
      _ ≤ c.sizeUpTo (i₂ : ) := monotone_sum_take _ A
      _ ≤ x := (c.mem_range_embedding_iff.1 hx₂).1
Disjointness of Block Embeddings in a Composition
Informal description
For any composition $c$ of a natural number $n$ and any two distinct indices $i_1$ and $i_2$ of blocks in $c$, the ranges of the embeddings of the $i_1$-th and $i_2$-th blocks are disjoint. That is, the sets $\mathrm{range}(c.\mathrm{embedding}\, i_1)$ and $\mathrm{range}(c.\mathrm{embedding}\, i_2)$ have no common elements.
Composition.mem_range_embedding theorem
(j : Fin n) : j ∈ Set.range (c.embedding (c.index j))
Full source
theorem mem_range_embedding (j : Fin n) : j ∈ Set.range (c.embedding (c.index j)) := by
  have : c.embedding (c.index j) (c.invEmbedding j) ∈ Set.range (c.embedding (c.index j)) :=
    Set.mem_range_self _
  rwa [c.embedding_comp_inv j] at this
Element Belongs to Range of Its Block's Embedding in a Composition
Informal description
For any composition $c$ of a natural number $n$ and any element $j \in \{0, \ldots, n-1\}$, the element $j$ belongs to the range of the embedding of its corresponding block in $c$. More precisely, if $i$ is the index of the block containing $j$ (i.e., $i = c.\mathrm{index}\, j$), then $j$ is in the image of the embedding $c.\mathrm{embedding}\, i$ of that block.
Composition.mem_range_embedding_iff' theorem
{j : Fin n} {i : Fin c.length} : j ∈ Set.range (c.embedding i) ↔ i = c.index j
Full source
theorem mem_range_embedding_iff' {j : Fin n} {i : Fin c.length} :
    j ∈ Set.range (c.embedding i)j ∈ Set.range (c.embedding i) ↔ i = c.index j := by
  constructor
  · rw [← not_imp_not]
    intro h
    exact Set.disjoint_right.1 (c.disjoint_range h) (c.mem_range_embedding j)
  · intro h
    rw [h]
    exact c.mem_range_embedding j
Characterization of Block Membership via Index: $j \in \mathrm{range}(c.\mathrm{embedding}\, i) \leftrightarrow i = c.\mathrm{index}\, j$
Informal description
For any composition $c$ of a natural number $n$, an element $j \in \{0, \ldots, n-1\}$, and a block index $i \in \{0, \ldots, c.\mathrm{length}-1\}$, the element $j$ belongs to the range of the embedding of the $i$-th block if and only if $i$ is the index of the block containing $j$. In other words, $j \in \mathrm{range}(c.\mathrm{embedding}\, i)$ if and only if $i = c.\mathrm{index}\, j$.
Composition.index_embedding theorem
(i : Fin c.length) (j : Fin (c.blocksFun i)) : c.index (c.embedding i j) = i
Full source
theorem index_embedding (i : Fin c.length) (j : Fin (c.blocksFun i)) :
    c.index (c.embedding i j) = i := by
  symm
  rw [← mem_range_embedding_iff']
  apply Set.mem_range_self
Index of Embedded Element in Composition Block is Correct
Informal description
For any composition $c$ of a natural number $n$, any block index $i \in \{0, \ldots, c.\mathrm{length}-1\}$, and any element $j$ within the $i$-th block (i.e., $j \in \{0, \ldots, c.\mathrm{blocksFun}\, i - 1\}$), the index of the embedded element $c.\mathrm{embedding}\, i\, j$ in $\{0, \ldots, n-1\}$ is equal to $i$. In other words, the composition's index function correctly identifies that the embedded element $c.\mathrm{embedding}\, i\, j$ belongs to the $i$-th block.
Composition.invEmbedding_comp theorem
(i : Fin c.length) (j : Fin (c.blocksFun i)) : (c.invEmbedding (c.embedding i j) : ℕ) = j
Full source
theorem invEmbedding_comp (i : Fin c.length) (j : Fin (c.blocksFun i)) :
    (c.invEmbedding (c.embedding i j) : ) = j := by
  simp_rw [coe_invEmbedding, index_embedding, coe_embedding, add_tsub_cancel_left]
Relative Position Preservation: $c.\mathrm{invEmbedding}(c.\mathrm{embedding}\, i\, j) = j$
Informal description
For any composition $c$ of a natural number $n$, any block index $i \in \{0, \ldots, c.\mathrm{length}-1\}$, and any element $j$ within the $i$-th block (i.e., $j \in \{0, \ldots, c.\mathrm{blocksFun}\, i - 1\}$), the relative position of the embedded element $c.\mathrm{embedding}\, i\, j$ within its block is equal to $j$. In other words, if we embed $j$ into the $i$-th block via $c.\mathrm{embedding}\, i\, j$ and then compute its position within the block using $c.\mathrm{invEmbedding}$, we recover $j$ itself.
Composition.blocksFinEquiv definition
: (Σ i : Fin c.length, Fin (c.blocksFun i)) ≃ Fin n
Full source
/-- Equivalence between the disjoint union of the blocks (each of them seen as
`Fin (c.blocksFun i)`) with `Fin n`. -/
def blocksFinEquiv : (Σi : Fin c.length, Fin (c.blocksFun i)) ≃ Fin n where
  toFun x := c.embedding x.1 x.2
  invFun j := ⟨c.index j, c.invEmbedding j⟩
  left_inv x := by
    rcases x with ⟨i, y⟩
    dsimp
    congr; · exact c.index_embedding _ _
    rw [Fin.heq_ext_iff]
    · exact c.invEmbedding_comp _ _
    · rw [c.index_embedding]
  right_inv j := c.embedding_comp_inv j
Bijection between Disjoint Union of Blocks and Fin n in a Composition
Informal description
For a composition \( c \) of a natural number \( n \), the equivalence \( \text{blocksFinEquiv} \) establishes a bijection between the disjoint union of the blocks (each viewed as \( \text{Fin}(c.\text{blocksFun}\, i) \) for \( i \in \text{Fin}\, c.\text{length} \)) and the finite set \( \text{Fin}\, n \). More precisely: - The forward map sends a pair \( (i, j) \), where \( i \) is a block index and \( j \) is an element within the \( i \)-th block, to the position \( c.\text{embedding}\, i\, j \) in \( \text{Fin}\, n \). - The inverse map takes an element \( j \in \text{Fin}\, n \) and returns the pair \( (c.\text{index}\, j, c.\text{invEmbedding}\, j) \), where \( c.\text{index}\, j \) is the index of the block containing \( j \), and \( c.\text{invEmbedding}\, j \) is the relative position of \( j \) within that block. This equivalence is bijective and preserves the structure of the composition, meaning that splitting and rejoining via these maps returns the original elements.
Composition.blocksFun_congr theorem
{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₂
Full source
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₂ := by
  cases hn
  rw [← Composition.ext_iff] at hc
  cases hc
  congr
  rwa [Fin.ext_iff]
Equality of Block Sizes in Compositions with Equal Blocks and Indices
Informal description
Let $c_1$ and $c_2$ be compositions of natural numbers $n_1$ and $n_2$ respectively, with $n_1 = n_2$. If their block lists are equal ($c_1.\text{blocks} = c_2.\text{blocks}$) and indices $i_1 \in \text{Fin}\, c_1.\text{length}$ and $i_2 \in \text{Fin}\, c_2.\text{length}$ satisfy $(i_1 : \mathbb{N}) = i_2$, then the corresponding block sizes are equal: $c_1.\text{blocksFun}\, i_1 = c_2.\text{blocksFun}\, i_2$.
Composition.sigma_eq_iff_blocks_eq theorem
{c : Σ n, Composition n} {c' : Σ n, Composition n} : c = c' ↔ c.2.blocks = c'.2.blocks
Full source
/-- 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 := by
  refine ⟨fun H => by rw [H], fun H => ?_⟩
  rcases c with ⟨n, c⟩
  rcases c' with ⟨n', c'⟩
  have : n = n' := by rw [← c.blocks_sum, ← c'.blocks_sum, H]
  induction this
  congr
  ext1
  exact H
Equality of Compositions via Block Equality
Informal description
Two compositions $c$ and $c'$ (possibly of different natural numbers) are equal if and only if their sequences of blocks are equal, i.e., $c.2.\text{blocks} = c'.2.\text{blocks}$.
Composition.instInhabited instance
{n : ℕ} : Inhabited (Composition n)
Full source
instance {n : } : Inhabited (Composition n) :=
  ⟨Composition.ones n⟩
Inhabitedness of Compositions of Natural Numbers
Informal description
For any natural number $n$, the type of compositions of $n$ is inhabited.
Composition.ones_length theorem
(n : ℕ) : (ones n).length = n
Full source
@[simp]
theorem ones_length (n : ) : (ones n).length = n :=
  List.length_replicate
Length of the All-Ones Composition: $\text{length}(\text{ones}(n)) = n$
Informal description
For any natural number $n$, the length of the composition `ones n` (which consists of $n$ blocks each of size 1) is equal to $n$.
Composition.ones_blocks theorem
(n : ℕ) : (ones n).blocks = replicate n (1 : ℕ)
Full source
@[simp]
theorem ones_blocks (n : ) : (ones n).blocks = replicate n (1 : ) :=
  rfl
Blocks of the All-Ones Composition: `(ones n).blocks = replicate n 1`
Informal description
For any natural number $n$, the list of blocks in the composition `ones n` (which consists of $n$ blocks each of size 1) is equal to the list `replicate n 1`, i.e., a list of length $n$ where every element is $1$.
Composition.ones_blocksFun theorem
(n : ℕ) (i : Fin (ones n).length) : (ones n).blocksFun i = 1
Full source
@[simp]
theorem ones_blocksFun (n : ) (i : Fin (ones n).length) : (ones n).blocksFun i = 1 := by
  simp only [blocksFun, ones, get_eq_getElem, getElem_replicate]
Block Sizes in All-Ones Composition: $(ones\, n).blocksFun\, i = 1$
Informal description
For any natural number $n$ and any index $i$ in the finite set $\{0, \ldots, n-1\}$, the size of the $i$-th block in the all-ones composition of $n$ is equal to $1$.
Composition.ones_sizeUpTo theorem
(n : ℕ) (i : ℕ) : (ones n).sizeUpTo i = min i n
Full source
@[simp]
theorem ones_sizeUpTo (n : ) (i : ) : (ones n).sizeUpTo i = min i n := by
  simp [sizeUpTo, ones_blocks, take_replicate]
Sum of First $i$ Blocks in All-Ones Composition Equals $\min(i, n)$
Informal description
For any natural number $n$ and index $i$, the sum of the sizes of the first $i$ blocks in the all-ones composition of $n$ (where each block has size $1$) is equal to the minimum of $i$ and $n$. In other words, if $c$ is the composition `ones n`, then $c.\text{sizeUpTo}(i) = \min(i, n)$.
Composition.ones_embedding theorem
(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⟩
Full source
@[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⟩ := by
  ext
  simpa using i.2.le
Embedding of First Element in All-Ones Composition Maps to Block Index
Informal description
For any natural number $n$ and any index $i \in \mathrm{Fin}\, n$ (i.e., $0 \leq i < n$), the order-preserving embedding of the $i$-th block in the all-ones composition of $n$ maps the first element of the block (index $0$) to the element $i$ in $\mathrm{Fin}\, n$. More precisely, if $c = \mathrm{ones}\, n$ is the all-ones composition (where each block has size $1$), then for any $i \in \mathrm{Fin}\, c.\mathrm{length}$ (which equals $n$), the embedding $c.\mathrm{embedding}\, i$ satisfies: \[ c.\mathrm{embedding}\, i\, \langle 0, h \rangle = \langle i, \text{proof} \rangle \] where $h$ is a proof that $0 < c.\mathrm{blocksFun}\, i = 1$, and the right-hand side is the element $i$ in $\mathrm{Fin}\, n$ with a proof that $i < n$.
Composition.ne_ones_iff theorem
{c : Composition n} : c ≠ ones n ↔ ∃ i ∈ c.blocks, 1 < i
Full source
theorem ne_ones_iff {c : Composition n} : c ≠ ones nc ≠ ones n ↔ ∃ i ∈ c.blocks, 1 < i := by
  refine (not_congr eq_ones_iff).trans ?_
  have : ∀ j ∈ c.blocks, j = 1 ↔ j ≤ 1 := fun j hj => by simp [le_antisymm_iff, c.one_le_blocks hj]
  simp +contextual [this]
Characterization of Non-Trivial Compositions: $c \neq \text{ones}(n) \leftrightarrow \exists i \in c.\text{blocks}, 1 < i$
Informal description
For any composition $c$ of a natural number $n$, the composition $c$ is not equal to the composition consisting of all ones (i.e., $c \neq \text{ones}(n)$) if and only if there exists a block size $i$ in the list of blocks of $c$ such that $1 < i$.
Composition.single definition
(n : ℕ) (h : 0 < n) : Composition n
Full source
/-- The composition made of a single block of size `n`. -/
def single (n : ) (h : 0 < n) : Composition n :=
  ⟨[n], by simp [h], by simp⟩
Single-block composition of $n$
Informal description
The composition of a natural number $n > 0$ consisting of a single block of size $n$. This is represented by the list $[n]$, which trivially sums to $n$ and satisfies the conditions of being a composition.
Composition.single_length theorem
{n : ℕ} (h : 0 < n) : (single n h).length = 1
Full source
@[simp]
theorem single_length {n : } (h : 0 < n) : (single n h).length = 1 :=
  rfl
Length of Single-Block Composition is One
Informal description
For any natural number $n > 0$, the length of the single-block composition of $n$ is equal to $1$.
Composition.single_blocks theorem
{n : ℕ} (h : 0 < n) : (single n h).blocks = [n]
Full source
@[simp]
theorem single_blocks {n : } (h : 0 < n) : (single n h).blocks = [n] :=
  rfl
Single-block composition has singleton blocks list
Informal description
For any natural number $n > 0$, the blocks of the single-block composition of $n$ is the singleton list $[n]$.
Composition.single_blocksFun theorem
{n : ℕ} (h : 0 < n) (i : Fin (single n h).length) : (single n h).blocksFun i = n
Full source
@[simp]
theorem single_blocksFun {n : } (h : 0 < n) (i : Fin (single n h).length) :
    (single n h).blocksFun i = n := by simp [blocksFun, single, blocks, i.2]
Single-block composition has constant block size $n$
Informal description
For any natural number $n > 0$ and any index $i$ in the finite set $\mathrm{Fin}\, 1$ (i.e., $i = 0$), the function $\mathrm{blocksFun}$ of the single-block composition of $n$ satisfies $\mathrm{blocksFun}\, i = n$. In other words, the only block in this composition has size $n$.
Composition.single_embedding theorem
{n : ℕ} (h : 0 < n) (i : Fin n) : ((single n h).embedding (0 : Fin 1)) i = i
Full source
@[simp]
theorem single_embedding {n : } (h : 0 < n) (i : Fin n) :
    ((single n h).embedding (0 : Fin 1)) i = i := by
  ext
  simp
Embedding of Single-Block Composition is Identity on $\mathrm{Fin}\, n$
Informal description
For any natural number $n > 0$ and any index $i \in \mathrm{Fin}\, n$, the embedding function of the single-block composition of $n$ maps $i$ to itself. That is, if $c$ is the single-block composition of $n$, then $c.\mathrm{embedding}(0)(i) = i$ for all $i \in \mathrm{Fin}\, n$.
Composition.ne_single_iff theorem
{n : ℕ} (hn : 0 < n) {c : Composition n} : c ≠ single n hn ↔ ∀ i, c.blocksFun i < n
Full source
theorem ne_single_iff {n : } (hn : 0 < n) {c : Composition n} :
    c ≠ single n hnc ≠ single n hn ↔ ∀ i, c.blocksFun i < n := by
  rw [← not_iff_not]
  push_neg
  constructor
  · rintro rfl
    exact ⟨⟨0, by simp⟩, by simp⟩
  · rintro ⟨i, hi⟩
    rw [eq_single_iff_length]
    have : ∀ j : Fin c.length, j = i := by
      intro j
      by_contra ji
      apply lt_irrefl (∑ k, c.blocksFun k)
      calc
        ∑ k, c.blocksFun k ≤ c.blocksFun i := by simp only [c.sum_blocksFun, hi]
        _ < ∑ k, c.blocksFun k :=
          Finset.single_lt_sum ji (Finset.mem_univ _) (Finset.mem_univ _) (c.one_le_blocksFun j)
            fun _ _ _ => zero_le _

    simpa using Fintype.card_eq_one_of_forall_eq this
Characterization of Non-Single Compositions: $c \neq \text{single}(n) \leftrightarrow \forall i, c.\mathrm{blocksFun}\, i < n$
Informal description
For a natural number $n > 0$ and a composition $c$ of $n$, the composition $c$ is not equal to the single-block composition of $n$ if and only if every block size $c.\mathrm{blocksFun}\, i$ is strictly less than $n$ for all indices $i \in \mathrm{Fin}\, c.\mathrm{length}$.
Composition.cast definition
(c : Composition m) (hmn : m = n) : Composition n
Full source
/-- Change `n` in `(c : Composition n)` to a propositionally equal value. -/
@[simps]
protected def cast (c : Composition m) (hmn : m = n) : Composition n where
  __ := c
  blocks_sum := c.blocks_sum.trans hmn
Cast of a composition to an equal natural number
Informal description
Given a composition $c$ of a natural number $m$ and a proof that $m = n$, the function returns a composition of $n$ by casting $c$ to a composition of $n$ while preserving the underlying list of blocks. The sum of the blocks is adjusted according to the equality $m = n$.
Composition.cast_rfl theorem
(c : Composition n) : c.cast rfl = c
Full source
@[simp]
theorem cast_rfl (c : Composition n) : c.cast rfl = c := rfl
Composition Cast with Reflexivity Preserves Identity
Informal description
For any composition $c$ of a natural number $n$, casting $c$ to a composition of $n$ using the reflexivity proof $n = n$ yields $c$ itself.
Composition.cast_heq theorem
(c : Composition m) (hmn : m = n) : HEq (c.cast hmn) c
Full source
theorem cast_heq (c : Composition m) (hmn : m = n) : HEq (c.cast hmn) c := by subst m; rfl
Hereditary Equality of Composition Cast
Informal description
Given a composition $c$ of a natural number $m$ and a proof that $m = n$, the cast of $c$ to a composition of $n$ is hereditarily equal to $c$.
Composition.cast_eq_cast theorem
(c : Composition m) (hmn : m = n) : c.cast hmn = cast (hmn ▸ rfl) c
Full source
theorem cast_eq_cast (c : Composition m) (hmn : m = n) :
    c.cast hmn = cast (hmn ▸ rfl) c := by
  subst m
  rfl
Equality of Composition Casts via Natural Number Equality
Informal description
Given a composition $c$ of a natural number $m$ and a proof that $m = n$, the cast of $c$ to a composition of $n$ is equal to the cast of $c$ via the equality $m = n$ and reflexivity.
Composition.append definition
(c₁ : Composition m) (c₂ : Composition n) : Composition (m + n)
Full source
/-- Append two compositions to get a composition of the sum of numbers. -/
@[simps]
def append (c₁ : Composition m) (c₂ : Composition n) : Composition (m + n) where
  blocks := c₁.blocks ++ c₂.blocks
  blocks_pos := by
    intro i hi
    rw [mem_append] at hi
    exact hi.elim c₁.blocks_pos c₂.blocks_pos
  blocks_sum := by simp
Concatenation of compositions
Informal description
Given two compositions \( c_1 \) of \( m \) and \( c_2 \) of \( n \), the composition \( c_1 \cdot c_2 \) is the composition of \( m + n \) obtained by concatenating the blocks of \( c_1 \) and \( c_2 \). Specifically, if \( c_1 \) is represented by the list of positive integers \( (i_0, \ldots, i_{k-1}) \) summing to \( m \) and \( c_2 \) is represented by \( (j_0, \ldots, j_{l-1}) \) summing to \( n \), then \( c_1 \cdot c_2 \) is represented by \( (i_0, \ldots, i_{k-1}, j_0, \ldots, j_{l-1}) \), which sums to \( m + n \).
Composition.reverse definition
(c : Composition n) : Composition n
Full source
/-- Reverse the order of blocks in a composition. -/
@[simps]
def reverse (c : Composition n) : Composition n where
  blocks := c.blocks.reverse
  blocks_pos hi := c.blocks_pos (mem_reverse.mp hi)
  blocks_sum := by simp [List.sum_reverse]
Reversed composition of a natural number
Informal description
Given a composition $c$ of a natural number $n$, the reverse composition $c^\text{reverse}$ is obtained by reversing the order of the blocks in $c$. Specifically, if $c$ is represented by the list of positive integers $(i_0, \ldots, i_{k-1})$ summing to $n$, then $c^\text{reverse}$ is represented by the list $(i_{k-1}, \ldots, i_0)$. The blocks of $c^\text{reverse}$ are the same as those of $c$ but in reverse order, and they still sum to $n$.
Composition.reverse_reverse theorem
(c : Composition n) : c.reverse.reverse = c
Full source
@[simp]
lemma reverse_reverse (c : Composition n) : c.reverse.reverse = c :=
  Composition.ext <| List.reverse_reverse _
Double Reversal of Composition Yields Original Composition
Informal description
For any composition $c$ of a natural number $n$, reversing the composition twice returns the original composition, i.e., $(c^\text{reverse})^\text{reverse} = c$.
Composition.reverse_involutive theorem
: Function.Involutive (@reverse n)
Full source
lemma reverse_involutive : Function.Involutive (@reverse n) := reverse_reverse
Involutivity of Composition Reversal
Informal description
The reverse operation on compositions of a natural number $n$ is involutive, meaning that for any composition $c$ of $n$, reversing $c$ twice yields the original composition, i.e., $c^{\text{reverse}\ \text{reverse}} = c$.
Composition.reverse_bijective theorem
: Function.Bijective (@reverse n)
Full source
lemma reverse_bijective : Function.Bijective (@reverse n) := reverse_involutive.bijective
Bijectivity of Composition Reversal
Informal description
The reverse operation on compositions of a natural number $n$ is bijective. That is, the function $\text{reverse} : \text{Composition}(n) \to \text{Composition}(n)$ is both injective and surjective.
Composition.reverse_injective theorem
: Function.Injective (@reverse n)
Full source
lemma reverse_injective : Function.Injective (@reverse n) := reverse_involutive.injective
Injectivity of Composition Reversal
Informal description
The reverse operation on compositions of a natural number $n$ is injective, meaning that for any two compositions $c_1$ and $c_2$ of $n$, if their reverses are equal, then the original compositions are equal, i.e., $c_1^\text{reverse} = c_2^\text{reverse}$ implies $c_1 = c_2$.
Composition.reverse_surjective theorem
: Function.Surjective (@reverse n)
Full source
lemma reverse_surjective : Function.Surjective (@reverse n) := reverse_involutive.surjective
Surjectivity of Composition Reversal
Informal description
The reverse operation on compositions of a natural number $n$ is surjective, meaning that for any composition $c$ of $n$, there exists a composition $c'$ of $n$ such that $c'^\text{reverse} = c$.
Composition.reverse_inj theorem
{c₁ c₂ : Composition n} : c₁.reverse = c₂.reverse ↔ c₁ = c₂
Full source
@[simp]
lemma reverse_inj {c₁ c₂ : Composition n} : c₁.reverse = c₂.reverse ↔ c₁ = c₂ :=
  reverse_injective.eq_iff
Reverse Composition Equality Criterion: $c_1^\text{reverse} = c_2^\text{reverse} \leftrightarrow c_1 = c_2$
Informal description
For any two compositions $c_1$ and $c_2$ of a natural number $n$, the reverse of $c_1$ equals the reverse of $c_2$ if and only if $c_1$ equals $c_2$.
Composition.reverse_ones theorem
: (ones n).reverse = ones n
Full source
@[simp]
lemma reverse_ones : (ones n).reverse = ones n := by ext1; simp
Reversing the All-Ones Composition Yields Itself
Informal description
For any natural number $n$, the reverse of the composition consisting of $n$ blocks of size $1$ (denoted as $\text{ones}_n$) is equal to itself, i.e., $(\text{ones}_n)^\text{reverse} = \text{ones}_n$.
Composition.reverse_single theorem
(hn : 0 < n) : (single n hn).reverse = single n hn
Full source
@[simp]
lemma reverse_single (hn : 0 < n) : (single n hn).reverse = single n hn := by ext1; simp
Reversing a Single-Block Composition Yields Itself
Informal description
For any positive integer $n > 0$, the reverse of the single-block composition of $n$ is equal to itself, i.e., $(\text{single}_n)^\text{reverse} = \text{single}_n$.
Composition.reverse_eq_ones theorem
{c : Composition n} : c.reverse = ones n ↔ c = ones n
Full source
@[simp]
lemma reverse_eq_ones {c : Composition n} : c.reverse = ones n ↔ c = ones n :=
  reverse_injective.eq_iff' reverse_ones
Characterization of Compositions Equal to Their Reverse via All-Ones Composition
Informal description
For any composition $c$ of a natural number $n$, the reverse of $c$ is equal to the all-ones composition $\text{ones}_n$ if and only if $c$ itself is equal to $\text{ones}_n$.
Composition.reverse_eq_single theorem
{hn : 0 < n} {c : Composition n} : c.reverse = single n hn ↔ c = single n hn
Full source
@[simp]
lemma reverse_eq_single {hn : 0 < n} {c : Composition n} :
    c.reverse = single n hn ↔ c = single n hn :=
  reverse_injective.eq_iff' <| reverse_single _
Reversed Composition Equals Single-Block Composition if and only if Original is Single-Block
Informal description
For a composition $c$ of a positive integer $n$, the reverse of $c$ is equal to the single-block composition of $n$ if and only if $c$ itself is the single-block composition of $n$. In other words, $c^\text{reverse} = [n]$ if and only if $c = [n]$.
Composition.reverse_append theorem
(c₁ : Composition m) (c₂ : Composition n) : reverse (append c₁ c₂) = (append c₂.reverse c₁.reverse).cast (add_comm _ _)
Full source
lemma reverse_append (c₁ : Composition m) (c₂ : Composition n) :
    reverse (append c₁ c₂) = (append c₂.reverse c₁.reverse).cast (add_comm _ _) :=
  Composition.ext <| by simp
Reversed Concatenation of Compositions via Addition Commutativity
Informal description
For any composition $c_1$ of a natural number $m$ and any composition $c_2$ of a natural number $n$, the reverse of the concatenation $c_1 \cdot c_2$ is equal to the concatenation of the reverses $c_2^\text{reverse} \cdot c_1^\text{reverse}$, cast via the commutative property of addition (i.e., $m + n = n + m$).
Composition.recOnSingleAppend definition
{motive : ∀ n, Composition n → Sort*} {n : ℕ} (c : Composition n) (zero : motive 0 (ones 0)) (single_append : ∀ k n c, motive n c → motive (k + 1 + n) (append (single (k + 1) k.succ_pos) c)) : motive n c
Full source
/-- Induction (recursion) principle on `c : Composition _`
that corresponds to the usual induction on the list of blocks of `c`. -/
@[elab_as_elim]
def recOnSingleAppend {motive : ∀ n, Composition n → Sort*} {n : } (c : Composition n)
    (zero : motive 0 (ones 0))
    (single_append : ∀ k n c, motive n c →
      motive (k + 1 + n) (append (single (k + 1) k.succ_pos) c)) :
    motive n c :=
  match n, c with
  | _, ⟨blocks, blocks_pos, rfl⟩ =>
    match blocks with
    | [] => zero
    | 0 :: _ => by simp at blocks_pos
    | (k + 1) :: l =>
      single_append k l.sum ⟨l, fun hi ↦ blocks_pos <| mem_cons_of_mem _ hi, rfl⟩ <|
        recOnSingleAppend _ zero single_append
  decreasing_by simp
Induction principle for compositions via single-block prepending
Informal description
Given a composition $c$ of a natural number $n$, a motive $P$ depending on compositions, and proofs that: 1. $P$ holds for the empty composition (the composition of 0 consisting of zero blocks) 2. For any $k \geq 0$, any natural number $n$, and any composition $c$ of $n$, if $P$ holds for $c$ then it holds for the composition obtained by prepending a single block of size $k+1$ to $c$ (resulting in a composition of $k+1+n$) Then $P$ holds for the given composition $c$. This is an induction principle that allows proving properties of compositions by: - Base case: Verifying for the empty composition - Inductive step: Showing that prepending any single block preserves the property
Composition.recOnAppendSingle definition
{motive : ∀ n, Composition n → Sort*} {n : ℕ} (c : Composition n) (zero : motive 0 (ones 0)) (append_single : ∀ k n c, motive n c → motive (n + (k + 1)) (append c (single (k + 1) k.succ_pos))) : motive n c
Full source
/-- Induction (recursion) principle on `c : Composition _`
that corresponds to the reverse induction on the list of blocks of `c`. -/
@[elab_as_elim]
def recOnAppendSingle {motive : ∀ n, Composition n → Sort*} {n : } (c : Composition n)
    (zero : motive 0 (ones 0))
    (append_single : ∀ k n c, motive n c →
      motive (n + (k + 1)) (append c (single (k + 1) k.succ_pos))) :
    motive n c :=
  reverse_reverse c ▸ c.reverse.recOnSingleAppend zero fun k n c ih ↦ by
    convert append_single k n c.reverse ih using 1
    · apply add_comm
    · rw [reverse_append, reverse_single]
      apply cast_heq
Induction principle for compositions via single-block appending
Informal description
Given a composition $c$ of a natural number $n$, a motive $P$ depending on compositions, and proofs that: 1. $P$ holds for the empty composition (the composition of 0 consisting of zero blocks) 2. For any $k \geq 0$, any natural number $n$, and any composition $c$ of $n$, if $P$ holds for $c$ then it holds for the composition obtained by appending a single block of size $k+1$ to $c$ (resulting in a composition of $n + (k+1)$) Then $P$ holds for the given composition $c$. This is an induction principle that allows proving properties of compositions by: - Base case: Verifying for the empty composition - Inductive step: Showing that appending any single block preserves the property
List.splitWrtCompositionAux definition
: List α → List ℕ → List (List α)
Full source
/-- Auxiliary for `List.splitWrtComposition`. -/
def splitWrtCompositionAux : List α → List List (List α)
  | _, [] => []
  | l, n::ns =>
    let (l₁, l₂) := l.splitAt n
    l₁::splitWrtCompositionAux l₂ ns
Auxiliary list splitting function for compositions
Informal description
Given a list `l` of elements of type `α` and a list `ns` of natural numbers, the auxiliary function splits `l` into sublists where the first sublist has length `n` (the first element of `ns`), the second sublist has length equal to the next element of `ns`, and so on. If `ns` is empty, it returns an empty list. More precisely: - For empty `ns`, returns empty list - For `n::ns`, splits `l` into: - First part: first `n` elements of `l` - Remaining parts: recursively split remaining elements according to `ns`
List.splitWrtComposition definition
(l : List α) (c : Composition n) : List (List α)
Full source
/-- 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 α) :=
  splitWrtCompositionAux l c.blocks
List splitting according to a composition
Informal description
Given a list $l$ of elements of type $\alpha$ and a composition $c$ of a natural number $n$ (where $c$ is represented by a list of positive integers $[i_1, \ldots, i_k]$ summing to $n$), the function splits $l$ into $k$ sublists of lengths $i_1, \ldots, i_k$ respectively. More precisely: - The first sublist consists of the first $i_1$ elements of $l$ - The second sublist consists of the next $i_2$ elements of $l$ - ... - The $k$-th sublist consists of the last $i_k$ elements of $l$ This operation is particularly meaningful when $l$ has length $n$, but the definition works for any list length.
List.splitWrtCompositionAux_cons theorem
(l : List α) (n ns) : l.splitWrtCompositionAux (n :: ns) = take n l :: (drop n l).splitWrtCompositionAux ns
Full source
@[local simp]
theorem splitWrtCompositionAux_cons (l : List α) (n ns) :
    l.splitWrtCompositionAux (n::ns) = taketake n l::(drop n l).splitWrtCompositionAux ns := by
  simp [splitWrtCompositionAux]
Recursive Decomposition of List Splitting with Composition Auxiliary Function
Informal description
For any list $l$ of elements of type $\alpha$ and any natural numbers $n$ and $ns$, the auxiliary splitting function satisfies: \[ \text{splitWrtCompositionAux}_l(n :: ns) = \text{take}_n(l) :: \text{splitWrtCompositionAux}_{\text{drop}_n(l)}(ns) \] where $\text{take}_n(l)$ returns the first $n$ elements of $l$, and $\text{drop}_n(l)$ returns the remaining elements after removing the first $n$ elements.
List.length_splitWrtCompositionAux theorem
(l : List α) (ns) : length (l.splitWrtCompositionAux ns) = ns.length
Full source
theorem length_splitWrtCompositionAux (l : List α) (ns) :
    length (l.splitWrtCompositionAux ns) = ns.length := by
    induction ns generalizing l
    · simp [splitWrtCompositionAux, *]
    · simp [*]
Length Preservation in List Splitting via Composition Auxiliary Function
Informal description
For any list $l$ of elements of type $\alpha$ and any list $ns$ of natural numbers, the length of the list obtained by splitting $l$ according to $ns$ via `splitWrtCompositionAux` is equal to the length of $ns$. In other words, if we split a list into sublists where the lengths are determined by $ns$, then the number of resulting sublists will be exactly the length of $ns$.
List.length_splitWrtComposition theorem
(l : List α) (c : Composition n) : length (l.splitWrtComposition c) = c.length
Full source
/-- 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 :=
  length_splitWrtCompositionAux _ _
Number of Sublists Equals Composition Length
Informal description
Given a list $l$ of elements of type $\alpha$ and a composition $c$ of a natural number $n$, the number of sublists obtained by splitting $l$ according to $c$ is equal to the number of blocks in $c$, i.e., $\text{length}(l.\text{splitWrtComposition}\ c) = c.\text{length}$.
List.map_length_splitWrtCompositionAux theorem
{ns : List ℕ} : ∀ {l : List α}, ns.sum ≤ l.length → map length (l.splitWrtCompositionAux ns) = ns
Full source
theorem map_length_splitWrtCompositionAux {ns : List } :
    ∀ {l : List α}, ns.sum ≤ l.lengthmap length (l.splitWrtCompositionAux ns) = ns := by
  induction ns with
  | nil => simp [splitWrtCompositionAux]
  | cons n ns IH =>
    intro l h; simp only [sum_cons] at h
    have := le_trans (Nat.le_add_right _ _) h
    simp only [splitWrtCompositionAux_cons, this]; dsimp
    rw [length_take, IH] <;> simp [length_drop]
    · assumption
    · exact le_tsub_of_add_le_left h
Sublist Lengths Match Composition in Auxiliary Splitting Function
Informal description
For any list $ns$ of natural numbers and any list $l$ of elements of type $\alpha$ such that the sum of $ns$ is less than or equal to the length of $l$, the list of lengths of sublists obtained by splitting $l$ according to $ns$ via `splitWrtCompositionAux` is equal to $ns$. In other words, if $\sum ns \leq \text{length}(l)$, then $\text{map length}(l.\text{splitWrtCompositionAux}\ ns) = ns$.
List.map_length_splitWrtComposition theorem
(l : List α) (c : Composition l.length) : map length (l.splitWrtComposition c) = c.blocks
Full source
/-- 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 :=
  map_length_splitWrtCompositionAux (le_of_eq c.blocks_sum)
Sublist Lengths Match Composition Blocks
Informal description
Given a list $l$ of length $n$ and a composition $c$ of $n$, the lengths of the sublists obtained by splitting $l$ according to $c$ are exactly the block sizes in $c$. That is, if $l$ is split into sublists $[l_1, \ldots, l_k]$ via $c$, then $\text{length}(l_i) = c.\text{blocks}_i$ for each $i$.
List.length_pos_of_mem_splitWrtComposition theorem
{l l' : List α} {c : Composition l.length} (h : l' ∈ l.splitWrtComposition c) : 0 < length l'
Full source
theorem length_pos_of_mem_splitWrtComposition {l l' : List α} {c : Composition l.length}
    (h : l' ∈ l.splitWrtComposition c) : 0 < length l' := by
  have : l'.length ∈ (l.splitWrtComposition c).map List.length :=
    List.mem_map_of_mem h
  rw [map_length_splitWrtComposition] at this
  exact c.blocks_pos this
Positivity of Sublist Lengths in Composition-Based Splitting
Informal description
For any list $l$ of type $\alpha$ and any sublist $l'$ obtained by splitting $l$ according to a composition $c$ of its length, the length of $l'$ is positive. That is, if $l' \in l.\text{splitWrtComposition}\ c$, then $\text{length}(l') > 0$.
List.sum_take_map_length_splitWrtComposition theorem
(l : List α) (c : Composition l.length) (i : ℕ) : (((l.splitWrtComposition c).map length).take i).sum = c.sizeUpTo i
Full source
theorem sum_take_map_length_splitWrtComposition (l : List α) (c : Composition l.length) (i : ) :
    (((l.splitWrtComposition c).map length).take i).sum = c.sizeUpTo i := by
  congr
  exact map_length_splitWrtComposition l c
Sum of Sublist Lengths Equals Composition's Cumulative Block Sizes
Informal description
Given a list $l$ of length $n$ and a composition $c$ of $n$, the sum of the lengths of the first $i$ sublists obtained by splitting $l$ according to $c$ is equal to the cumulative sum of the first $i$ block sizes in $c$. More precisely, if $l$ is split into sublists $[l_1, \ldots, l_k]$ via $c$, then: \[ \sum_{j=0}^{i-1} \text{length}(l_j) = c.\text{sizeUpTo}(i) \]
List.getElem_splitWrtCompositionAux theorem
(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
Full source
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 := by
  induction ns generalizing l i with
  | nil => cases hi
  | cons n ns IH =>
    rcases i with - | i
    · rw [Nat.add_zero, List.take_zero, sum_nil]
      simp
    · simp only [splitWrtCompositionAux, getElem_cons_succ, IH, take,
          sum_cons, Nat.add_eq, add_zero, splitAt_eq, drop_take, drop_drop]
      rw [Nat.add_sub_add_left]
Characterization of Split Sublists via Cumulative Sums
Informal description
Given a list $l$ of elements of type $\alpha$, a list $ns$ of natural numbers, and an index $i$ such that $i$ is less than the length of the split list, the $i$-th element of the list obtained by splitting $l$ according to $ns$ is equal to the sublist of $l$ obtained by taking the first $\sum_{j=0}^{i} ns_j$ elements and then dropping the first $\sum_{j=0}^{i-1} ns_j$ elements. More formally: \[ (l.\text{splitWrtCompositionAux}\ ns)[i] = \text{drop}_{\sum_{j=0}^{i-1} ns_j} (\text{take}_{\sum_{j=0}^{i} ns_j} l) \] where $ns_j$ denotes the $j$-th element of $ns$ (with $0$-based indexing).
List.getElem_splitWrtComposition' theorem
(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)
Full source
/-- 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) :=
  getElem_splitWrtCompositionAux _ _ hi
Characterization of Sublists in Composition-Based Splitting
Informal description
Let $l$ be a list of elements of type $\alpha$ and $c$ be a composition of a natural number $n$. For any index $i$ such that $i$ is less than the number of sublists obtained by splitting $l$ according to $c$, the $i$-th sublist in the split is equal to the portion of $l$ between the indices $c.\text{sizeUpTo}(i)$ and $c.\text{sizeUpTo}(i+1)$. More precisely: \[ (l.\text{splitWrtComposition}\ c)[i] = \text{drop}_{c.\text{sizeUpTo}(i)} (\text{take}_{c.\text{sizeUpTo}(i+1)} l) \]
List.getElem_splitWrtComposition theorem
(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)
Full source
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) :=
  getElem_splitWrtComposition' _ _ h
Characterization of List Splitting via Composition Blocks
Informal description
Let $l$ be a list of elements of type $\alpha$ and $c$ be a composition of a natural number $n$. For any index $i$ such that $i$ is less than the number of sublists obtained by splitting $l$ according to $c$, the $i$-th sublist in the split is equal to the portion of $l$ between the cumulative sums of the first $i$ and first $(i+1)$ blocks of $c$. More precisely: \[ (l.\text{splitWrtComposition}\ c)_i = \text{drop}_{s_i} (\text{take}_{s_{i+1}} l) \] where $s_j = \sum_{k=0}^{j-1} c_k$ is the cumulative sum of the first $j$ blocks of $c$.
List.flatten_splitWrtCompositionAux theorem
{ns : List ℕ} : ∀ {l : List α}, ns.sum = l.length → (l.splitWrtCompositionAux ns).flatten = l
Full source
theorem flatten_splitWrtCompositionAux {ns : List } :
    ∀ {l : List α}, ns.sum = l.length → (l.splitWrtCompositionAux ns).flatten = l := by
  induction ns with
  | nil => exact fun h ↦ (length_eq_zero_iff.1 h.symm).symm
  | cons n ns IH =>
    intro l h; rw [sum_cons] at h
    simp only [splitWrtCompositionAux_cons]; dsimp
    rw [IH]
    · simp
    · rw [length_drop, ← h, add_tsub_cancel_left]
Flattening Preserves Original List under Composition Splitting
Informal description
For any list $l$ of elements of type $\alpha$ and any list of natural numbers $ns$ such that the sum of $ns$ equals the length of $l$, the flattened result of splitting $l$ according to $ns$ equals $l$ itself. In other words, if we split $l$ into sublists whose lengths are given by $ns$ and then concatenate these sublists, we recover the original list $l$.
List.flatten_splitWrtComposition theorem
(l : List α) (c : Composition l.length) : (l.splitWrtComposition c).flatten = l
Full source
/-- If one splits a list along a composition, and then flattens the sublists, one gets back the
original list. -/
@[simp]
theorem flatten_splitWrtComposition (l : List α) (c : Composition l.length) :
    (l.splitWrtComposition c).flatten = l :=
  flatten_splitWrtCompositionAux c.blocks_sum
List Splitting and Joining Preserves Original List under Composition
Informal description
Given a list $l$ of elements of type $\alpha$ and a composition $c$ of $n = \text{length}(l)$, the concatenation of the sublists obtained by splitting $l$ according to $c$ equals $l$ itself. In other words, if we split $l$ into parts whose lengths correspond to the blocks of $c$ and then join these parts back together, we recover the original list $l$.
List.splitWrtComposition_flatten theorem
(L : List (List α)) (c : Composition L.flatten.length) (h : map length L = c.blocks) : splitWrtComposition (flatten L) c = L
Full source
/-- If one joins a list of lists and then splits the flattening along the right composition,
one gets back the original list of lists. -/
@[simp]
theorem splitWrtComposition_flatten (L : List (List α)) (c : Composition L.flatten.length)
    (h : map length L = c.blocks) : splitWrtComposition (flatten L) c = L := by
  simp only [eq_self_iff_true, and_self_iff, eq_iff_flatten_eq, flatten_splitWrtComposition,
    map_length_splitWrtComposition, h]
Splitting the Join of Sublists Recovers Original Sublists under Matching Composition
Informal description
Given a list of lists $L = [L_1, \ldots, L_k]$ with elements of type $\alpha$ and a composition $c$ of $n = \text{length}(L_1 \mathbin{+\!\!+} \cdots \mathbin{+\!\!+} L_k)$ such that the lengths of the sublists $L_i$ match the blocks of $c$ (i.e., $\text{length}(L_i) = c.\text{blocks}_i$ for each $i$), then splitting the concatenated list $L_1 \mathbin{+\!\!+} \cdots \mathbin{+\!\!+} L_k$ according to $c$ recovers the original list of lists $L$.
compositionAsSetEquiv definition
(n : ℕ) : CompositionAsSet n ≃ Finset (Fin (n - 1))
Full source
/-- 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 : ) : CompositionAsSetCompositionAsSet n ≃ Finset (Fin (n - 1)) where
  toFun c :=
    { i : Fin (n - 1) |
        (⟨1 + (i : ℕ), by
              apply (add_lt_add_left i.is_lt 1).trans_le
              rw [Nat.succ_eq_add_one, add_comm]
              exact add_le_add (Nat.sub_le n 1) (le_refl 1)⟩ :
            Fin n.succ) ∈
          c.boundaries }.toFinset
  invFun s :=
    { boundaries :=
        { i : Fin n.succ |
            i = 0 ∨ i = Fin.last n ∨ ∃ (j : Fin (n - 1)) (_hj : j ∈ s), (i : ℕ) = j + 1 }.toFinset
      zero_mem := by simp
      getLast_mem := by simp }
  left_inv := by
    intro c
    ext i
    simp only [add_comm, Set.toFinset_setOf, Finset.mem_univ,
     forall_true_left, Finset.mem_filter, true_and, exists_prop]
    constructor
    · rintro (rfl | rfl | ⟨j, hj1, hj2⟩)
      · exact c.zero_mem
      · exact c.getLast_mem
      · convert hj1
    · simp only [or_iff_not_imp_left, ← ne_eq, ← Fin.exists_succ_eq]
      rintro i_mem ⟨j, rfl⟩ i_ne_last
      rcases Nat.exists_add_one_eq.mpr j.pos with ⟨n, rfl⟩
      obtain ⟨k, rfl⟩ : ∃ k : Fin n, k.castSucc = j := by
        simpa [Fin.exists_castSucc_eq] using i_ne_last
      use k
      simpa using i_mem
  right_inv := by
    intro s
    ext i
    have : (i : ℕ) + 1 ≠ n := by
      apply ne_of_lt
      convert add_lt_add_right i.is_lt 1
      apply (Nat.succ_pred_eq_of_pos _).symm
      exact Nat.lt_of_lt_pred (Fin.pos i)
    simp only [add_comm, Fin.ext_iff, Fin.val_zero, Fin.val_last, exists_prop, Set.toFinset_setOf,
      Finset.mem_univ, forall_true_left, Finset.mem_filter, add_eq_zero, and_false,
      add_left_inj, false_or, true_and, reduceCtorEq]
    simp_rw [this, false_or, ← Fin.ext_iff, exists_eq_right']
Bijection between compositions as sets and subsets of $\{0, \ldots, n-2\}$
Informal description
For any natural number $n$, there is a bijection between the set of compositions of $n$ (represented as `CompositionAsSet n`) and the subsets of $\{0, \ldots, n-2\}$ (represented as `Finset (Fin (n - 1))`). The bijection is constructed as follows: - Given a composition `c : CompositionAsSet n`, the corresponding subset consists of all elements $i \in \{0, \ldots, n-2\}$ such that $1 + i$ (interpreted as an element of $\{0, \ldots, n\}$) is a boundary point of `c`. - Conversely, given a subset $s \subseteq \{0, \ldots, n-2\}$, the corresponding composition has boundaries at $0$, $n$, and all points of the form $j + 1$ where $j \in s$. This bijection preserves the combinatorial structure of compositions and is used to establish counting results, such as the fact that there are $2^{n-1}$ compositions of $n$.
compositionAsSet_card theorem
(n : ℕ) : Fintype.card (CompositionAsSet n) = 2 ^ (n - 1)
Full source
theorem compositionAsSet_card (n : ) : Fintype.card (CompositionAsSet n) = 2 ^ (n - 1) := by
  have : Fintype.card (Finset (Fin (n - 1))) = 2 ^ (n - 1) := by simp
  rw [← this]
  exact Fintype.card_congr (compositionAsSetEquiv n)
Cardinality of Compositions as Sets: $|\text{CompositionAsSet}(n)| = 2^{n-1}$
Informal description
For any natural number $n$, the number of distinct compositions of $n$ represented as `CompositionAsSet` structures is equal to $2^{n-1}$.
CompositionAsSet.boundaries_nonempty theorem
: c.boundaries.Nonempty
Full source
theorem boundaries_nonempty : c.boundaries.Nonempty :=
  ⟨0, c.zero_mem⟩
Nonempty Boundaries in Composition as Set
Informal description
For any composition `c` represented as a set, the set of boundaries `c.boundaries` is nonempty.
CompositionAsSet.length definition
: ℕ
Full source
/-- Number of blocks in a `CompositionAsSet`. -/
def length :  :=
  Finset.card c.boundaries - 1
Number of blocks in a composition as a set
Informal description
The number of blocks in a composition represented as a set is equal to the cardinality of the set of boundaries minus one.
CompositionAsSet.card_boundaries_eq_succ_length theorem
: c.boundaries.card = c.length + 1
Full source
theorem card_boundaries_eq_succ_length : c.boundaries.card = c.length + 1 :=
  (tsub_eq_iff_eq_add_of_le (Nat.succ_le_of_lt c.card_boundaries_pos)).mp rfl
Cardinality of Boundaries Equals Number of Blocks Plus One
Informal description
For a composition `c` represented as a set, the cardinality of the set of boundaries `c.boundaries` is equal to the number of blocks `c.length` plus one, i.e., $|c.\text{boundaries}| = c.\text{length} + 1$.
CompositionAsSet.length_lt_card_boundaries theorem
: c.length < c.boundaries.card
Full source
theorem length_lt_card_boundaries : c.length < c.boundaries.card := by
  rw [c.card_boundaries_eq_succ_length]
  exact Nat.lt_add_one _
Number of Blocks is Less Than Boundary Cardinality in Composition as Set
Informal description
For any composition `c` of a natural number `n` represented as a set, the number of blocks `c.length` is strictly less than the cardinality of the set of boundaries `c.boundaries`.
CompositionAsSet.lt_length theorem
(i : Fin c.length) : (i : ℕ) + 1 < c.boundaries.card
Full source
theorem lt_length (i : Fin c.length) : (i : ) + 1 < c.boundaries.card :=
  lt_tsub_iff_right.mp i.2
Boundary Cardinality Upper Bound for Composition Indices
Informal description
For any composition `c` of a natural number `n` represented as a set, and for any index `i` in the range `[0, c.length)`, the value `i + 1` is strictly less than the cardinality of the set of boundaries `c.boundaries`.
CompositionAsSet.lt_length' theorem
(i : Fin c.length) : (i : ℕ) < c.boundaries.card
Full source
theorem lt_length' (i : Fin c.length) : (i : ) < c.boundaries.card :=
  lt_of_le_of_lt (Nat.le_succ i) (c.lt_length i)
Boundary Cardinality Upper Bound for Composition Indices (Weakened Form)
Informal description
For any composition `c` of a natural number `n` represented as a set, and for any index `i` in the range `[0, c.length)`, the value `i` is strictly less than the cardinality of the set of boundaries `c.boundaries`.
CompositionAsSet.boundary definition
: Fin c.boundaries.card ↪o Fin (n + 1)
Full source
/-- Canonical increasing bijection from `Fin c.boundaries.card` to `c.boundaries`. -/
def boundary : FinFin c.boundaries.card ↪o Fin (n + 1) :=
  c.boundaries.orderEmbOfFin rfl
Order embedding of composition boundaries
Informal description
The canonical order-preserving embedding from the finite type $\text{Fin } c.\text{boundaries.card}$ to the boundaries of the composition $c$, viewed as elements of $\text{Fin } (n + 1)$. This embedding is increasing and bijective, mapping each index to the corresponding boundary point in the composition.
CompositionAsSet.boundary_zero theorem
: (c.boundary ⟨0, c.card_boundaries_pos⟩ : Fin (n + 1)) = 0
Full source
@[simp]
theorem boundary_zero : (c.boundary ⟨0, c.card_boundaries_pos⟩ : Fin (n + 1)) = 0 := by
  rw [boundary, Finset.orderEmbOfFin_zero rfl c.card_boundaries_pos]
  exact le_antisymm (Finset.min'_le _ _ c.zero_mem) (Fin.zero_le _)
First Boundary Point is Zero in Composition as Set
Informal description
For any composition `c` of a natural number `n` represented as a set, the first boundary point (corresponding to index 0) is equal to 0 in `Fin (n + 1)`.
CompositionAsSet.boundary_length theorem
: c.boundary ⟨c.length, c.length_lt_card_boundaries⟩ = Fin.last n
Full source
@[simp]
theorem boundary_length : c.boundary ⟨c.length, c.length_lt_card_boundaries⟩ = Fin.last n := by
  convert Finset.orderEmbOfFin_last rfl c.card_boundaries_pos
  exact le_antisymm (Finset.le_max' _ _ c.getLast_mem) (Fin.le_last _)
Last Boundary Point Equals `n` in Composition as Set
Informal description
For a composition `c` of a natural number `n` represented as a set, the boundary point at index `c.length` (the last boundary) is equal to the last element `n` in `Fin (n + 1)`.
CompositionAsSet.blocksFun definition
(i : Fin c.length) : ℕ
Full source
/-- Size of the `i`-th block in a `CompositionAsSet`, seen as a function on `Fin c.length`. -/
def blocksFun (i : Fin c.length) :  :=
  c.boundary ⟨(i : ℕ) + 1, c.lt_length i⟩ - c.boundary ⟨i, c.lt_length' i⟩
Block sizes in a composition as a set
Informal description
For a composition `c` of a natural number `n` represented as a set, the function `c.blocksFun` maps each index `i ∈ Fin c.length` to the size of the `i`-th block, computed as the difference between consecutive boundary points: \[ c.\text{blocksFun}(i) = c.\text{boundary}(i+1) - c.\text{boundary}(i) \] where `c.boundary` is the increasing enumeration of the boundary points of the composition.
CompositionAsSet.blocksFun_pos theorem
(i : Fin c.length) : 0 < c.blocksFun i
Full source
theorem blocksFun_pos (i : Fin c.length) : 0 < c.blocksFun i :=
  haveI : (⟨i, c.lt_length' i⟩ : Fin c.boundaries.card) < ⟨i + 1, c.lt_length i⟩ :=
    Nat.lt_succ_self _
  lt_tsub_iff_left.mpr ((c.boundaries.orderEmbOfFin rfl).strictMono this)
Positivity of Block Sizes in Composition as Set
Informal description
For any composition `c` of a natural number `n` represented as a set, and for any index `i` in the range `[0, c.length)`, the size of the `i`-th block is positive, i.e., $c.\text{blocksFun}(i) > 0$.
CompositionAsSet.blocks definition
(c : CompositionAsSet n) : List ℕ
Full source
/-- List of the sizes of the blocks in a `CompositionAsSet`. -/
def blocks (c : CompositionAsSet n) : List  :=
  ofFn c.blocksFun
List of block sizes in a composition as a set
Informal description
For a composition `c` of a natural number `n` represented as a set, the list `c.blocks` consists of the sizes of the blocks in the composition, where each block size is given by the difference between consecutive boundary points. Specifically, if `c.boundary` is the increasing enumeration of the boundary points of the composition, then the `i`-th element of `c.blocks` is `c.boundary(i+1) - c.boundary(i)`.
CompositionAsSet.blocks_length theorem
: c.blocks.length = c.length
Full source
@[simp]
theorem blocks_length : c.blocks.length = c.length :=
  length_ofFn
Length of Blocks List Equals Number of Blocks in Composition as Set
Informal description
For any composition `c` of a natural number `n` represented as a set, the length of the list `c.blocks` (containing the sizes of the blocks) is equal to the number of blocks `c.length` in the composition.
CompositionAsSet.blocks_partial_sum theorem
{i : ℕ} (h : i < c.boundaries.card) : (c.blocks.take i).sum = c.boundary ⟨i, h⟩
Full source
theorem blocks_partial_sum {i : } (h : i < c.boundaries.card) :
    (c.blocks.take i).sum = c.boundary ⟨i, h⟩ := by
  induction i with
  | zero => simp
  | succ i IH =>
    have A : i < c.blocks.length := by
      rw [c.card_boundaries_eq_succ_length] at h
      simp [blocks, Nat.lt_of_succ_lt_succ h]
    have B : i < c.boundaries.card := lt_of_lt_of_le A (by simp [blocks, length, Nat.sub_le])
    rw [sum_take_succ _ _ A, IH B]
    simp [blocks, blocksFun, get_ofFn]
Partial Sum of Blocks Equals Boundary Point in Composition as Set
Informal description
For a composition `c` of a natural number `n` represented as a set, and for any natural number `i` such that `i < c.boundaries.card`, the sum of the first `i` blocks in `c.blocks` is equal to the `i`-th boundary point of `c`. In other words, if `c.boundary` is the increasing enumeration of the boundary points, then: \[ \sum_{k=0}^{i-1} c.\text{blocks}[k] = c.\text{boundary}(i) \]
CompositionAsSet.mem_boundaries_iff_exists_blocks_sum_take_eq theorem
{j : Fin (n + 1)} : j ∈ c.boundaries ↔ ∃ i < c.boundaries.card, (c.blocks.take i).sum = j
Full source
theorem mem_boundaries_iff_exists_blocks_sum_take_eq {j : Fin (n + 1)} :
    j ∈ c.boundariesj ∈ c.boundaries ↔ ∃ i < c.boundaries.card, (c.blocks.take i).sum = j := by
  constructor
  · intro hj
    rcases (c.boundaries.orderIsoOfFin rfl).surjective ⟨j, hj⟩ with ⟨i, hi⟩
    rw [Subtype.ext_iff, Subtype.coe_mk] at hi
    refine ⟨i.1, i.2, ?_⟩
    dsimp at hi
    rw [← hi, c.blocks_partial_sum i.2]
    rfl
  · rintro ⟨i, hi, H⟩
    convert (c.boundaries.orderIsoOfFin rfl ⟨i, hi⟩).2
    have : c.boundary ⟨i, hi⟩ = j := by rwa [Fin.ext_iff, ← c.blocks_partial_sum hi]
    exact this.symm
Characterization of Boundary Points via Partial Sums of Blocks
Informal description
For a composition `c` of a natural number `n` represented as a set, a point `j` in `Fin (n + 1)` is a boundary point of `c` if and only if there exists an index `i` less than the number of boundaries in `c` such that the sum of the first `i` block sizes equals `j`. In other words: \[ j \in c.\text{boundaries} \iff \exists i < c.\text{boundaries.card}, \sum_{k=0}^{i-1} c.\text{blocks}[k] = j \]
CompositionAsSet.blocks_sum theorem
: c.blocks.sum = n
Full source
theorem blocks_sum : c.blocks.sum = n := by
  have : c.blocks.take c.length = c.blocks := take_of_length_le (by simp [blocks])
  rw [← this, c.blocks_partial_sum c.length_lt_card_boundaries, c.boundary_length]
  rfl
Sum of Block Sizes Equals `n` in Composition as Set
Informal description
For a composition `c` of a natural number `n` represented as a set, the sum of the sizes of all blocks in `c.blocks` is equal to `n`. In other words: \[ \sum_{i=0}^{c.\text{length}-1} c.\text{blocksFun}(i) = n \]
CompositionAsSet.toComposition definition
: Composition n
Full source
/-- 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 where
  blocks := c.blocks
  blocks_pos := by simp only [blocks, forall_mem_ofFn_iff, blocksFun_pos c, forall_true_iff]
  blocks_sum := c.blocks_sum
Conversion from Composition as Set to List of Blocks
Informal description
Given a composition `c` of a natural number `n` represented as a set (i.e., a finite subset of `{0, ..., n}` containing `0` and `n`), the function `CompositionAsSet.toComposition` constructs a `Composition n` by converting the set representation into a list of positive integers `c.blocks` that sum to `n`. Here, `c.blocks` is defined as the list of differences between consecutive boundary points in the set representation, ensuring each block size is positive and their sum equals `n`.
Composition.toCompositionAsSet_length theorem
(c : Composition n) : c.toCompositionAsSet.length = c.length
Full source
@[simp]
theorem Composition.toCompositionAsSet_length (c : Composition n) :
    c.toCompositionAsSet.length = c.length := by
  simp [Composition.toCompositionAsSet, CompositionAsSet.length, c.card_boundaries_eq_succ_length]
Equality of Lengths in Composition Conversion
Informal description
For any composition $c$ of a natural number $n$, the length of the corresponding composition as a set (i.e., the number of blocks) is equal to the length of the original composition $c$.
CompositionAsSet.toComposition_length theorem
(c : CompositionAsSet n) : c.toComposition.length = c.length
Full source
@[simp]
theorem CompositionAsSet.toComposition_length (c : CompositionAsSet n) :
    c.toComposition.length = c.length := by
  simp [CompositionAsSet.toComposition, Composition.length, Composition.blocks]
Length Preservation in Composition Conversion from Set to List
Informal description
For any composition $c$ of a natural number $n$ represented as a set, the length of the corresponding composition (obtained via `toComposition`) is equal to the number of blocks in $c$.
Composition.toCompositionAsSet_blocks theorem
(c : Composition n) : c.toCompositionAsSet.blocks = c.blocks
Full source
@[simp]
theorem Composition.toCompositionAsSet_blocks (c : Composition n) :
    c.toCompositionAsSet.blocks = c.blocks := by
  let d := c.toCompositionAsSet
  change d.blocks = c.blocks
  have length_eq : d.blocks.length = c.blocks.length := by simp [d, blocks_length]
  suffices H : ∀ i ≤ d.blocks.length, (d.blocks.take i).sum = (c.blocks.take i).sum from
    eq_of_sum_take_eq length_eq H
  intro i hi
  have i_lt : i < d.boundaries.card := by
    simpa [CompositionAsSet.blocks, length_ofFn,
      d.card_boundaries_eq_succ_length] using Nat.lt_succ_iff.2 hi
  have i_lt' : i < c.boundaries.card := i_lt
  have i_lt'' : i < c.length + 1 := by rwa [c.card_boundaries_eq_succ_length] at i_lt'
  have A :
    d.boundaries.orderEmbOfFin rfl ⟨i, i_lt⟩ =
      c.boundaries.orderEmbOfFin c.card_boundaries_eq_succ_length ⟨i, i_lt''⟩ :=
    rfl
  have B : c.sizeUpTo i = c.boundary ⟨i, i_lt''⟩ := rfl
  rw [d.blocks_partial_sum i_lt, CompositionAsSet.boundary, ← Composition.sizeUpTo, B, A,
    c.orderEmbOfFin_boundaries]
Equality of Block Lists in Composition Conversion
Informal description
For any composition $c$ of a natural number $n$, the list of block sizes in the corresponding `CompositionAsSet` representation is equal to the original list of block sizes $c.\text{blocks}$.
CompositionAsSet.toComposition_blocks theorem
(c : CompositionAsSet n) : c.toComposition.blocks = c.blocks
Full source
@[simp]
theorem CompositionAsSet.toComposition_blocks (c : CompositionAsSet n) :
    c.toComposition.blocks = c.blocks :=
  rfl
Equality of Block Lists in Composition Conversion from Set to List
Informal description
For any composition $c$ of a natural number $n$ represented as a set, the list of block sizes in the corresponding `Composition` (obtained via `toComposition`) is equal to the original list of block sizes $c.\text{blocks}$.
CompositionAsSet.toComposition_boundaries theorem
(c : CompositionAsSet n) : c.toComposition.boundaries = c.boundaries
Full source
@[simp]
theorem CompositionAsSet.toComposition_boundaries (c : CompositionAsSet n) :
    c.toComposition.boundaries = c.boundaries := by
  ext j
  simp only [c.mem_boundaries_iff_exists_blocks_sum_take_eq, Composition.boundaries, Finset.mem_map]
  constructor
  · rintro ⟨i, _, hi⟩
    refine ⟨i.1, ?_, ?_⟩
    · simpa [c.card_boundaries_eq_succ_length] using i.2
    · simp [Composition.boundary, Composition.sizeUpTo, ← hi]
  · rintro ⟨i, i_lt, hi⟩
    refine ⟨i, by simp, ?_⟩
    rw [c.card_boundaries_eq_succ_length] at i_lt
    simp [Composition.boundary, Nat.mod_eq_of_lt i_lt, Composition.sizeUpTo, hi]
Boundary Preservation in Composition Conversion from Set to List
Informal description
For any composition $c$ of a natural number $n$ represented as a set, the boundaries of the corresponding `Composition` (obtained via `toComposition`) are equal to the original boundaries $c.\text{boundaries}$.
Composition.toCompositionAsSet_boundaries theorem
(c : Composition n) : c.toCompositionAsSet.boundaries = c.boundaries
Full source
@[simp]
theorem Composition.toCompositionAsSet_boundaries (c : Composition n) :
    c.toCompositionAsSet.boundaries = c.boundaries :=
  rfl
Equality of Boundaries in Composition Conversion
Informal description
For any composition $c$ of a natural number $n$, the boundaries of the corresponding `CompositionAsSet` (obtained via `toCompositionAsSet`) are equal to the boundaries of $c$.
compositionEquiv definition
(n : ℕ) : Composition n ≃ CompositionAsSet n
Full source
/-- Equivalence between `Composition n` and `CompositionAsSet n`. -/
def compositionEquiv (n : ) : CompositionComposition n ≃ CompositionAsSet n where
  toFun c := c.toCompositionAsSet
  invFun c := c.toComposition
  left_inv c := by
    ext1
    exact c.toCompositionAsSet_blocks
  right_inv c := by
    ext1
    exact c.toComposition_boundaries
Equivalence between List and Set Representations of Compositions
Informal description
The equivalence `compositionEquiv` establishes a bijection between the type `Composition n` of compositions of a natural number $n$ (represented as lists of positive integers summing to $n$) and the type `CompositionAsSet n` of compositions viewed as finite subsets of $\{0, \dots, n\}$ containing both $0$ and $n$. Specifically: - The forward map `toFun` converts a composition $c$ to its set representation by taking the boundaries of the blocks (including $0$ and $n$). - The inverse map `invFun` converts a set representation back to a list of block sizes by computing the differences between consecutive boundary points. - The maps are mutual inverses, as verified by the proofs `left_inv` and `right_inv`.
compositionFintype instance
(n : ℕ) : Fintype (Composition n)
Full source
instance compositionFintype (n : ) : Fintype (Composition n) :=
  Fintype.ofEquiv _ (compositionEquiv n).symm
Finite Type Structure for Compositions of Natural Numbers
Informal description
For any natural number $n$, the type of compositions of $n$ (lists of positive integers summing to $n$) is a finite type.
composition_card theorem
(n : ℕ) : Fintype.card (Composition n) = 2 ^ (n - 1)
Full source
theorem composition_card (n : ) : Fintype.card (Composition n) = 2 ^ (n - 1) := by
  rw [← compositionAsSet_card n]
  exact Fintype.card_congr (compositionEquiv n)
Cardinality of Compositions: $|\text{Composition}(n)| = 2^{n-1}$
Informal description
For any natural number $n$, the number of distinct compositions of $n$ (represented as lists of positive integers summing to $n$) is equal to $2^{n-1}$.