H2z: Izomorfizmy typów [TODO]
Require Import Equality.
Require Import FunctionalExtensionality.
From Typonomikon Require Import BC2e BC2f.
#[refine, export]
Instance iso_pi_fun
{A B2 : Type} {B1 : A -> Type}
(i : forall x : A, iso (B1 x) B2)
: iso (forall x : A, B1 x) (A -> B2) :=
{
coel f := fun a => coel (i a) (f a);
coer f := fun a => coer (i a) (f a);
}.
Proof.
- intros f.
extensionality a.
now rewrite coel_coer.
- intros f.
extensionality a.
now rewrite coer_coel.
Defined.
#[refine, export]
Instance iso_sigT_prod
{A B2 : Type} {B1 : A -> Type}
(i : forall x : A, iso (B1 x) B2)
: iso {x : A & B1 x} (A * B2) :=
{
coel '(existT _ a b1) := (a, coel (i a) b1);
coer '(a, b2) := existT _ a (coer (i a) b2);
}.
Proof.
- intros [a b1].
now rewrite coel_coer.
- intros [a b2].
now rewrite coer_coel.
Defined.
Izomorfizmy charakterystyczne typów induktywnych (TODO)
Liczby naturalne
Definition pred (n : nat) : option nat :=
match n with
| 0 => None
| S n' => Some n'
end.
Definition unpred (on : option nat) : nat :=
match on with
| None => 0
| Some n => S n
end.
#[refine]
#[export]
Instance iso_nat_option_nat : iso nat (option nat) :=
{
coel n := match n with | 0 => None | S n' => Some n' end;
coer o := match o with | None => 0 | Some n => S n end;
}.
Proof.
- now intros [].
- now intros [].
Defined.
Definition uncons {A : Type} (l : list A) : option (A * list A) :=
match l with
| [] => None
| h :: t => Some (h, t)
end.
Definition ununcons {A : Type} (x : option (A * list A)) : list A :=
match x with
| None => []
| Some (h, t) => h :: t
end.
#[refine]
#[export]
Instance list_char (A : Type) : iso (list A) (option (A * list A)) :=
{
coel l :=
match l with
| [] => None
| h :: t => Some (h, t)
end;
coer o :=
match o with
| None => []
| Some (h, t) => h :: t
end;
}.
Proof.
- now intros [].
- now intros [[] |].
Defined.
From Typonomikon Require Import F2.
Jak można się domyślić po przykładach, charakterystyczne izomorfizmy
dla prostych typów induktywnych są łatwe. A co z innowacyjniejszymi
rodzajami definicji induktywnych oraz z definicjami koinduktywnymi?
Sprawdźmy to!
Axiom sim_eq :
forall (A : Type) (x y : Stream A), sim x y -> x = y.
#[refine]
#[export]
Instance Stream_char (A : Type) : iso (Stream A) (A * Stream A) :=
{
coel s := (hd s, tl s);
coer '(a, s) := {| hd := a; tl := s |}
}.
Proof.
- intro s.
apply sim_eq.
now constructor; cbn.
- now intros [a s]; cbn.
Defined.
Charakteryzacje "kontenerowe" (TODO)
Stream unit ~ unit
Require Import FinFun ZArith.
CoFixpoint theChosenOne : Stream unit :=
{|
hd := tt;
tl := theChosenOne;
|}.
Lemma all_chosen_unit_aux :
forall s : Stream unit,
sim s theChosenOne.
Lemma all_chosen_unit :
forall x y : Stream unit,
sim x y.
Lemma all_eq :
forall x y : Stream unit,
x = y.
Definition unit_to_stream (u : unit) : Stream unit := theChosenOne.
Definition stream_to_unit (s : Stream unit) : unit := tt.
Lemma unit_is_Stream_unit :
Bijective unit_to_stream.
Definition index {A : Type} (s : Stream A) : nat -> A :=
fun n => F2.nth n s.
CoFixpoint memoize {A : Type} (f : nat -> A) : Stream A :=
{|
hd := f 0;
tl := memoize (fun n => f (S n));
|}.
Lemma index_memoize :
forall {A : Type} (f : nat -> A) (n : nat),
index (memoize f) n = f n.
Proof.
intros A f n; revert f.
induction n as [| n']; cbn; intros; [easy |].
change (F2.nth n' _) with (index (memoize (fun n => f (S n))) n').
now rewrite IHn'.
Qed.
Lemma memoize_index :
forall {A : Type} (s : Stream A),
sim (memoize (index s)) s.
Proof.
cofix CH.
constructor; cbn; [easy |].
now apply CH.
Qed.
Charakteryzacje "wektorowe" (TODO)
list A ~ {n : nat & vec A n}
Set Warnings "-notation-overridden".
From Typonomikon Require Import E1.
Set Warnings "notation-overridden".
Definition vlist (A : Type) : Type :=
{n : nat & vec A n}.
Fixpoint vectorize' {A : Type} (l : list A) : vec A (length l) :=
match l with
| nil => vnil
| cons h t => vcons h (vectorize' t)
end.
Definition vectorize {A : Type} (l : list A) : vlist A :=
existT _ (length l) (vectorize' l).
Fixpoint toList {A : Type} {n : nat} (v : vec A n) : list A :=
match v with
| vnil => nil
| vcons h t => cons h (toList t)
end.
Definition listize {A : Type} (v : vlist A) : list A :=
toList (projT2 v).
Lemma eq_head_tail :
forall {A : Type} {n : nat} (v1 v2 : vec A (S n)),
head v1 = head v2 -> tail v1 = tail v2 -> v1 = v2.
Proof.
intros A n v1 v2.
dependent destruction v1; dependent destruction v2; cbn.
now intros -> ->.
Qed.
From Typonomikon Require Import BC3b.
Lemma transport_cons :
forall {A : Type} {n m : nat} (h : A) (t : vec A n) (p : n = m),
transport (fun n : nat => vec A (S n)) p
(h :: t) = h :: transport (fun n : nat => vec A n) p t.
Proof.
now destruct p; cbn.
Qed.
#[refine]
#[export]
Instance iso_list_vlist (A : Type) : iso (list A) (vlist A) :=
{
coel := vectorize;
coer := listize;
}.
Proof.
- induction a as [| h t]; cbn in *; [easy |].
now rewrite IHt.
- intros [n v].
unfold vectorize; cbn.
induction v as [| h t]; cbn; [easy |].
apply sigT_eq' in IHv; cbn in IHv.
destruct IHv as [p e].
unshelve eapply sigT_eq.
+ exact (ap S p).
+ now rewrite transport_ap, transport_cons, e.
Defined.
Ciekawsze izomorfizmy
nat ~ nat + nat
Jak trudno jest zrobić ciekawsze izomorfizmy?
Function div2 (n : nat) : nat + nat :=
match n with
| 0 => inl 0
| 1 => inr 0
| S (S n') =>
match div2 n' with
| inl m => inl (S m)
| inr m => inr (S m)
end
end.
Definition undiv2 (x : nat + nat) : nat :=
match x with
| inl n => 2 * n
| inr n => S (2 * n)
end.
#[refine]
#[export]
Instance iso_nat_sum_nat_nat : iso nat (nat + nat) :=
{
coel := div2;
coer := undiv2;
}.
Proof.
- intros a.
functional induction (div2 a); cbn; [easy.. | |].
+ rewrite e0 in IHs; cbn in IHs.
now rewrite <- plus_n_Sm, IHs.
+ rewrite e0 in IHs; cbn in IHs.
now rewrite <- plus_n_Sm, IHs.
- destruct b as [n | n].
+ cbn.
functional induction (div2 n); cbn; [easy.. | |].
* now rewrite <- 2!plus_n_Sm; cbn; rewrite IHs.
* now rewrite <- 2!plus_n_Sm; cbn; rewrite IHs.
+ induction n as [| n']; cbn in *; [easy |].
destruct n' as [| n'']; cbn in *; [easy |].
now rewrite <- plus_n_Sm, IHn'.
Defined.
Niezbyt trudno, ale łatwo też nie.
nat ~ nat * nat
goto
Function goto' (x y n : nat) : nat * nat :=
match n, x with
| 0 , _ => (x, y)
| S n', 0 => goto' (S y) 0 n'
| S n', S x' => goto' x' (S y) n'
end.
Definition goto (n : nat) : nat * nat :=
goto' 0 0 n.
Lemma goto'_add :
forall x y n m x' y': nat,
goto' x y n = (x', y') ->
goto' x y (n + m) = goto' x' y' m.
Proof.
intros x y n.
functional induction goto' x y n; cbn; intros.
- now inv H.
- now apply IHp.
- now apply IHp.
Qed.
Lemma goto'_small :
forall x y n : nat,
n <= x ->
goto' x y n = (x - n, y + n).
Proof.
intros x y n Hle.
functional induction goto' x y n; cbn; [now f_equal; lia | now lia |].
now rewrite IHp; [f_equal |]; lia.
Qed.
Lemma goto'_right :
forall x y : nat,
goto' x y (1 + x + y) = (S x, y).
Proof.
intros.
replace (1 + x + y) with (x + (1 + y)) by lia.
erewrite goto'_add; cycle 1.
- now apply goto'_small.
- rewrite Nat.sub_diag; cbn.
now rewrite goto'_small; [f_equal |]; lia.
Qed.
Lemma goto_add :
forall n m : nat,
goto (n + m) = goto' (fst (goto n)) (snd (goto n)) m.
Proof.
unfold goto.
intros n m.
erewrite goto'_add; [easy |].
now destruct (goto' 0 0 n).
Qed.
comefrom
Chcielibyśmy zdefiniować funkcję odwrotną do
goto' w ten sposób:
comefrom (0, 0) = 0
comefrom (S x, 0) = 1 + comefrom (0, x)
comefrom (x, S y) = 1 + comefrom (S x, y)
Niestety takie równania nie są strukturalnie rekurencyjne, więc definicja
nie jest akceptowana przez Coqa. Próba ratowania sytuacji za pomocą rekursji
dobrze ufundowanej też by się nie powiodła (wiem bo próbowałem).
Zamiast tego, użyjemy nieco przerobionej definicji, a potem spróbujemy pokazać,
że spełnia ona powyższe równania.
Fixpoint comefrom' (x y : nat) {struct x} : nat :=
match x with
| 0 =>
(fix aux (y : nat) : nat :=
match y with
| 0 => 0
| S y' => 1 + y + aux y'
end) y
| S x' => x + y + comefrom' x' y
end.
Definition comefrom (xy : nat * nat) : nat :=
comefrom' (fst xy) (snd xy).
Lemma comefrom'_eq_1 :
comefrom' 0 0 = 0.
Proof.
easy.
Qed.
Lemma comefrom'_eq_2 :
forall x : nat,
comefrom' (S x) 0 = 1 + comefrom' 0 x.
Proof.
now induction x as [| x']; cbn in *; lia.
Qed.
Lemma comefrom'_eq_3 :
forall x y : nat,
comefrom' x (S y) = 1 + comefrom' (S x) y.
Proof.
induction x as [| x'].
- intros []; cbn; lia.
- intros y.
specialize (IHx' y); cbn in *.
now lia.
Qed.
Lemma comefrom'_right :
forall x y : nat,
comefrom' (S x) y = 1 + x + y + comefrom' x y.
Proof.
induction x as [| x']; cbn; intros; [now lia |].
specialize (IHx' y).
now lia.
Qed.
Lemma comefrom'_up :
forall x y : nat,
comefrom' x (S y) = 2 + x + y + comefrom' x y.
Proof.
induction x as [| x']; cbn; intros; [now lia |].
specialize (IHx' y).
now lia.
Qed.
Lemma comefrom'_goto' :
forall x y n x' y' : nat,
goto' x y n = (x', y') ->
comefrom' x' y' = comefrom' x y + n.
Proof.
intros x y n.
functional induction goto' x y n; intros.
- now inv H; lia.
- now rewrite (IHp _ _ H), comefrom'_eq_2; lia.
- now rewrite (IHp _ _ H), comefrom'_eq_3; lia.
Qed.
Lemma comefrom_goto :
forall n : nat,
comefrom (goto n) = n.
Proof.
intros.
destruct (goto n) as [x y] eqn: Heq.
unfold comefrom; cbn.
rewrite (comefrom'_goto' 0 0 n x y); cbn; [easy |].
exact Heq.
Qed.
Lemma goto_comefrom :
forall xy : nat * nat,
goto (comefrom xy) = xy.
Proof.
intros [x y].
unfold comefrom, fst, snd.
revert y.
induction x as [| x'].
- induction y as [| y']; [easy |].
rewrite comefrom'_up, Nat.add_comm, goto_add, IHy'; cbn.
rewrite goto'_small; [| easy].
now f_equal; lia.
- intros y.
rewrite comefrom'_right, Nat.add_comm, goto_add, IHx'.
unfold fst, snd.
now apply goto'_right.
Qed.
#[refine]
#[export]
Instance iso_nat_prod_nat_nat : iso nat (nat * nat) :=
{
coel := goto;
coer := comefrom;
}.
Proof.
- now apply comefrom_goto.
- now apply goto_comefrom.
Defined.
nat ~ nat * nat, alternatywnie (TODO)
Definition komenvan (x : nat) (y : nat) : nat :=
let n := x + y in Nat.div2 (S n * n) + y.
nat ~ list nat
Jak trudno jest z podstawowych izomorfizmów dla produktów i sum
uskładać coś w stylu
nat ~ list nat? A może nie da się i trzeba
robić ręcznie?
Fixpoint nat_vec {n : nat} (arg : nat) : vec nat (S n) :=
match n with
| 0 => arg :: vnil
| S n' =>
let
(arg1, arg2) := goto arg
in
arg1 :: nat_vec arg2
end.
Fixpoint vec_nat {n : nat} (v : vec nat n) {struct v} : option nat :=
match v with
| vnil => None
| vcons h t =>
match vec_nat t with
| None => Some h
| Some r => Some (comefrom (h, r))
end
end.
#[refine]
#[export]
Instance vec_S (A : Type) (n : nat) : iso (vec A (S n)) (A * vec A n) :=
{
coel v := (head v, tail v);
coer '(h, t) := vcons h t;
}.
Proof.
- intros.
now refine (match a with vcons _ _ => _ end); cbn.
- now intros [a v]; cbn.
Defined.
#[export]
Instance iso_nat_vlist_S :
forall n : nat,
iso nat (vec nat (S n)).
Proof.
induction n as [| n'].
- split with (coel := fun n => vcons n vnil) (coer := head); [easy |].
intros b.
refine (match b with vcons _ _ => _ end).
destruct n; cbn; f_equal; [| easy].
now refine (match v with vnil => _ end).
- eapply iso_trans.
+ now apply iso_nat_prod_nat_nat.
+ eapply iso_trans; cycle 1.
* now apply iso_sym, vec_S.
* apply iso_pres_prod; [| easy].
now apply iso_refl.
Defined.
#[export]
Instance iso_vlist_option :
forall A : Type,
iso (vlist A) (option {n : nat & vec A (S n)}).
Proof.
unshelve esplit.
- intros [[| n] v].
+ exact None.
+ exact (Some (existT _ n v)).
- intros [[n v] |].
+ exact (existT _ (S n) v).
+ exact (existT _ 0 vnil).
- now intros [? []].
- now intros [[] |].
Defined.
#[export]
Instance iso_nat_list_nat :
iso nat (list nat).
Proof.
eapply iso_trans; [| now apply iso_sym, iso_list_vlist].
unfold vlist.
eapply iso_trans; [now apply iso_nat_option_nat |].
eapply iso_trans; [| now apply iso_sym, iso_vlist_option].
apply iso_pres_option.
eapply iso_trans; [now apply iso_nat_prod_nat_nat |].
apply iso_sym, iso_sigT_prod.
intros.
now apply iso_sym, iso_nat_vlist_S.
Defined.
... ale nat ~ list nat jest dość trudne.