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 ton
.composition_card
states that the cardinality ofComposition n
is exactly2^(n-1)
, which is proved by constructing an equiv withCompositionAsSet n
(see below), which is itself in bijection with the subsets ofFin (n-1)
(this holds even forn = 0
, where-
is nat subtraction).
Let c : Composition n
be a composition of n
. Then
-
c.blocks
is the list of blocks inc
. -
c.length
is the number of blocks in the composition. -
c.blocks_fun : Fin c.length → ℕ
is the realization ofc.blocks
as a function onFin 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 toi
.; -
c.embedding i : Fin (c.blocks_fun i) → Fin n
is the increasing embedding of thei
-th block inFin n
; -
c.index j
, forj : Fin n
, is the index of the block containingj
. -
Composition.ones n
is the composition ofn
made of ones, i.e.,[1, ..., 1]
. -
Composition.single n (hn : 0 < n)
is the composition ofn
made of a single block of sizen
.
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 ofl
corresponding to the blocks ofc
.join_splitWrtComposition
states that splitting a list and then joining it gives back the original list.joinSplitWrtComposition_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 #
A composition of n
is a list of positive integers summing to n
.
Instances For
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
.
Combinatorial viewpoint on a composition of
n
as consecutive integers{0, ..., n-1}
- zero_mem : 0 ∈ self.boundaries
Proof that
0
is a member ofboundaries
Last element of the composition
Instances For
Equations
- instInhabitedCompositionAsSet = { default := { boundaries := Finset.univ, zero_mem := ⋯, getLast_mem := ⋯ } }
Compositions #
A composition of an integer n
is a decomposition n = i₀ + ... + i_{k-1}
of n
into a sum of
positive integers.
Equations
- Composition.instToStringComposition n = { toString := fun (c : Composition n) => toString c.blocks }
The length of a composition, i.e., the number of blocks in the composition.
Equations
- Composition.length c = List.length c.blocks
Instances For
The blocks of a composition, seen as a function on Fin c.length
. When composing analytic
functions using compositions, this is the main player.
Equations
- Composition.blocksFun c = List.get c.blocks
Instances For
The sum of the sizes of the blocks in a composition up to i
.
Equations
- Composition.sizeUpTo c i = List.sum (List.take i c.blocks)
Instances For
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
.
Equations
- Composition.boundary c = OrderEmbedding.ofStrictMono (fun (i : Fin (Composition.length c + 1)) => { val := Composition.sizeUpTo c ↑i, isLt := ⋯ }) ⋯
Instances For
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
.
Equations
- Composition.boundaries c = Finset.map (Composition.boundary c).toEmbedding Finset.univ
Instances For
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.
Equations
- Composition.toCompositionAsSet c = { boundaries := Composition.boundaries c, zero_mem := ⋯, getLast_mem := ⋯ }
Instances For
The canonical increasing bijection between Fin (c.length + 1)
and c.boundaries
is
exactly c.boundary
.
Embedding the i
-th block of a composition (identified with Fin (c.blocks_fun i)
) into
Fin n
at the relevant position.
Equations
- Composition.embedding c i = RelEmbedding.trans (Fin.natAddEmb (Composition.sizeUpTo c ↑i)) (Fin.castLEEmb ⋯)
Instances For
index_exists
asserts there is some i
with j < c.size_up_to (i+1)
.
In the next definition index
we use nat.find
to produce the minimal such index.
c.index j
is the index of the block in the composition c
containing j
.
Equations
- Composition.index c j = { val := Nat.find ⋯, isLt := ⋯ }
Instances For
Mapping an element j
of Fin n
to the element in the block containing it, identified with
Fin (c.blocks_fun (c.index j))
through the canonical increasing bijection.
Equations
- Composition.invEmbedding c j = { val := ↑j - Composition.sizeUpTo c ↑(Composition.index c j), isLt := ⋯ }
Instances For
The embeddings of different blocks of a composition are disjoint.
Equivalence between the disjoint union of the blocks (each of them seen as
Fin (c.blocks_fun i)
) with Fin n
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Two compositions (possibly of different integers) coincide if and only if they have the same sequence of blocks.
The composition Composition.ones
#
The composition made of blocks all of size 1
.
Equations
- Composition.ones n = { blocks := List.replicate n 1, blocks_pos := ⋯, blocks_sum := ⋯ }
Instances For
Equations
- Composition.instInhabitedComposition = { default := Composition.ones n }
The composition Composition.single
#
The composition made of a single block of size n
.
Equations
- Composition.single n h = { blocks := [n], blocks_pos := ⋯, blocks_sum := ⋯ }
Instances For
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.blocks_fun 0
, ..., c.blocks_fun (c.length-1)
. This is inverse to the
join operation.
Auxiliary for List.splitWrtComposition
.
Equations
- List.splitWrtCompositionAux x [] = []
- List.splitWrtCompositionAux x (n :: ns) = match List.splitAt n x with | (l₁, l₂) => l₁ :: List.splitWrtCompositionAux l₂ ns
Instances For
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.
Equations
- List.splitWrtComposition l c = List.splitWrtCompositionAux l c.blocks
Instances For
When one splits a list along a composition c
, the number of sublists thus created is
c.length
.
When one splits a list along a composition c
, the lengths of the sublists thus created are
given by the block sizes in c
.
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.
If one splits a list along a composition, and then joins the sublists, one gets back the original list.
If one joins a list of lists and then splits the join along the right composition, one gets back the original list of lists.
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.
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.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- compositionAsSetFintype n = Fintype.ofEquiv (Finset (Fin (n - 1))) (compositionAsSetEquiv n).symm
Number of blocks in a CompositionAsSet
.
Equations
- CompositionAsSet.length c = c.boundaries.card - 1
Instances For
Canonical increasing bijection from Fin c.boundaries.card
to c.boundaries
.
Equations
- CompositionAsSet.boundary c = Finset.orderEmbOfFin c.boundaries ⋯
Instances For
Size of the i
-th block in a CompositionAsSet
, seen as a function on Fin c.length
.
Equations
- CompositionAsSet.blocksFun c i = ↑((CompositionAsSet.boundary c) { val := ↑i + 1, isLt := ⋯ }) - ↑((CompositionAsSet.boundary c) { val := ↑i, isLt := ⋯ })
Instances For
Associating a Composition n
to a CompositionAsSet n
, by registering the sizes of the
blocks as a list of positive integers.
Equations
- CompositionAsSet.toComposition c = { blocks := CompositionAsSet.blocks c, blocks_pos := ⋯, blocks_sum := ⋯ }
Instances For
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
.
Equivalence between Composition n
and CompositionAsSet n
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- compositionFintype n = Fintype.ofEquiv (CompositionAsSet n) (compositionEquiv n).symm