File: srel.v

package info (click to toggle)
coq-relation-algebra 1.7.11-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 912 kB
  • sloc: ml: 1,452; makefile: 53; sh: 20
file content (260 lines) | stat: -rw-r--r-- 10,045 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
(** * srel: heterogeneous binary relations between setoids *)

(** counterpart to module [rel], where we provide a KAT model of relations on setoids
    relations have to be invariant under the setoid equalities, the identity relation 
    is defined as the setoid equality rather than [Logic.eq], Kleene star is defined 
    accordingly.
 *)

Require Bool.
Require Export boolean prop.
Require Import kat rel.

(** base type for setoids ; 
    if there is standard one in the standard library, we might want to switch to it 
    it could also be nice to have [lattice.weq] set up using such a structure, to share notation and lemmas
 *)
Record EqType := {
    type_of:> Type@{U};
    Eq: relation type_of;
    Equivalence_Eq: Equivalence Eq
  }.
#[export] Existing Instance Equivalence_Eq.

(* note: would be natural to try to define a counterpart to [lattice.pw_ops] 
   for equality preserving funtions from A to X (using the following record type as carrier)
 *)
Record spw (A: EqType) (X: lattice.ops) := {
    spw_bod:> A->X;
    spw_Eq: Proper (Eq A ==> weq) spw_bod
  }.
(*
Definition spw_bod' A X := (spw_bod A X: spw A X -> lattice.pw_ops X A).
Coercion spw_bod': spw >-> car.
#[export] Existing Instance spw_Eq.
 *)
(*
  but:
  - this requires laws on X (preservation of weq) to lift the operations, e.g., 
    the lift of [cup] requires [cup_weq] in order to preserve [Eq A]
  - this would force us to use [Proper (Eq A ==> weq)] rather than [pwr A weq] as equality 
    in order to obtain [Proper (Eq A ==> Eq A ==> weq)] for relations, 
    which is possibly not so convenient
 *)

(** * setoid-preserving relations as a lattice *)

(** setoid-preserving relations *)
Record srel (n m: EqType) := {
    hrel_of:> hrel n m;
    srel_Eq: Proper (Eq n ==> Eq m ==> iff) hrel_of
  }.
Arguments hrel_of {_ _}.
(* TOTHINK: only useful locally? *)
Coercion car_of n m: srel n m -> hrel_lattice_ops n m := hrel_of.
#[export] Existing Instance srel_Eq.

(** setoid-preserving relations as a lattice; actually a sublattice of that of plain relations *)
Section s.
 Variables n m: EqType.
 Definition srel_leq (R S: srel n m): Prop := R ≦ S.  
 Definition srel_weq (R S: srel n m): Prop := R ≡ S.  
 Program Definition srel_cup (R S: srel n m): srel n m := {| hrel_of := R ⊔ S |}.
 Next Obligation. now rewrite H, H0. Qed.
 Program Definition srel_cap (R S: srel n m): srel n m := {| hrel_of := R ⊓ S |}.
 Next Obligation. now rewrite H, H0. Qed.
 Program Definition srel_neg (R: srel n m): srel n m := {| hrel_of := !R |}.
 Next Obligation. now rewrite H, H0. Qed.
 Program Definition srel_bot: srel n m := {| hrel_of := bot |}.
 Next Obligation. tauto. Qed.
 Program Definition srel_top: srel n m := {| hrel_of := top |}.
 Next Obligation. tauto. Qed.
 Canonical Structure srel_lattice_ops: lattice.ops := {|
  car := srel n m;
  leq := srel_leq;
  weq := srel_weq;
  cup := srel_cup;
  cap := srel_cap;
  neg := srel_neg;
  bot := srel_bot;
  top := srel_top
 |}.
 Arguments srel_leq _ _ /. 
 Arguments srel_weq _ _ /. 
 Arguments srel_cup _ _ /. 
 Arguments srel_cap _ _ /. 
 Arguments srel_neg _ /. 
 Arguments srel_bot /. 
 Arguments srel_top /. 

 (** lattices laws follow from the fact that we have a sublattice of plain relations *)
 #[export] Instance srel_lattice_laws: lattice.laws (BDL+STR+CNV+DIV) srel_lattice_ops.
 Proof. apply (laws_of_injective_morphism hrel_of); trivial. now split. Qed.

End s.


(** * setoid-preserving relations as a Kleene category *)

(** not a subcategory of plain relations: we have to modify [1] and [x^*] *)
Section RepOps.
 Implicit Types n m p : EqType.

 Program Definition srel_one n: srel n n := 
  {| hrel_of := Eq n |}.

 Program Definition srel_dot n m p (x: srel n m) (y: srel m p): srel n p := 
  {| hrel_of := x⋅y |}.
 Next Obligation.
   split; intros [z H1 H2].
    rewrite H in H1. rewrite H0 in H2. now exists z. 
    rewrite <-H in H1. rewrite <-H0 in H2. now exists z. 
 Qed. 

 Program Definition srel_cnv n m (x: srel n m): srel m n := 
   {| hrel_of := x° |}.
 Next Obligation. unfold hrel_cnv. now rewrite H, H0. Qed.
 
 Program Definition srel_ldv n m p (x: srel n m) (y: srel n p): srel m p := 
  {| hrel_of := x -o y |}.
 Next Obligation. unfold hrel_ldv. setoid_rewrite H. setoid_rewrite H0. reflexivity. Qed. 

 Program Definition srel_rdv n m p (x: srel m n) (y: srel p n): srel p m := 
  {| hrel_of := y o- x |}.
 Next Obligation. unfold hrel_rdv. setoid_rewrite H. setoid_rewrite H0. reflexivity. Qed. 

 Section i.
  Variable n: EqType.
  Variable x: srel n n.
  (** finite iterations of a relation *)
  Fixpoint iter u: srel n n := match u with O => srel_one n | S u => srel_dot _ _ _ x (iter u) end.
  Program Definition srel_str: srel n n := {| hrel_of i j := exists u, iter u i j |}.
  Next Obligation. setoid_rewrite H. setoid_rewrite H0. reflexivity. Qed.
  Definition srel_itr: srel n n := srel_dot n n n x srel_str.
 End i.

 Arguments srel_dot [_ _ _] _ _/. 
 Arguments srel_ldv [_ _ _] _ _/. 
 Arguments srel_rdv [_ _ _] _ _/. 
 Arguments srel_cnv [_ _] _ /. 
 Arguments srel_str [_] _ /. 
 Arguments srel_itr [_] _ /. 
 Arguments srel_one {_} /. 
End RepOps.

Canonical Structure srel_monoid_ops :=  
  monoid.mk_ops EqType srel_lattice_ops srel_dot srel_one srel_itr srel_str srel_cnv srel_ldv srel_rdv.

(** we cannot use [monoid.laws_of_faithful_functor]: [1] and [_^*] are not preserved by [rel_of];
    nevertheless, we can reuse [hrel_monoid_laws] for quite a few axioms; and we just reprove the remaining ones
 *)
#[export] Instance srel_monoid_laws: monoid.laws (BDL+STR+CNV+DIV) srel_monoid_ops.
Proof.
  constructor; (try now left); intros. 
   apply srel_lattice_laws.
   apply (dotA (laws:=hrel_monoid_laws)).
   intros i j. split.
    intros [k ik kj]. simpl in ik; now rewrite ik. 
    intro. exists i. simpl; reflexivity. assumption. 
   apply (cnvdot_ (laws:=hrel_monoid_laws)).
   apply (cnv_invol (laws:=hrel_monoid_laws)).
   intros i j ij. now apply (cnv_leq (laws:=hrel_monoid_laws)).
   intros i j E. exists O. exact E.
   intros i k [j Hij [u Hjk]]. exists (S u). now exists j. 
   assert (E: forall i, (iter n x i: srel n n) ⋅ z ≦ z).
    induction i. simpl. intros h k [l hl lk]. simpl in hl. now rewrite hl. 
    rewrite <-H0 at 2. transitivity (x⋅((iter n x i: srel n n)⋅z)). 
     cbn. firstorder congruence. now apply (dot_leq (H:=hrel_monoid_laws)).  
    intros i j [? [? ?] ?]. eapply E. repeat eexists; eauto.
   reflexivity. 
   apply (capdotx (laws:=hrel_monoid_laws)).
   apply (ldv_spec (laws:=hrel_monoid_laws)).
   apply (rdv_spec (laws:=hrel_monoid_laws)).
Qed.

#[export] Instance Equivalence_srel_one A: Equivalence (@one srel_monoid_ops A).
Proof. cbn. typeclasses eauto. Qed.

(** * setoid-preserving relations as a Kleene category with tests *)

(** setoid-preserving tests as a Boolean lattice;
    we redo everything, for lack of nice generic operations on [spw]
 *)
Section tests.
 Variable A: ob srel_monoid_ops.
 Record dset := {
     dset_bod:> A -> bool;
     dset_Eq: Proper (Eq A ==> eq) dset_bod;
   }.
 (* TOTHINK: only useful locally? *)
 Coercion car_of_dset f: lattice.pw_ops bool_lattice_ops A := dset_bod f.
 #[export] Existing Instance dset_Eq.
 (** all operations ar imported from [lattice.pw_ops]  *)
 Definition dset_leq (R S: dset): Prop := R ≦ S.  
 Definition dset_weq (R S: dset): Prop := R ≡ S.  
 Program Definition dset_cup (R S: dset): dset := {| dset_bod := R ⊔ S |}.
 Next Obligation. now rewrite H. Qed.
 Program Definition dset_cap (R S: dset): dset := {| dset_bod := R ⊓ S |}.
 Next Obligation. now rewrite H. Qed.
 Program Definition dset_neg (R: dset): dset := {| dset_bod := !R |}.
 Next Obligation. now rewrite H. Qed.
 Program Definition dset_bot: dset := {| dset_bod := bot |}.
 Program Definition dset_top: dset := {| dset_bod := top |}.
 Canonical Structure dset_lattice_ops: lattice.ops := {|
  car := dset;
  leq := dset_leq;
  weq := dset_weq;
  cup := dset_cup;
  cap := dset_cap;
  neg := dset_neg;
  bot := dset_bot;
  top := dset_top
 |}.
 Arguments dset_leq _ _ /. 
 Arguments dset_weq _ _ /. 
 Arguments dset_cup _ _ /. 
 Arguments dset_cap _ _ /. 
 Arguments dset_neg _ /. 
 Arguments dset_bot /. 
 Arguments dset_top /. 
 
 (** lattices laws follow from the fact that we have a sublattice of plain tests *)
 #[export] Instance dset_lattice_laws: lattice.laws (BL+STR+CNV+DIV) dset_lattice_ops.
 Proof. apply (laws_of_injective_morphism dset_bod); trivial. now split. Qed.
 
 Program Definition srel_inj (x: dset): srel A A := {|hrel_of i j := Eq A i j /\ x i|}.
 Next Obligation. now rewrite H,H0. Qed.

End tests.

(** packing everything as a Kleene category with tests *)
Canonical Structure srel_kat_ops := 
  kat.mk_ops srel_monoid_ops dset_lattice_ops srel_inj.

(** like for monoid laws, we have to reprove everything since we don't have a sub-KAT of that of plain relations *)
#[export] Instance srel_kat_laws: kat.laws srel_kat_ops.
Proof.
  constructor. apply lower_laws.
  intro. simpl. apply lower_lattice_laws. 
  assert (inj_leq: forall n, Proper (leq ==> leq) (@srel_inj n)).
   intros n e f H i j [E H']. split. assumption. revert H'. apply mm_bool_Prop, H.
  constructor; try discriminate. 
  apply inj_leq.
  apply op_leq_weq_1.
  intros _ x y i j. split. 
   intros [E H']. setoid_rewrite Bool.orb_true_iff in H'. 
    destruct H'; [left|right]; split; assumption.  
   intros [[E H']|[E H']]; split; trivial; setoid_rewrite Bool.orb_true_iff; now auto.
  intros _ i j. compute. intuition discriminate. 
  intros ? i j. compute. tauto. 
  intros ? p q i j. split. 
   intros [E H']. setoid_rewrite Bool.andb_true_iff in H'. exists i; split; try tauto. reflexivity. 
   intros [k [ik Hi] [kj Hk]]. subst. split; trivial.
   now transitivity k.
   setoid_rewrite Bool.andb_true_iff; split; trivial.
   now rewrite ik. 
Qed.

Ltac fold_srel := ra_fold srel_monoid_ops.
Tactic Notation "fold_srel" "in" hyp_list(H) := ra_fold srel_monoid_ops in H.
Tactic Notation "fold_srel" "in" "*" := ra_fold srel_monoid_ops in *.