452 lines
13 KiB
Text
452 lines
13 KiB
Text
/-
|
||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Author: Leonardo de Moura
|
||
|
||
Type class for encodable types.
|
||
Note that every encodable type is countable.
|
||
-/
|
||
import data.fintype data.list data.list.sort data.sum data.nat.div data.subtype data.countable data.equiv data.finset
|
||
open option list nat function
|
||
|
||
structure encodable [class] (A : Type) :=
|
||
(encode : A → nat) (decode : nat → option A) (encodek : ∀ a, decode (encode a) = some a)
|
||
|
||
open encodable
|
||
|
||
definition countable_of_encodable {A : Type} : encodable A → countable A :=
|
||
assume e : encodable A,
|
||
have injective encode, from
|
||
λ (a₁ a₂ : A) (h : encode a₁ = encode a₂),
|
||
assert decode A (encode a₁) = decode A (encode a₂), by rewrite h,
|
||
by rewrite [*encodek at this]; injection this; assumption,
|
||
exists.intro encode this
|
||
|
||
definition encodable_fintype [instance] {A : Type} [h₁ : fintype A] [h₂ : decidable_eq A] : encodable A :=
|
||
encodable.mk
|
||
(λ a, find a (elements_of A))
|
||
(λ n, nth (elements_of A) n)
|
||
(λ a, find_nth (fintype.complete a))
|
||
|
||
definition encodable_nat [instance] : encodable nat :=
|
||
encodable.mk (λ a, a) (λ n, some n) (λ a, rfl)
|
||
|
||
definition encodable_option [instance] {A : Type} [h : encodable A] : encodable (option A) :=
|
||
encodable.mk
|
||
(λ o, match o with
|
||
| some a := succ (encode a)
|
||
| none := 0
|
||
end)
|
||
(λ n, if n = 0 then some none else some (decode A (pred n)))
|
||
(λ o,
|
||
begin
|
||
cases o with a,
|
||
begin esimp end,
|
||
begin esimp, rewrite [if_neg !succ_ne_zero, encodable.encodek] end
|
||
end)
|
||
|
||
section sum
|
||
variables {A B : Type}
|
||
variables [h₁ : encodable A] [h₂ : encodable B]
|
||
include h₁ h₂
|
||
|
||
definition encode_sum : sum A B → nat
|
||
| (sum.inl a) := 2 * encode a
|
||
| (sum.inr b) := 2 * encode b + 1
|
||
|
||
definition decode_sum (n : nat) : option (sum A B) :=
|
||
if n mod 2 = 0 then
|
||
match decode A (n div 2) with
|
||
| some a := some (sum.inl a)
|
||
| none := none
|
||
end
|
||
else
|
||
match decode B ((n - 1) div 2) with
|
||
| some b := some (sum.inr b)
|
||
| none := none
|
||
end
|
||
|
||
open decidable
|
||
theorem decode_encode_sum : ∀ s : sum A B, decode_sum (encode_sum s) = some s
|
||
| (sum.inl a) :=
|
||
assert aux : 2 > 0, from dec_trivial,
|
||
begin
|
||
esimp [encode_sum, decode_sum],
|
||
rewrite [mul_mod_right, if_pos (eq.refl (0 : nat)), mul_div_cancel_left _ aux, encodable.encodek]
|
||
end
|
||
| (sum.inr b) :=
|
||
assert aux₁ : 2 > 0, from dec_trivial,
|
||
assert aux₂ : 1 mod 2 = 1, by rewrite [nat.modulo_def],
|
||
assert aux₃ : 1 ≠ 0, from dec_trivial,
|
||
begin
|
||
esimp [encode_sum, decode_sum],
|
||
rewrite [add.comm, add_mul_mod_self_left, aux₂, if_neg aux₃, add_sub_cancel_left,
|
||
mul_div_cancel_left _ aux₁, encodable.encodek]
|
||
end
|
||
|
||
definition encodable_sum [instance] : encodable (sum A B) :=
|
||
encodable.mk
|
||
(λ s, encode_sum s)
|
||
(λ n, decode_sum n)
|
||
(λ s, decode_encode_sum s)
|
||
end sum
|
||
|
||
section prod
|
||
variables {A B : Type}
|
||
variables [h₁ : encodable A] [h₂ : encodable B]
|
||
include h₁ h₂
|
||
|
||
definition encode_prod : A × B → nat
|
||
| (a, b) := mkpair (encode a) (encode b)
|
||
|
||
definition decode_prod (n : nat) : option (A × B) :=
|
||
match unpair n with
|
||
| (n₁, n₂) :=
|
||
match decode A n₁ with
|
||
| some a :=
|
||
match decode B n₂ with
|
||
| some b := some (a, b)
|
||
| none := none
|
||
end
|
||
| none := none
|
||
end
|
||
end
|
||
|
||
theorem decode_encode_prod : ∀ p : A × B, decode_prod (encode_prod p) = some p
|
||
| (a, b) :=
|
||
begin
|
||
esimp [encode_prod, decode_prod, prod.cases_on],
|
||
rewrite [unpair_mkpair],
|
||
esimp,
|
||
rewrite [*encodable.encodek]
|
||
end
|
||
|
||
definition encodable_product [instance] : encodable (A × B) :=
|
||
encodable.mk
|
||
encode_prod
|
||
decode_prod
|
||
decode_encode_prod
|
||
end prod
|
||
|
||
section list
|
||
variables {A : Type}
|
||
variables [h : encodable A]
|
||
include h
|
||
|
||
definition encode_list_core : list A → nat
|
||
| [] := 0
|
||
| (a::l) := mkpair (encode a) (encode_list_core l)
|
||
|
||
theorem encode_list_core_cons (a : A) (l : list A) : encode_list_core (a::l) = mkpair (encode a) (encode_list_core l) :=
|
||
rfl
|
||
|
||
definition encode_list (l : list A) : nat :=
|
||
mkpair (length l) (encode_list_core l)
|
||
|
||
definition decode_list_core : nat → nat → option (list A)
|
||
| 0 v := some []
|
||
| (succ n) v :=
|
||
match unpair v with
|
||
| (v₁, v₂) :=
|
||
match decode A v₁ with
|
||
| some a :=
|
||
match decode_list_core n v₂ with
|
||
| some l := some (a::l)
|
||
| none := none
|
||
end
|
||
| none := none
|
||
end
|
||
end
|
||
|
||
theorem decode_list_core_succ (n v : nat) :
|
||
decode_list_core (succ n) v =
|
||
match unpair v with
|
||
| (v₁, v₂) :=
|
||
match decode A v₁ with
|
||
| some a :=
|
||
match decode_list_core n v₂ with
|
||
| some l := some (a::l)
|
||
| none := none
|
||
end
|
||
| none := none
|
||
end
|
||
end
|
||
:= rfl
|
||
|
||
definition decode_list (n : nat) : option (list A) :=
|
||
match unpair n with
|
||
| (l, v) := decode_list_core l v
|
||
end
|
||
|
||
theorem decode_encode_list_core : ∀ l : list A, decode_list_core (length l) (encode_list_core l) = some l
|
||
| [] := rfl
|
||
| (a::l) :=
|
||
begin
|
||
rewrite [encode_list_core_cons, length_cons, add_one (length l), decode_list_core_succ],
|
||
rewrite [unpair_mkpair],
|
||
esimp [prod.cases_on],
|
||
rewrite [decode_encode_list_core l],
|
||
rewrite [encodable.encodek],
|
||
end
|
||
|
||
theorem decode_encode_list (l : list A) : decode_list (encode_list l) = some l :=
|
||
begin
|
||
esimp [encode_list, decode_list],
|
||
rewrite [unpair_mkpair],
|
||
esimp [prod.cases_on],
|
||
apply decode_encode_list_core
|
||
end
|
||
|
||
definition encodable_list [instance] : encodable (list A) :=
|
||
encodable.mk
|
||
encode_list
|
||
decode_list
|
||
decode_encode_list
|
||
end list
|
||
|
||
section finset
|
||
variable {A : Type}
|
||
variable [encA : encodable A]
|
||
include encA
|
||
|
||
private definition enle (a b : A) : Prop := encode a ≤ encode b
|
||
|
||
private lemma enle.refl (a : A) : enle a a :=
|
||
!le.refl
|
||
|
||
private lemma enle.trans (a b c : A) : enle a b → enle b c → enle a c :=
|
||
assume h₁ h₂, le.trans h₁ h₂
|
||
|
||
private lemma enle.total (a b : A) : enle a b ∨ enle b a :=
|
||
le.total
|
||
|
||
private lemma enle.antisymm (a b : A) : enle a b → enle b a → a = b :=
|
||
assume h₁ h₂,
|
||
assert encode a = encode b, from le.antisymm h₁ h₂,
|
||
assert decode A (encode a) = decode A (encode b), by rewrite this,
|
||
assert some a = some b, by rewrite [*encodek at this]; exact this,
|
||
option.no_confusion this (λ e, e)
|
||
|
||
private definition decidable_enle [instance] (a b : A) : decidable (enle a b) :=
|
||
decidable_le (encode a) (encode b)
|
||
|
||
variables [decA : decidable_eq A]
|
||
include decA
|
||
|
||
private definition ensort (l : list A) : list A :=
|
||
sort enle l
|
||
|
||
open subtype perm
|
||
private lemma sorted_eq_of_perm {l₁ l₂ : list A} (h : l₁ ~ l₂) : ensort l₁ = ensort l₂ :=
|
||
list.sort_eq_of_perm_core enle.total enle.trans enle.refl enle.antisymm h
|
||
|
||
definition encode_finset (s : finset A) : nat :=
|
||
quot.lift_on s
|
||
(λ l, encode (ensort (elt_of l)))
|
||
(λ l₁ l₂ p,
|
||
have elt_of l₁ ~ elt_of l₂, from p,
|
||
assert ensort (elt_of l₁) = ensort (elt_of l₂), from sorted_eq_of_perm this,
|
||
by rewrite this)
|
||
|
||
definition decode_finset (n : nat) : option (finset A) :=
|
||
match decode (list A) n with
|
||
| some l₁ := some (finset.to_finset l₁)
|
||
| none := none
|
||
end
|
||
|
||
theorem decode_encode_finset (s : finset A) : decode_finset (encode_finset s) = some s :=
|
||
quot.induction_on s (λ l,
|
||
begin
|
||
unfold encode_finset, unfold decode_finset, rewrite encodek, esimp, congruence,
|
||
apply quot.sound, cases l with l nd,
|
||
show erase_dup (ensort l) ~ l, from
|
||
have nodup (ensort l), from nodup_of_perm_of_nodup (perm.symm !sort_perm) nd,
|
||
calc erase_dup (ensort l) = ensort l : erase_dup_eq_of_nodup this
|
||
... ~ l : sort_perm
|
||
end)
|
||
|
||
definition encodable_finset [instance] : encodable (finset A) :=
|
||
encodable.mk
|
||
encode_finset
|
||
decode_finset
|
||
decode_encode_finset
|
||
end finset
|
||
|
||
section subtype
|
||
open subtype decidable
|
||
variable {A : Type}
|
||
variable {P : A → Prop}
|
||
variable [encA : encodable A]
|
||
variable [decP : decidable_pred P]
|
||
|
||
include encA
|
||
definition encode_subtype : {a : A | P a} → nat
|
||
| (tag v h) := encode v
|
||
|
||
include decP
|
||
definition decode_subtype (v : nat) : option {a : A | P a} :=
|
||
match decode A v with
|
||
| some a := if h : P a then some (tag a h) else none
|
||
| none := none
|
||
end
|
||
|
||
lemma decode_encode_subtype : ∀ s : {a : A | P a}, decode_subtype (encode_subtype s) = some s
|
||
| (tag v h) :=
|
||
begin
|
||
unfold [encode_subtype, decode_subtype], rewrite encodek, esimp,
|
||
rewrite [dif_pos h]
|
||
end
|
||
|
||
definition encodable_subtype [instance] : encodable {a : A | P a} :=
|
||
encodable.mk
|
||
encode_subtype
|
||
decode_subtype
|
||
decode_encode_subtype
|
||
end subtype
|
||
|
||
definition encodable_of_left_injection
|
||
{A B : Type} [h₁ : encodable A]
|
||
(f : B → A) (finv : A → option B) (linv : ∀ b, finv (f b) = some b) : encodable B :=
|
||
encodable.mk
|
||
(λ b, encode (f b))
|
||
(λ n,
|
||
match decode A n with
|
||
| some a := finv a
|
||
| none := none
|
||
end)
|
||
(λ b,
|
||
begin
|
||
esimp,
|
||
rewrite [encodable.encodek],
|
||
esimp [option.cases_on],
|
||
rewrite [linv]
|
||
end)
|
||
|
||
section
|
||
open equiv
|
||
|
||
definition encodable_of_equiv {A B : Type} [h : encodable A] : A ≃ B → encodable B
|
||
| (mk f g l r) :=
|
||
encodable_of_left_injection g (λ a, some (f a))
|
||
(λ b, by rewrite r; reflexivity)
|
||
end
|
||
|
||
/-
|
||
Choice function for encodable types and decidable predicates.
|
||
We provide the following API
|
||
|
||
choose {A : Type} {p : A → Prop} [c : encodable A] [d : decidable_pred p] : (∃ x, p x) → A :=
|
||
choose_spec {A : Type} {p : A → Prop} [c : encodable A] [d : decidable_pred p] (ex : ∃ x, p x) : p (choose ex) :=
|
||
-/
|
||
section find_a
|
||
parameters {A : Type} {p : A → Prop} [c : encodable A] [d : decidable_pred p]
|
||
include c
|
||
include d
|
||
|
||
private definition pn (n : nat) : Prop :=
|
||
match decode A n with
|
||
| some a := p a
|
||
| none := false
|
||
end
|
||
|
||
private definition decidable_pn : decidable_pred pn :=
|
||
λ n,
|
||
match decode A n with
|
||
| some a := λ e : decode A n = some a,
|
||
match d a with
|
||
| decidable.inl t :=
|
||
begin
|
||
unfold pn, rewrite e, esimp [option.cases_on],
|
||
exact (decidable.inl t)
|
||
end
|
||
| decidable.inr f :=
|
||
begin
|
||
unfold pn, rewrite e, esimp [option.cases_on],
|
||
exact (decidable.inr f)
|
||
end
|
||
end
|
||
| none := λ e : decode A n = none,
|
||
begin
|
||
unfold pn, rewrite e, esimp [option.cases_on],
|
||
exact decidable_false
|
||
end
|
||
end (eq.refl (decode A n))
|
||
|
||
private definition ex_pn_of_ex : (∃ x, p x) → (∃ x, pn x) :=
|
||
assume ex,
|
||
obtain (w : A) (pw : p w), from ex,
|
||
exists.intro (encode w)
|
||
begin
|
||
unfold pn, rewrite [encodek], esimp, exact pw
|
||
end
|
||
|
||
private lemma decode_ne_none_of_pn {n : nat} : pn n → decode A n ≠ none :=
|
||
assume pnn e,
|
||
begin
|
||
rewrite [▸ (match decode A n with | some a := p a | none := false end) at pnn],
|
||
rewrite [e at pnn], esimp [option.cases_on] at pnn,
|
||
exact (false.elim pnn)
|
||
end
|
||
|
||
open subtype
|
||
|
||
private definition of_nat (n : nat) : pn n → { a : A | p a } :=
|
||
match decode A n with
|
||
| some a := λ (e : decode A n = some a),
|
||
begin
|
||
unfold pn, rewrite e, esimp [option.cases_on], intro pa,
|
||
exact (tag a pa)
|
||
end
|
||
| none := λ (e : decode A n = none) h, absurd e (decode_ne_none_of_pn h)
|
||
end (eq.refl (decode A n))
|
||
|
||
private definition find_a : (∃ x, p x) → {a : A | p a} :=
|
||
suppose ∃ x, p x,
|
||
have ∃ x, pn x, from ex_pn_of_ex this,
|
||
let r := @nat.find _ decidable_pn this in
|
||
have pn r, from @nat.find_spec pn decidable_pn this,
|
||
of_nat r this
|
||
end find_a
|
||
|
||
namespace encodable
|
||
open subtype
|
||
|
||
definition choose {A : Type} {p : A → Prop} [c : encodable A] [d : decidable_pred p] : (∃ x, p x) → A :=
|
||
assume ex, elt_of (find_a ex)
|
||
|
||
theorem choose_spec {A : Type} {p : A → Prop} [c : encodable A] [d : decidable_pred p] (ex : ∃ x, p x) : p (choose ex) :=
|
||
has_property (find_a ex)
|
||
|
||
theorem axiom_of_choice {A : Type} {B : A → Type} {R : Π x, B x → Prop} [c : Π a, encodable (B a)] [d : ∀ x y, decidable (R x y)]
|
||
: (∀x, ∃y, R x y) → ∃f, ∀x, R x (f x) :=
|
||
assume H,
|
||
have ∀x, R x (choose (H x)), from take x, choose_spec (H x),
|
||
exists.intro _ this
|
||
|
||
theorem skolem {A : Type} {B : A → Type} {P : Π x, B x → Prop} [c : Π a, encodable (B a)] [d : ∀ x y, decidable (P x y)]
|
||
: (∀x, ∃y, P x y) ↔ ∃f, (∀x, P x (f x)) :=
|
||
iff.intro
|
||
(suppose (∀ x, ∃y, P x y), axiom_of_choice this)
|
||
(suppose (∃ f, (∀x, P x (f x))),
|
||
take x, obtain (fw : ∀x, B x) (Hw : ∀x, P x (fw x)), from this,
|
||
exists.intro (fw x) (Hw x))
|
||
end encodable
|
||
|
||
namespace quot
|
||
section
|
||
open setoid encodable
|
||
parameter {A : Type}
|
||
parameter {s : setoid A}
|
||
parameter [decR : ∀ a b : A, decidable (a ≈ b)]
|
||
parameter [encA : encodable A]
|
||
include decR
|
||
include encA
|
||
|
||
-- Choose equivalence class representative
|
||
definition rep (q : quot s) : A :=
|
||
choose (exists_rep q)
|
||
|
||
theorem rep_spec (q : quot s) : ⟦rep q⟧ = q :=
|
||
choose_spec (exists_rep q)
|
||
end
|
||
end quot
|