The finite type with n
elements #
fin n
is the type whose elements are natural numbers smaller than n
.
This file expands on the development in the core library.
Main definitions #
Induction principles #
fin_zero_elim
: Elimination principle for the empty setfin 0
, generalizesfin.elim0
.fin.succ_rec
: DefineC n i
by induction oni : fin n
interpreted as(0 : fin (n - i)).succ.succ…
. This function has two arguments:H0 n
defines0
-th elementC (n+1) 0
of an(n+1)
-tuple, andHs n i
defines(i+1)
-st element of(n+1)
-tuple based onn
,i
, andi
-th element ofn
-tuple.fin.succ_rec_on
: same asfin.succ_rec
buti : fin n
is the first argument;fin.induction
: DefineC i
by induction oni : fin (n + 1)
, separating into thenat
-like base cases ofC 0
andC (i.succ)
.fin.induction_on
: same asfin.induction
but withi : fin (n + 1)
as the first argument.
Casts #
cast_lt i h
: embedi
into afin
whereh
proves it belongs into;cast_le h
: embedfin n
intofin m
,h : n ≤ m
;cast eq
: embedfin n
intofin m
,eq : n = m
;cast_add m
: embedfin n
intofin (n+m)
;cast_succ
: embedfin n
intofin (n+1)
;succ_above p
: embedfin n
intofin (n + 1)
with a hole aroundp
;pred_above (p : fin n) i
: embedi : fin (n+1)
intofin n
by subtracting one ifp < i
;cast_pred
: embedfin (n + 2)
intofin (n + 1)
by mappinglast (n + 1)
tolast n
;sub_nat i h
: subtractm
fromi ≥ m
, generalizesfin.pred
;add_nat m i
: addm
oni
on the right, generalizesfin.succ
;nat_add n i
addsn
oni
on the left;clamp n m
:min n m
as an element offin (m + 1)
;
Operation on tuples #
We interpret maps Π i : fin n, α i
as tuples (α 0, …, α (n-1))
.
If α i
is a constant map, then tuples are isomorphic (but not definitionally equal)
to vector
s.
We define the following operations:
tail
: the tail of ann+1
tuple, i.e., its lastn
entries;cons
: adding an element at the beginning of ann
-tuple, to get ann+1
-tuple;init
: the beginning of ann+1
tuple, i.e., its firstn
entries;snoc
: adding an element at the end of ann
-tuple, to get ann+1
-tuple. The namesnoc
comes fromcons
(i.e., adding an element to the left of a tuple) read in reverse order.insert_nth
: insert an element to a tuple at a given position.find p
: returns the first indexn
wherep n
is satisfied, andnone
if it is never satisfied.
Misc definitions #
Elimination principle for the empty set fin 0
, dependent version.
Equations
- fin_zero_elim x = x.elim0
Equations
- fin.fin_to_nat n = {coe := subtype.val (λ (i : ℕ), i < n)}
coercions and constructions #
order #
Equations
- fin.linear_order = {le := has_le.le fin.has_le, lt := has_lt.lt fin.has_lt, le_refl := _, le_trans := _, lt_iff_le_not_le := _, le_antisymm := _, le_total := _, decidable_le := fin.decidable_le n, decidable_eq := fin.decidable_eq n, decidable_lt := fin.decidable_lt n}
The inclusion map fin n → ℕ
is a relation embedding.
Equations
- fin.coe_embedding n = {to_embedding := {to_fun := coe coe_to_lift, inj' := _}, map_rel_iff' := _}
The ordering on fin n
is a well order.
Use the ordering on fin n
for checking recursive definitions.
For example, the following definition is not accepted by the termination checker,
unless we declare the has_well_founded
instance:
def factorial {n : ℕ} : fin n → ℕ
| ⟨0, _⟩ := 1
| ⟨i + 1, hi⟩ := (i + 1) * factorial ⟨i, i.lt_succ_self.trans hi⟩
Equations
- fin.bounded_lattice = {sup := lattice.sup lattice_of_linear_order, le := linear_order.le fin.linear_order, lt := linear_order.lt fin.linear_order, le_refl := _, le_trans := _, lt_iff_le_not_le := _, le_antisymm := _, le_sup_left := _, le_sup_right := _, sup_le := _, inf := lattice.inf lattice_of_linear_order, inf_le_left := _, inf_le_right := _, le_inf := _, top := fin.last n, le_top := _, bot := 0, bot_le := _}
Equations
- fin.order_iso_unique = unique.mk' (fin n ≃o fin n)
Two strictly monotone functions from fin n
are equal provided that their ranges
are equal.
addition, numerals, and coercion from nat #
Equations
- fin.add_comm_monoid n = {add := has_add.add fin.has_add, add_assoc := _, zero := 0, zero_add := _, add_zero := _, nsmul := add_monoid.nsmul._default 0 has_add.add fin.zero_add fin.add_zero, nsmul_zero' := _, nsmul_succ' := _, add_comm := _}
succ and casts into larger fin types #
fin.succ
as an order_embedding
Equations
cast_le h i
embeds i
into a larger fin
type.
Equations
- fin.cast_le h = order_embedding.of_strict_mono (λ (a : fin n), a.cast_lt _) fin.cast_le._proof_2
While in many cases fin.cast
is better than equiv.cast
/cast
, sometimes we want to apply
a generic theorem about cast
.
cast_add m i
embeds i : fin n
in fin (n+m)
.
Equations
- fin.cast_add m = fin.cast_le _
cast_succ i
is positive when i
is positive
nat_add n i
adds n
to i
"on the left".
Equations
- fin.nat_add n = order_embedding.of_strict_mono (λ (i : fin m), ⟨n + ↑i, _⟩) _
recursion and induction principles #
Define C n i
by induction on i : fin n
interpreted as (0 : fin (n - i)).succ.succ…
.
This function has two arguments: H0 n
defines 0
-th element C (n+1) 0
of an (n+1)
-tuple,
and Hs n i
defines (i+1)
-st element of (n+1)
-tuple based on n
, i
, and i
-th element
of n
-tuple.
Equations
- fin.succ_rec H0 Hs ⟨i.succ, h⟩ = Hs n ⟨i, _⟩ (fin.succ_rec H0 Hs ⟨i, _⟩)
- fin.succ_rec H0 Hs ⟨0, _x⟩ = H0 n
- fin.succ_rec H0 Hs i = i.elim0
Define C n i
by induction on i : fin n
interpreted as (0 : fin (n - i)).succ.succ…
.
This function has two arguments: H0 n
defines 0
-th element C (n+1) 0
of an (n+1)
-tuple,
and Hs n i
defines (i+1)
-st element of (n+1)
-tuple based on n
, i
, and i
-th element
of n
-tuple.
A version of fin.succ_rec
taking i : fin n
as the first argument.
Equations
- i.succ_rec_on H0 Hs = fin.succ_rec H0 Hs i
Define C i
by induction on i : fin (n + 1)
via induction on the underlying nat
value.
This function has two arguments: h0
handles the base case on C 0
,
and hs
defines the inductive step using C i.cast_succ
.
Define C i
by induction on i : fin (n + 1)
via induction on the underlying nat
value.
This function has two arguments: h0
handles the base case on C 0
,
and hs
defines the inductive step using C i.cast_succ
.
A version of fin.induction
taking i : fin (n + 1)
as the first argument.
Equations
- i.induction_on h0 hs = fin.induction h0 hs i
Define f : Π i : fin n.succ, C i
by separately handling the cases i = 0
and
i = j.succ
, j : fin n
.
Equations
- fin.cases H0 Hs = fin.induction H0 (λ (i : fin n) (_x : C (⇑fin.cast_succ i)), Hs i)
pred #
Abelian group structure on fin (n+1)
.
Equations
- fin.add_comm_group n = {add := add_comm_monoid.add (fin.add_comm_monoid n), add_assoc := _, zero := add_comm_monoid.zero (fin.add_comm_monoid n), zero_add := _, add_zero := _, nsmul := add_comm_monoid.nsmul (fin.add_comm_monoid n), nsmul_zero' := _, nsmul_succ' := _, neg := has_neg.neg (fin.has_neg n.succ), sub := fin.sub (n + 1), sub_eq_add_neg := _, gsmul := add_group.gsmul._default add_comm_monoid.add _ add_comm_monoid.zero _ _ add_comm_monoid.nsmul _ _ has_neg.neg, gsmul_zero' := _, gsmul_succ' := _, gsmul_neg' := _, add_left_neg := _, add_comm := _}
succ_above p i
embeds fin n
into fin (n + 1)
with a hole around p
.
Equations
- p.succ_above = order_embedding.of_strict_mono (λ (a : fin n), (λ (i : fin n), ite (⇑fin.cast_succ i < p) (⇑fin.cast_succ i) i.succ) a) _
Embedding i : fin n
into fin (n + 1)
with a hole around p : fin (n + 1)
embeds i
by cast_succ
when the resulting i.cast_succ < p
.
Embedding i : fin n
into fin (n + 1)
is always about some hole p
.
Embedding i : fin n
into fin (n + 1)
using a pivot p
that is greater
results in a value that is less than p
.
Embedding i : fin n
into fin (n + 1)
using a pivot p
that is lesser
results in a value that is greater than p
.
Given a fixed pivot x : fin (n + 1)
, x.succ_above
is injective
Given a fixed pivot x : fin (n + 1)
, x.succ_above
is injective
succ_above
is injective at the pivot
succ_above
is injective at the pivot
By moving succ
to the outside of this expression, we create opportunities for further
simplification using succ_above_zero
or succ_succ_above_zero
.
pred_above p i
embeds i : fin (n+1)
into fin n
by subtracting one if p < i
.
Equations
- p.pred_above i = dite (⇑fin.cast_succ p < i) (λ (h : ⇑fin.cast_succ p < i), i.pred _) (λ (h : ¬⇑fin.cast_succ p < i), i.cast_lt _)
Sending fin (n+1)
to fin n
by subtracting one from anything above p
then back to fin (n+1)
with a gap around p
is the identity away from p
.
Sending fin n
into fin (n + 1)
with a gap at p
then back to fin n
by subtracting one from anything above p
is the identity.
Tuples #
We can think of the type Π(i : fin n), α i
as n
-tuples of elements of possibly varying type
α i
. A particular case is fin n → α
of elements with all the same type. Here are some relevant
operations, first about adding or removing elements at the beginning of a tuple.
There is exactly one tuple of size zero.
Equations
- fin.tuple0_unique α = pi.unique_of_empty fin.tuple0_unique._proof_1 α
Updating a tuple and adding an element at the beginning commute.
Updating a nonzero element and taking the tail commute.
fin.append ho u v
appends two vectors of lengths m
and n
to produce
one of length o = m + n
. ho
provides control of definitional equality
for the vector length.
In the previous section, we have discussed inserting or removing elements on the left of a
tuple. In this section, we do the same on the right. A difference is that fin (n+1)
is constructed
inductively from fin n
starting from the left, not from the right. This implies that Lean needs
more help to realize that elements belong to the right types, i.e., we need to insert casts at
several places.
Adding an element at the end of an n
-tuple, to get an n+1
-tuple. The name snoc
comes from
cons
(i.e., adding an element to the left of a tuple) read in reverse order.
Updating a tuple and adding an element at the end commute.
Adding an element at the beginning of a tuple and then updating it amounts to adding it directly.
Updating an element and taking the beginning commute.
tail
and init
commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use.
cons
and snoc
commute. We state this lemma in a non-dependent setting, as otherwise it
would involve a cast to convince Lean that the two types are equal, making it harder to use.
Insert an element into a tuple at a given position. For i = 0
see fin.cons
,
for i = fin.last n
see fin.snoc
.
Equations
- i.insert_nth x p j = i.insert_nth' x p j
- _x_2.insert_nth x _x_3 _x_1 = cast _ x
find p
returns the first index n
where p n
is satisfied, and none
if it is never
satisfied.
If find p = some i
, then p i
holds
find p
does not return none
if and only if p i
holds at some index i
.