Finite sets #
Terms of type finset α
are one way of talking about finite subsets of α
in mathlib.
Below, finset α
is defined as a structure with 2 fields:
val
is amultiset α
of elements;nodup
is a proof thatval
has no duplicates.
Finsets in Lean are constructive in that they have an underlying list
that enumerates their
elements. In particular, any function that uses the data of the underlying list cannot depend on its
ordering. This is handled on the multiset
level by multiset API, so in most cases one needn't
worry about it explicitly.
Finsets give a basic foundation for defining finite sums and products over types:
Lean refers to these operations as big_operator
s.
More information can be found in algebra.big_operators.basic
.
Finsets are directly used to define fintypes in Lean.
A fintype α
instance for a type α
consists of
a universal finset α
containing every term of α
, called univ
. See data.fintype.basic
.
There is also univ'
, the noncomputable partner to univ
,
which is defined to be α
as a finset if α
is finite,
and the empty finset otherwise. See data.fintype.basic
.
finset.card
, the size of a finset is defined in data.finset.card
. This is then used to define
fintype.card
, the size of a type.
Main declarations #
Main definitions #
finset
: Defines a type for the finite subsets ofα
. Constructing afinset
requires two pieces of data:val
, amultiset α
of elements, andnodup
, a proof thatval
has no duplicates.finset.has_mem
: Defines membershipa ∈ (s : finset α)
.finset.has_coe
: Provides a coercions : finset α
tos : set α
.finset.has_coe_to_sort
: Coerces : finset α
to the type of allx ∈ s
.finset.induction_on
: Induction on finsets. To prove a proposition about an arbitraryfinset α
, it suffices to prove it for the empty finset, and to show that if it holds for somefinset α
, then it holds for the finset obtained by inserting a new element.finset.choose
: Given a proofh
of existence and uniqueness of a certain element satisfying a predicate,choose s h
returns the element ofs
satisfying that predicate.
Finset constructions #
singleton
: Denoted by{a}
; the finset consisting of one element.finset.empty
: Denoted by∅
. The finset associated to any type consisting of no elements.finset.range
: For anyn : ℕ
,range n
is equal to{0, 1, ... , n - 1} ⊆ ℕ
. This convention is consistent with other languages and normalizescard (range n) = n
. Beware,n
is not inrange n
.finset.attach
: Givens : finset α
,attach s
forms a finset of elements of the subtype{a // a ∈ s}
; in other words, it attaches elements to a proof of membership in the set.
Finsets from functions #
finset.image
: Given a functionf : α → β
,s.image f
is the image finset inβ
.finset.map
: Given an embeddingf : α ↪ β
,s.map f
is the image finset inβ
.finset.filter
: Given a predicatep : α → Prop
,s.filter p
is the finset consisting of those elements ins
satisfying the predicatep
.
The lattice structure on subsets of finsets #
There is a natural lattice structure on the subsets of a set.
In Lean, we use lattice notation to talk about things involving unions and intersections. See
order.lattice
. For the lattice structure on finsets, ⊥
is called bot
with ⊥ = ∅
and ⊤
is
called top
with ⊤ = univ
.
finset.has_subset
: Lots of API about lattices, otherwise behaves exactly as one would expect.finset.has_union
: Definess ∪ t
(ors ⊔ t
) as the union ofs
andt
. Seefinset.sup
/finset.bUnion
for finite unions.finset.has_inter
: Definess ∩ t
(ors ⊓ t
) as the intersection ofs
andt
. Seefinset.inf
for finite intersections.finset.disj_union
: Given a hypothesish
which states that finsetss
andt
are disjoint,s.disj_union t h
is the set such thata ∈ disj_union s t h
iffa ∈ s
ora ∈ t
; this does not require decidable equality on the typeα
.
Operations on two or more finsets #
insert
andfinset.cons
: For anya : α
,insert s a
returnss ∪ {a}
.cons s a h
returns the same except that it requires a hypothesis stating thata
is not already ins
. This does not require decidable equality on the typeα
.finset.has_union
: see "The lattice structure on subsets of finsets"finset.has_inter
: see "The lattice structure on subsets of finsets"finset.erase
: For anya : α
,erase s a
returnss
with the elementa
removed.finset.has_sdiff
: Defines the set differences \ t
for finsetss
andt
.finset.product
: Given finsets ofα
andβ
, defines finsets ofα × β
. For arbitrary dependent products, seedata.finset.pi
.finset.bUnion
: Finite unions of finsets; given an indexing functionf : α → finset β
and as : finset α
,s.bUnion f
is the union of all finsets of the formf a
fora ∈ s
.finset.bInter
: TODO: Implemement finite intersections.
Maps constructed using finsets #
finset.piecewise
: Given two functionsf
,g
,s.piecewise f g
is a function which is equal tof
ons
andg
on the complement.
Predicates on finsets #
disjoint
: defined via the lattice structure on finsets; two sets are disjoint if their intersection is empty.finset.nonempty
: A finset is nonempty if it has elements. This is equivalent to sayings ≠ ∅
. TODO: Decide on the simp normal form.
Equivalences between finsets #
- The
data.equiv
files describe a general type of equivalence, so look in there for any lemmas. There is some API for rewriting sums and products froms
tot
given thats ≃ t
. TODO: examples
Tags #
finite sets, finset
Equations
- finset.has_decidable_eq s₁ s₂ = decidable_of_iff (s₁.val = s₂.val) finset.val_inj
membership #
Equations
set coercion #
Equations
extensionality #
type coercion #
Coercion from a finset to the corresponding subtype.
Equations
- finset.pi_finset_coe.can_lift ι α s = {coe := λ (f : Π (i : ι), α i) (i : ↥s), f ↑i, cond := can_lift.cond (Π (i : ι), α i) (pi_subtype.can_lift ι α (λ (_x : ι), _x ∈ s)), prf := _}
Equations
- finset.pi_finset_coe.can_lift' ι α s = finset.pi_finset_coe.can_lift ι (λ (_x : ι), α) s
Equations
- finset.finset_coe.can_lift s = {coe := coe coe_to_lift, cond := λ (a : α), a ∈ s, prf := _}
Subset and strict subset relations #
Equations
- finset.partial_order = {le := has_subset.subset finset.has_subset, lt := has_ssubset.ssubset finset.has_ssubset, le_refl := _, le_trans := _, lt_iff_le_not_le := _, le_antisymm := _}
Coercion to set α
as an order_embedding
.
Equations
- finset.coe_emb = {to_embedding := {to_fun := coe coe_to_lift, inj' := _}, map_rel_iff' := _}
Nonempty #
The property s.nonempty
expresses the fact that the finset s
is not empty. It should be used
in theorem assumptions instead of ∃ x, x ∈ s
or s ≠ ∅
as it gives access to a nice API thanks
to the dot notation.
empty #
Equations
Equations
singleton #
{a} : finset a
is the set {a}
containing a
and nothing else.
This differs from insert a ∅
in that it does not require a decidable_eq
instance for α
.
cons #
cons a s h
is the set {a} ∪ s
containing a
and the elements of s
. It is the same as
insert a s
when it is defined, but unlike insert a s
it does not require decidable_eq α
,
and the union is guaranteed to be disjoint.
disjoint union #
disj_union s t h
is the set such that a ∈ disj_union s t h
iff a ∈ s
or a ∈ t
.
It is the same as s ∪ t
, but it does not require decidable equality on the type. The hypothesis
ensures that the sets are disjoint.
insert #
insert a s
is the set {a} ∪ s
containing a
and the elements of s
.
Equations
- finset.has_insert = {insert := λ (a : α) (s : finset α), {val := multiset.ndinsert a s.val, nodup := _}}
The universe annotation is required for the following instance, possibly this is a bug in Lean. See leanprover.zulipchat.com/#narrow/stream/113488-general/topic/strange.20error.20(universe.20issue.3F)
To prove a proposition about an arbitrary finset α
,
it suffices to prove it for the empty finset
,
and to show that if it holds for some finset α
,
then it holds for the finset
obtained by inserting a new element.
To prove a proposition about S : finset α
,
it suffices to prove it for the empty finset
,
and to show that if it holds for some finset α ⊆ S
,
then it holds for the finset
obtained by inserting a new element of S
.
To prove a proposition about a nonempty s : finset α
, it suffices to show it holds for all
singletons and that if it holds for nonempty t : finset α
, then it also holds for the finset
obtained by inserting an element in t
.
Inserting an element to a finite set is equivalent to the option type.
Lattice structure #
Equations
- finset.lattice = {sup := has_union.union finset.has_union, le := partial_order.le finset.partial_order, lt := partial_order.lt finset.partial_order, le_refl := _, le_trans := _, lt_iff_le_not_le := _, le_antisymm := _, le_sup_left := _, le_sup_right := _, sup_le := _, inf := has_inter.inter finset.has_inter, inf_le_left := _, inf_le_right := _, le_inf := _}
union #
To prove a relation on pairs of finset X
, it suffices to show that it is
- symmetric,
- it holds when one of the
finset
s is empty, - it holds for pairs of singletons,
- if it holds for
[a, c]
and for[b, c]
, then it holds for[a ∪ b, c]
.
inter #
Equations
- finset.distrib_lattice = {sup := lattice.sup finset.lattice, le := lattice.le finset.lattice, lt := lattice.lt finset.lattice, le_refl := _, le_trans := _, lt_iff_le_not_le := _, le_antisymm := _, le_sup_left := _, le_sup_right := _, sup_le := _, inf := lattice.inf finset.lattice, inf_le_left := _, inf_le_right := _, le_inf := _, le_sup_inf := _}
erase #
An element of s
that is not an element of erase s a
must be
a
.
sdiff #
Equations
- finset.generalized_boolean_algebra = {sup := distrib_lattice.sup finset.distrib_lattice, le := distrib_lattice.le finset.distrib_lattice, lt := distrib_lattice.lt finset.distrib_lattice, le_refl := _, le_trans := _, lt_iff_le_not_le := _, le_antisymm := _, le_sup_left := _, le_sup_right := _, sup_le := _, inf := distrib_lattice.inf finset.distrib_lattice, inf_le_left := _, inf_le_right := _, le_inf := _, le_sup_inf := _, sdiff := sdiff finset.has_sdiff, bot := order_bot.bot finset.order_bot, sup_inf_sdiff := _, inf_inf_sdiff := _}
attach #
piecewise #
decidable equality for functions whose domain is bounded by finsets
filter #
filter p s
is the set of elements of s
that satisfy p
.
Equations
- finset.filter p s = {val := multiset.filter p s.val, nodup := _}
If all elements of a finset
satisfy the predicate p
, s.filter p
is s
.
If all elements of a finset
fail to satisfy the predicate p
, s.filter p
is ∅
.
The following instance allows us to write {x ∈ s | p x}
for finset.filter p s
.
Since the former notation requires us to define this for all propositions p
, and finset.filter
only works for decidable propositions, the notation {x ∈ s | p x}
is only compatible with
classical logic because it uses classical.prop_decidable
.
We don't want to redo all lemmas of finset.filter
for has_sep.sep
, so we make sure that simp
unfolds the notation {x ∈ s | p x}
to finset.filter p s
. If p
happens to be decidable, the
simp-lemma finset.filter_congr_decidable
will make sure that finset.filter
uses the right
instance for decidability.
Equations
- finset.has_sep = {sep := λ (p : α → Prop) (x : finset α), finset.filter p x}
After filtering out everything that does not equal a given value, at most that value remains.
This is equivalent to filter_eq'
with the equality the other way.
After filtering out everything that does not equal a given value, at most that value remains.
This is equivalent to filter_eq
with the equality the other way.
range #
range n
is the set of natural numbers less than n
.
Equations
- finset.range n = {val := multiset.range n, nodup := _}
Equivalence between the set of natural numbers which are ≥ k
and ℕ
, given by n → n - k
.
dedup on list and multiset #
to_finset l
removes duplicates from the list l
to produce a finset.
map #
When f
is an embedding of α
in β
and s
is a finset in α
, then s.map f
is the image
finset in β
. The embedding condition guarantees that there are no duplicates in the image.
Equations
- finset.map f s = {val := multiset.map ⇑f s.val, nodup := _}
If the only elements outside s
are those left fixed by σ
, then mapping by σ
has no effect.
Associate to an embedding f
from α
to β
the order embedding that maps a finset to its
image under f
.
Equations
Alias of map_nonempty
.
image #
image f s
is the forward image of s
under f
.
Equations
- finset.image f s = (multiset.map f s.val).to_finset
Equations
- finset.can_lift = {coe := finset.image can_lift.coe, cond := λ (s : finset β), ∀ (x : β), x ∈ s → can_lift.cond α x, prf := _}
Subtype #
Given a finset s
and a predicate p
, s.subtype p
is the finset of subtype p
whose
elements belong to s
.
Equations
- finset.subtype p s = finset.map {to_fun := λ (x : {x // x ∈ finset.filter p s}), ⟨x.val, _⟩, inj' := _} (finset.filter p s).attach
s.subtype p
converts back to s.filter p
with
embedding.subtype
.
If all elements of a finset
satisfy the predicate p
,
s.subtype p
converts back to s
with embedding.subtype
.
If a finset
of a subtype is converted to the main type with
embedding.subtype
, all elements of the result have the property of
the subtype.
If a finset
of a subtype is converted to the main type with
embedding.subtype
, the result does not contain any value that does
not satisfy the property of the subtype.
If a finset
of a subtype is converted to the main type with
embedding.subtype
, the result is a subset of the set giving the
subtype.
bUnion #
This section is about the bounded union of an indexed family t : α → finset β
of finite sets
over a finite set s : finset α
.
bUnion s t
is the union of t x
over x ∈ s
.
(This was formerly bind
due to the monad structure on types with decidable_eq
.)
disjoint #
Equations
- U.decidable_disjoint V = decidable_of_decidable_of_iff (finset.has_decidable_eq (U ⊓ V) ⊥) _
choose #
Given a finset l
and a predicate p
, associate to a proof that there is a unique element of
l
satisfying p
this unique element, as an element of the corresponding subtype.
Equations
- finset.choose_x p l hp = multiset.choose_x p l.val hp
Given a finset l
and a predicate p
, associate to a proof that there is a unique element of
l
satisfying p
this unique element, as an element of the ambient type.
Equations
- finset.choose p l hp = ↑(finset.choose_x p l hp)
Given an equivalence α
to β
, produce an equivalence between finset α
and finset β
.
Equations
- e.finset_congr = {to_fun := λ (s : finset α), finset.map e.to_embedding s, inv_fun := λ (s : finset β), finset.map e.symm.to_embedding s, left_inv := _, right_inv := _}
Inhabited types are equivalent to option β
for some β
by identifying default α
with none
.