Skip to content

Instantly share code, notes, and snippets.

@hacklex
Created January 8, 2023 21:04
Show Gist options
  • Select an option

  • Save hacklex/6d4dadac106b84d897fcb5ea699af77e to your computer and use it in GitHub Desktop.

Select an option

Save hacklex/6d4dadac106b84d897fcb5ea699af77e to your computer and use it in GitHub Desktop.
Non-computational setoids
module FStar.Algebra.Setoid
module TC = FStar.Tactics.Typeclasses
module F = FStar.FunctionalExtensionality
open FStar.Tactics
class equivalence_relation a = {
eq : a -> a -> bool;
reflexivity : (x:a -> Lemma (eq x x));
symmetry: (x:a -> y:a -> Lemma (x `eq` y <==> y `eq` x));
transitivity: (x:a -> y:a -> z:a -> Lemma (((eq x y) /\ (eq y z)) ==> eq x z));
}
type setoid t {| equivalence_relation t |} =
(f:F.restricted_g_t t (fun _ -> bool){
(exists z. f z == true /\ (forall p. f p == eq p z))
})
// ec stands for equivalence class.
let ec #a {| e:equivalence_relation a |} (x:a) : setoid a =
reflexivity x;
Classical.forall_intro_2 e.symmetry;
Classical.forall_intro_3 e.transitivity;
F.on_g a (fun t -> eq x t)
let get_x #t {| equivalence_relation t |} (sx: setoid t) : GTot(z:t{sx z == true}) =
IndefiniteDescription.indefinite_description_ghost t (fun p -> sx p == true)
let main_lemma #t {| z: equivalence_relation t |} (x y: t)
: Lemma (requires eq x y)
(ensures ec x == ec y) =
Classical.forall_intro_2 z.symmetry;
Classical.forall_intro_3 z.transitivity;
assert (forall p. ec x p == ec y p);
assert (F.feq_g (ec x) (ec y))
class has_mul t = {
[@@@TC.no_method] has_mul_has_eq : equivalence_relation t;
mul: t -> t -> t;
mul_congruence: (x:t) -> (y:t) -> (z:t) -> (w:t)
-> Lemma (requires eq x z /\ eq y w) (ensures eq (mul x y) (mul z w))
}
class has_mul_eq t = {
( * ) : t -> t -> t;
mul_eq_congruence: (x:t) -> (y:t) -> (z:t) -> (w:t)
-> Lemma (requires (x == z) /\ (y == w))
(ensures (x * y) == (z * w))
}
instance has_mul_has_eq t (hm: has_mul t) : equivalence_relation t = hm.has_mul_has_eq
class mul_semigroup t = {
[@@@TC.no_method] mul_semigroup_has_mul : has_mul t;
mul_associativity: (x:t) -> (y:t) -> (z:t) -> Lemma (eq (mul x (mul y z)) (mul (mul x y) z))
}
instance mul_semigroup_has_mul t (ms: mul_semigroup t) : has_mul t = ms.mul_semigroup_has_mul
class mul_monoid t = {
[@@@TC.no_method] mul_monoid_sg : mul_semigroup t;
mul_neutral : t;
mul_identity : (x:t) -> Lemma ((mul x mul_neutral `eq` x) /\ (mul mul_neutral x `eq` x))
}
class mul_semigroup_eq t = {
[@@@TC.no_method] mul_semigroup_eq_has_mul_eq : has_mul_eq t;
mul_eq_associativity: (x:t) -> (y:t) -> (z:t) -> Lemma ((x * (y * z)) == ((x * y) * z))
}
instance mul_semigroup_eq_has_mul_eq t (ms: mul_semigroup_eq t) : has_mul_eq t = ms.mul_semigroup_eq_has_mul_eq
class mul_monoid_eq t = {
[@@@TC.no_method] mul_monoid_eq_mul_semigroup_eq : mul_semigroup_eq t;
mul_eq_neutral : t;
mul_eq_identity : (x:t) -> Lemma (x * mul_eq_neutral == x /\ mul_eq_neutral * x == x)
}
instance has_mul_setoid t {| hm: has_mul t |}
: has_mul_eq (setoid t) =
{
( * ) = (fun (x y: setoid t) -> let ex = get_x x in
let ey = get_x y in
let r = F.on_g t (fun p -> eq p (hm.mul ex ey)) in
reflexivity (hm.mul ex ey);
r);
mul_eq_congruence = fun (x y z w: setoid t) -> ()
}
instance mul_semigroup_setoid t ( mm: mul_semigroup t ) : mul_semigroup_eq (setoid t) =
let ( * ) (p q: setoid t) = p * q in
Classical.forall_intro_3 mm.mul_associativity;
Classical.forall_intro mm.mul_semigroup_has_mul.has_mul_has_eq.reflexivity;
Classical.forall_intro_2 mm.mul_semigroup_has_mul.has_mul_has_eq.symmetry;
Classical.forall_intro_3 mm.mul_semigroup_has_mul.has_mul_has_eq.transitivity;
{
mul_semigroup_eq_has_mul_eq = has_mul_setoid t;
mul_eq_associativity = (fun (x y z: setoid t) ->
let eq = mm.mul_semigroup_has_mul.has_mul_has_eq.eq in
let sx = get_x x in
let sy = get_x y in
let sz = get_x z in
let yz = F.on_g t (fun p -> eq p (mul sy sz)) in
let xy = F.on_g t (fun p -> eq p (mul sx sy)) in
assert (get_x yz `eq` mul sy sz);
assert (F.feq_g (y*z) yz);
assert (F.feq_g (x*y) xy);
// assert (yz == y*z);
assert (F.feq_g (x*(y*z)) (F.on_g t (fun p -> eq p (mul (get_x x) (get_x yz)))));
// assert ((x*(y*z)) == F.on_g t (fun p -> eq p (mul (get_x x) (get_x yz))));
let x_yz = x * (y*z) in
let xy_z = (x * y)*z in
// assert (get_x x_yz `eq` mul sx (get_x yz));
// assert (get_x xy_z `eq` mul (get_x xy) sz);
mm.mul_semigroup_has_mul.mul_congruence sx (get_x yz) sx (mul sy sz);
mm.mul_semigroup_has_mul.mul_congruence (get_x xy) sz (mul sx sy) sz;
assert (F.feq_g x_yz xy_z)
)
}
let test_lemma #t {| sg: mul_semigroup t |} (p q r s: t)
: Lemma (ensures (ec p * ec q * ec r * ec s == (ec p * ec q) * (ec r * ec s))) =
let hm : mul_semigroup_eq (setoid t) = TC.solve in
hm.mul_eq_associativity (ec p) (ec q) (ec r);
Classical.forall_intro_3 hm.mul_eq_associativity
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment