feat(library/data/fintype): add finite function related theories

develop kth related techniques, all_lists_of_len, all_funs, map between lists and functions, finite inverse and cardinality
remove function module from default import list for now
This commit is contained in:
Haitao Zhang 2015-06-08 10:19:14 -07:00 committed by Leonardo de Moura
parent 35eae96aa5
commit 6949e2d422
2 changed files with 366 additions and 8 deletions

View file

@ -5,4 +5,4 @@ Authors: Leonardo de Moura
Finite type (type class).
-/
import .basic .function .card
import .basic .card

View file

@ -1,7 +1,365 @@
/-
Copyright (c) 2015 Haitao Zhang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Haitao Zhang
Finite type (type class).
-/
/-
Copyright (c) 2015 Haitao Zhang. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author : Haitao Zhang
-/
import data
open nat function eq.ops
namespace list
-- this is in preparation for counting the number of finite functions
section list_of_lists
open prod
variable {A : Type}
definition cons_pair (pr : A × list A) := (pr1 pr) :: (pr2 pr)
definition cons_all_of (elts : list A) (ls : list (list A)) : list (list A) :=
map cons_pair (product elts ls)
lemma pair_of_cons {a} {l} {pr : A × list A} : cons_pair pr = a::l → pr = (a, l) :=
prod.destruct pr (λ p1 p2, assume Peq, list.no_confusion Peq (by intros; substvars))
lemma cons_pair_inj : injective (@cons_pair A) :=
take p1 p2, assume Pl,
prod.eq (list.no_confusion Pl (λ P1 P2, P1)) (list.no_confusion Pl (λ P1 P2, P2))
lemma nodup_of_cons_all {elts : list A} {ls : list (list A)}
: nodup elts → nodup ls → nodup (cons_all_of elts ls) :=
assume Pelts Pls,
nodup_map cons_pair_inj (nodup_product Pelts Pls)
lemma length_cons_all {elts : list A} {ls : list (list A)} :
length (cons_all_of elts ls) = length elts * length ls := calc
length (cons_all_of elts ls) = length (product elts ls) : length_map
... = length elts * length ls : length_product
variable [finA : fintype A]
include finA
definition all_lists_of_len : ∀ (n : nat), list (list A)
| 0 := [[]]
| (succ n) := cons_all_of (elements_of A) (all_lists_of_len n)
lemma nodup_all_lists : ∀ (n : nat), nodup (@all_lists_of_len A _ n)
| 0 := nodup_singleton []
| (succ n) := nodup_of_cons_all (fintype.unique A) (nodup_all_lists n)
lemma mem_all_lists : ∀ (n : nat) (l : list A), length l = n → l ∈ all_lists_of_len n
| 0 [] := assume P, mem_cons [] []
| 0 (a::l) := assume Peq, by contradiction
| (succ n) [] := assume Peq, by contradiction
| (succ n) (a::l) := assume Peq, begin
apply mem_map, apply mem_product,
exact fintype.complete a,
exact mem_all_lists n l (succ_inj Peq)
end
lemma leq_of_mem_all_lists : ∀ {n : nat} ⦃l : list A⦄,
l ∈ all_lists_of_len n → length l = n
| 0 [] := assume P, rfl
| 0 (a::l) := assume Pin, assert Peq : (a::l) = [], from mem_singleton Pin,
by contradiction
| (succ n) [] := assume Pin, obtain pr Pprin Ppr, from exists_of_mem_map Pin,
by contradiction
| (succ n) (a::l) := assume Pin, obtain pr Pprin Ppr, from exists_of_mem_map Pin,
assert Pl : l ∈ all_lists_of_len n,
from mem_of_mem_product_right ((pair_of_cons Ppr) ▸ Pprin),
by rewrite [length_cons, leq_of_mem_all_lists Pl]
open fintype
lemma length_all_lists : ∀ {n : nat}, length (@all_lists_of_len A _ n) = (card A) ^ n
| 0 := calc length [[]] = 1 : length_cons
| (succ n) := calc length _ = card A * length (all_lists_of_len n) : length_cons_all
... = card A * (card A ^ n) : length_all_lists
... = (card A ^ n) * card A : nat.mul.comm
... = (card A) ^ (succ n) : pow_succ
end list_of_lists
section kth
variable {A : Type}
definition kth : ∀ k (l : list A), k < length l → A
| k [] := begin rewrite length_nil, intro Pltz, exact absurd Pltz !not_lt_zero end
| 0 (a::l) := λ P, a
| (k+1) (a::l):= by rewrite length_cons; intro Plt; exact kth k l (lt_of_succ_lt_succ Plt)
lemma kth_zero_of_cons {a} (l : list A) (P : 0 < length (a::l)) : kth 0 (a::l) P = a :=
rfl
lemma kth_succ_of_cons {a} k (l : list A) (P : k+1 < length (a::l)) :
kth (succ k) (a::l) P = kth k l (lt_of_succ_lt_succ P) :=
rfl
lemma kth_mem : ∀ {k : nat} {l : list A} P, kth k l P ∈ l
| k [] := assume P, absurd P !not_lt_zero
| 0 (a::l) := assume P, by rewrite kth_zero_of_cons; apply mem_cons
| (succ k) (a::l) := assume P, by
rewrite [kth_succ_of_cons]; apply mem_cons_of_mem a; apply kth_mem
-- Leo provided the following proof.
lemma eq_of_kth_eq [deceqA : decidable_eq A]
: ∀ {l1 l2 : list A} (Pleq : length l1 = length l2),
(∀ (k : nat) (Plt1 : k < length l1) (Plt2 : k < length l2), kth k l1 Plt1 = kth k l2 Plt2) → l1 = l2
| [] [] h₁ h₂ := rfl
| (a₁::l₁) [] h₁ h₂ := by contradiction
| [] (a₂::l₂) h₁ h₂ := by contradiction
| (a₁::l₁) (a₂::l₂) h₁ h₂ :=
have ih₁ : length l₁ = length l₂, by injection h₁; eassumption,
have ih₂ : ∀ (k : nat) (plt₁ : k < length l₁) (plt₂ : k < length l₂), kth k l₁ plt₁ = kth k l₂ plt₂,
begin
intro k plt₁ plt₂,
have splt₁ : succ k < length l₁ + 1, from succ_le_succ plt₁,
have splt₂ : succ k < length l₂ + 1, from succ_le_succ plt₂,
have keq : kth (succ k) (a₁::l₁) splt₁ = kth (succ k) (a₂::l₂) splt₂, from h₂ (succ k) splt₁ splt₂,
rewrite *kth_succ_of_cons at keq,
exact keq
end,
assert ih : l₁ = l₂, from eq_of_kth_eq ih₁ ih₂,
assert k₁ : a₁ = a₂,
begin
have lt₁ : 0 < length (a₁::l₁), from !zero_lt_succ,
have lt₂ : 0 < length (a₂::l₂), from !zero_lt_succ,
have e₁ : kth 0 (a₁::l₁) lt₁ = kth 0 (a₂::l₂) lt₂, from h₂ 0 lt₁ lt₂,
rewrite *kth_zero_of_cons at e₁,
assumption
end,
by subst l₁; subst a₁
lemma kth_of_map {B : Type} {f : A → B} :
∀ {k : nat} {l : list A} Plt Pmlt, kth k (map f l) Pmlt = f (kth k l Plt)
| k [] := assume P, absurd P !not_lt_zero
| 0 (a::l) := assume Plt, by
rewrite [map_cons]; intro Pmlt; rewrite [kth_zero_of_cons]
| (succ k) (a::l) := assume P, begin
rewrite [map_cons], intro Pmlt, rewrite [*kth_succ_of_cons],
apply kth_of_map
end
lemma kth_find [deceqA : decidable_eq A] :
∀ {l : list A} {a} P, kth (find a l) l P = a
| [] := take a, assume P, absurd P !not_lt_zero
| (x::l) := take a, begin
assert Pd : decidable (a = x), {apply deceqA},
cases Pd with Pe Pne,
rewrite [find_cons_of_eq l Pe], intro P, rewrite [kth_zero_of_cons, Pe],
rewrite [find_cons_of_ne l Pne], intro P, rewrite [kth_succ_of_cons],
apply kth_find
end
lemma find_kth [deceqA : decidable_eq A] :
∀ {k : nat} {l : list A} P, find (kth k l P) l < length l
| k [] := assume P, absurd P !not_lt_zero
| 0 (a::l) := assume P, begin
rewrite [kth_zero_of_cons, find_cons_of_eq l rfl, length_cons],
exact !zero_lt_succ
end
| (succ k) (a::l) := assume P, begin
rewrite [kth_succ_of_cons],
assert Pd : decidable ((kth k l (lt_of_succ_lt_succ P)) = a),
{apply deceqA},
cases Pd with Pe Pne,
rewrite [find_cons_of_eq l Pe], apply zero_lt_succ,
rewrite [find_cons_of_ne l Pne], apply succ_lt_succ, apply find_kth
end
lemma find_kth_of_nodup [deceqA : decidable_eq A] :
∀ {k : nat} {l : list A} P, nodup l → find (kth k l P) l = k
| k [] := assume P, absurd P !not_lt_zero
| 0 (a::l) := assume Plt Pnodup,
by rewrite [kth_zero_of_cons, find_cons_of_eq l rfl]
| (succ k) (a::l) := assume Plt Pnodup, begin
rewrite [kth_succ_of_cons],
assert Pd : decidable ((kth k l (lt_of_succ_lt_succ Plt)) = a),
{apply deceqA},
cases Pd with Pe Pne,
assert Pin : a ∈ l, {rewrite -Pe, apply kth_mem},
exact absurd Pin (not_mem_of_nodup_cons Pnodup),
rewrite [find_cons_of_ne l Pne], apply congr (eq.refl succ),
apply find_kth_of_nodup (lt_of_succ_lt_succ Plt) (nodup_of_nodup_cons Pnodup)
end
end kth
end list
namespace fintype
open list
section found
variables {A B : Type}
variable [finA : fintype A]
include finA
lemma find_in_range [deceqB : decidable_eq B] {f : A → B} (b : B) :
∀ (l : list A) (P : find b (map f l) < length l), f (kth (find b (map f l)) l P) = b
| [] := assume P, begin exact absurd P !not_lt_zero end
| (a::l) := decidable.rec_on (deceqB b (f a))
(assume Peq, begin
rewrite [map_cons f a l, find_cons_of_eq _ Peq],
intro P, rewrite [kth_zero_of_cons], exact (Peq⁻¹)
end)
(assume Pne, begin
rewrite [map_cons f a l, find_cons_of_ne _ Pne],
intro P,
rewrite [kth_succ_of_cons (find b (map f l)) l P],
exact find_in_range l (lt_of_succ_lt_succ P)
end)
end found
section list_to_fun
variables {A B : Type}
variable [finA : fintype A]
include finA
definition fun_to_list (f : A → B) : list B := map f (elems A)
lemma length_map_of_fintype (f : A → B) : length (map f (elems A)) = card A :=
by apply length_map
variable [deceqA : decidable_eq A]
include deceqA
lemma fintype_find (a : A) : find a (elems A) < card A :=
find_lt_length (complete a)
definition list_to_fun (l : list B) (leq : length l = card A) : A → B :=
take x,
kth _ _ (leq⁻¹ ▸ fintype_find x)
definition all_funs [finB : fintype B] : list (A → B) :=
dmap (λ l, length l = card A) list_to_fun (all_lists_of_len (card A))
lemma list_to_fun_apply (l : list B) (leq : length l = card A) (a : A) :
∀ P, list_to_fun l leq a = kth (find a (elems A)) l P :=
assume P, rfl
variable [deceqB : decidable_eq B]
include deceqB
lemma fun_eq_list_to_fun_map (f : A → B) : ∀ P, f = list_to_fun (map f (elems A)) P :=
assume Pleq, funext (take a,
assert Plt : _, from Pleq⁻¹ ▸ find_lt_length (complete a), begin
rewrite [list_to_fun_apply _ Pleq a (Pleq⁻¹ ▸ find_lt_length (complete a))],
assert Pmlt : find a (elems A) < length (map f (elems A)),
{rewrite length_map, exact Plt},
rewrite [@kth_of_map A B f (find a (elems A)) (elems A) Plt _, kth_find]
end)
lemma list_eq_map_list_to_fun (l : list B) (leq : length l = card A)
: l = map (list_to_fun l leq) (elems A) :=
begin
apply eq_of_kth_eq, rewrite length_map, apply leq,
intro k Plt Plt2,
assert Plt1 : k < length (elems A), {apply leq ▸ Plt},
assert Plt3 : find (kth k (elems A) Plt1) (elems A) < length l,
{rewrite leq, apply find_kth},
rewrite [kth_of_map Plt1 Plt2, list_to_fun_apply l leq _ Plt3],
generalize Plt3,
rewrite [find_kth_of_nodup Plt1 (unique A)],
intro Plt, exact rfl
end
lemma fun_to_list_to_fun (f : A → B) : ∀ P, list_to_fun (fun_to_list f) P = f :=
assume P, (fun_eq_list_to_fun_map f P)⁻¹
lemma list_to_fun_to_list (l : list B) (leq : length l = card A) :
fun_to_list (list_to_fun l leq) = l
:= (list_eq_map_list_to_fun l leq)⁻¹
lemma dinj_list_to_fun : dinj (λ (l : list B), length l = card A) list_to_fun :=
take l1 l2 Pl1 Pl2 Peq,
by rewrite [list_eq_map_list_to_fun l1 Pl1, list_eq_map_list_to_fun l2 Pl2, Peq]
variable [finB : fintype B]
include finB
lemma nodup_all_funs : nodup (@all_funs A B _ _ _) :=
dmap_nodup_of_dinj dinj_list_to_fun (nodup_all_lists _)
lemma all_funs_complete (f : A → B) : f ∈ all_funs :=
assert Plin : map f (elems A) ∈ all_lists_of_len (card A),
from mem_all_lists (card A) _ (by rewrite length_map),
assert Plfin : list_to_fun (map f (elems A)) (length_map_of_fintype f) ∈ all_funs,
from mem_of_dmap _ Plin,
begin rewrite [fun_eq_list_to_fun_map f (length_map_of_fintype f)], apply Plfin end
lemma all_funs_to_all_lists : map fun_to_list (@all_funs A B _ _ _) = all_lists_of_len (card A) :=
map_of_dmap_inv_pos list_to_fun_to_list leq_of_mem_all_lists
lemma length_all_funs : length (@all_funs A B _ _ _) = (card B) ^ (card A) := calc
length _ = length (map fun_to_list all_funs) : length_map
... = length (all_lists_of_len (card A)) : all_funs_to_all_lists
... = (card B) ^ (card A) : length_all_lists
definition fun_is_fintype [instance] : fintype (A → B) :=
fintype.mk all_funs nodup_all_funs all_funs_complete
lemma card_funs : card (A → B) = (card B) ^ (card A) := length_all_funs
end list_to_fun
section surj_inv
variables {A B : Type}
variable [finA : fintype A]
include finA
-- surj from fintype domain implies fintype range
lemma mem_map_of_surj {f : A → B} (surj : surjective f) : ∀ b, b ∈ map f (elems A) :=
take b, obtain a Peq, from surj b,
Peq ▸ mem_map f (complete a)
variable [deceqB : decidable_eq B]
include deceqB
lemma found_of_surj {f : A → B} (surj : surjective f) :
∀ b, let elts := elems A, k := find b (map f elts) in k < length elts :=
λ b, let elts := elems A, img := map f elts, k := find b img in
have Pin : b ∈ img, from mem_map_of_surj surj b,
assert Pfound : k < length img, from find_lt_length (mem_map_of_surj surj b),
length_map f elts ▸ Pfound
definition right_inv {f : A → B} (surj : surjective f) : B → A :=
λ b, let elts := elems A, k := find b (map f elts) in
kth k elts (found_of_surj surj b)
lemma id_of_right_inv {f : A → B} (surj : surjective f) : f ∘ (right_inv surj) = id :=
funext (λ b, find_in_range b (elems A) (found_of_surj surj b))
end surj_inv
-- inj functions for equal card types are also surj and therefore bij
-- the right inv (since it is surj) is also the left inv
section inj
variables {A B : Type}
variable [finA : fintype A]
include finA
variable [deceqA : decidable_eq A]
include deceqA
variable [finB : fintype B]
include finB
variable [deceqB : decidable_eq B]
include deceqB
open finset
lemma surj_of_inj_eq_card : card A = card B → ∀ {f : A → B}, injective f → surjective f :=
assume Peqcard, take f, assume Pinj,
decidable.rec_on decidable_forall_finite
(assume P : surjective f, P)
(assume Pnsurj : ¬surjective f, obtain b Pne, from exists_not_of_not_forall Pnsurj,
assert Pall : ∀ a, f a ≠ b, from forall_not_of_not_exists Pne,
assert Pbnin : b ∉ image f univ, from λ Pin,
obtain a Pa, from exists_of_mem_image Pin, absurd (and.right Pa) (Pall a),
assert Puniv : finset.card (image f univ) = card A,
from card_eq_card_image_of_inj Pinj,
assert Punivb : finset.card (image f univ) = card B, from eq.trans Puniv Peqcard,
assert P : image f univ = univ, from univ_of_card_eq_univ Punivb,
absurd (P⁻¹▸ mem_univ b) Pbnin)
end inj
end fintype