-
Notifications
You must be signed in to change notification settings - Fork 2
/
monoid_group.v
368 lines (319 loc) · 11.5 KB
/
monoid_group.v
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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
(**
Every monoid has a nonempty subgroup consisting of the monoid's
invertible elements.
Copyright (C) 2018 Larry D. Lee Jr. <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*)
Require Import base.
Require Import monoid.
Require Import group.
Require Import Eqdep.
Module Monoid_Group.
(**
Represents the homomorphic mapping between
the set of invertible elements within a monoid
and the group formed over them by the monoid
operation.
*)
Structure Monoid_Group : Type := monoid_group {
(** Represents the set of monoid elements. *)
E : Set;
(** Represents the identity monoid element. *)
E_0 : E;
(** Represents the monoid operation. *)
monoid_op: E -> E -> E;
(** Asserts that the monoid operator is associative. *)
monoid_op_is_assoc : Monoid.is_assoc E monoid_op;
(**
Accepts one monoid element, x, and asserts
that x is the left identity element.
*)
monoid_op_is_id_l := Monoid.is_id_l E monoid_op;
(**
Accepts one monoid element, x, and asserts
that x is the right identity element.
*)
monoid_op_is_id_r := Monoid.is_id_r E monoid_op;
(**
Accepts one monoid element, x, and asserts
that x is the identity element.
*)
monoid_op_is_id := Monoid.is_id E monoid_op;
(** Asserts that 0 is the left identity monoid element. *)
monoid_op_id_l : Monoid.is_id_l E monoid_op E_0;
(** Asserts that 0 is the right identity monoid element. *)
monoid_op_id_r : Monoid.is_id_r E monoid_op E_0;
(**
Represents the monoid whose invertable
elements we are going to map onto a group.
*)
m := Monoid.monoid E E_0 monoid_op monoid_op_is_assoc monoid_op_id_l monoid_op_id_r;
(**
Represents those monoid elements that are
invertable.
Note: each value can be seen intuitively as
a pair, (x, H), where x is a monoid element
and H is a proof that x is invertable.
*)
D : Set
:= { x : E | Monoid.has_inv m x };
(**
Accepts a monoid element and a proof that
it is invertable and returns its projection
in D.
*)
D_cons
: forall x : E, Monoid.has_inv m x -> D
:= exist (Monoid.has_inv m);
(**
Asserts that any two equal invertable monoid
elements, x and y, are equivalent (using
dependent equality).
Note: to compare sig elements that differ
only in their proof terms, such as (x, H) and
(x, H0), we must introduce a new notion of
equality called "dependent equality". This
relationship is defined in the Eqdep module.
*)
D_eq_dep
: forall (x : E) (H : Monoid.has_inv m x) (y : E) (H0 : Monoid.has_inv m y), y = x -> eq_dep E (Monoid.has_inv m) y H0 x H;
(**
Given that two invertable monoid elements x
and y are equal (using dependent equality),
this lemma proves that their projections
into D are equal.
Note: this proof is equivalent to:
eq_dep_eq_sig E (Monoid.has_inv m) y x H0 H
(D_eq_dep x H y H0 H1).
The definition for eq_dep_eq_sig has been
expanded however for compatability with
Coq v8.4.
*)
D_eq
: forall (x : E) (H : Monoid.has_inv m x) (y : E) (H0 : Monoid.has_inv m y), y = x -> D_cons y H0 = D_cons x H
:= fun x H y H0 H1
=> eq_dep_ind E (Monoid.has_inv m) y H0
(fun (z : E) (H2 : Monoid.has_inv m z)
=> D_cons y H0 = D_cons z H2)
(eq_refl (D_cons y H0)) x H (D_eq_dep x H y H0 H1);
(**
Represents the group identity element.
*)
D_0 := D_cons E_0 (Monoid.op_has_inv_0 m);
(**
Represents the group operation.
Note: intuitively this function accepts two
invertable monoid elements, (x, H) and (y,
H0), and returns (x + y, H1), where H, H0,
and H1 are generalized invertability proofs.
*)
group_op
: D -> D -> D
:= sig_rec
(fun _ => D -> D)
(fun (u : E) (H : Monoid.has_inv m u)
=> sig_rec
(fun _ => D)
(fun (v : E) (H0 : Monoid.has_inv m v)
=> D_cons
(monoid_op u v)
(Monoid.op_inv_closed m u H v H0)));
(**
Accepts a group element, x, and asserts
that x is a left identity element.
*)
group_op_is_id_l := Monoid.is_id_l D group_op;
(**
Accepts a group element, x, and asserts
that x is a right identity element.
*)
group_op_is_id_r := Monoid.is_id_r D group_op;
(**
Accepts a group element, x, and asserts
that x is an/the identity element.
*)
group_op_is_id := Monoid.is_id D group_op;
(** Proves that D_0 is a left identity element. *)
group_op_id_l
: group_op_is_id_l D_0
:= sig_ind
(fun x => group_op D_0 x = x)
(fun (u : E) (H : Monoid.has_inv m u)
=> D_eq u H (monoid_op E_0 u) (Monoid.op_inv_closed m E_0 (Monoid.op_has_inv_0 m) u H)
(monoid_op_id_l u));
(** Proves that D_0 is a right identity element. *)
group_op_id_r
: group_op_is_id_r D_0
:= sig_ind
(fun x => group_op x D_0 = x)
(fun (u : E) (H : Monoid.has_inv m u)
=> D_eq u H (monoid_op u E_0) (Monoid.op_inv_closed m u H E_0 (Monoid.op_has_inv_0 m))
(monoid_op_id_r u));
(** Proves that D_0 is the identity element. *)
group_op_id
: group_op_is_id D_0
:= conj group_op_id_l group_op_id_r;
(**
Proves that the group operation is
associative.
*)
group_op_assoc
: Monoid.is_assoc D group_op
:= sig_ind
(fun x => forall y z : D, group_op x (group_op y z) = group_op (group_op x y) z)
(fun (u : E) (H : Monoid.has_inv m u)
=> sig_ind
(fun y => forall z : D, group_op (D_cons u H) (group_op y z) = group_op (group_op (D_cons u H) y) z)
(fun (v : E) (H0 : Monoid.has_inv m v)
=> sig_ind
(fun z => group_op (D_cons u H) (group_op (D_cons v H0) z) = group_op (group_op (D_cons u H) (D_cons v H0)) z)
(fun (w : E) (H1 : Monoid.has_inv m w)
=> let a
: E
:= monoid_op u (monoid_op v w) in
let H2
: Monoid.has_inv m a
:= Monoid.op_inv_closed m u H (monoid_op v w) (Monoid.op_inv_closed m v H0 w H1) in
let b
: E
:= monoid_op (monoid_op u v) w in
let H3
: Monoid.has_inv m b
:= Monoid.op_inv_closed m (monoid_op u v) (Monoid.op_inv_closed m u H v H0) w H1 in
let X
: D
:= D_cons a H2 in
let Y
: D
:= D_cons b H3 in
D_eq b H3 a H2
(monoid_op_is_assoc u v w)
)));
(**
Accepts two values, x and y, and asserts
that y is a left inverse of x.
*)
group_op_is_inv_l := Monoid.is_inv_l D group_op D_0 group_op_id;
(**
Accepts two values, x and y, and asserts
that y is a right inverse of x.
*)
group_op_is_inv_r := Monoid.is_inv_r D group_op D_0 group_op_id;
(**
Accepts two values, x and y, and asserts
that y is an inverse of x.
*)
group_op_is_inv := Monoid.is_inv D group_op D_0 group_op_id;
(**
Accepts two invertable monoid elements, x
and y, where y is a left inverse of x and
proves that y's projection into D is the
left inverse of x's.
*)
group_op_inv_l
: forall (u : E) (H : Monoid.has_inv m u) (v : E) (H0 : Monoid.has_inv m v),
Monoid.op_is_inv_l m u v ->
group_op_is_inv_l (D_cons u H) (D_cons v H0)
:= fun (u : E) (H : Monoid.has_inv m u) (v : E) (H0 : Monoid.has_inv m v)
=> D_eq E_0 (Monoid.op_has_inv_0 m) (monoid_op v u) (Monoid.op_inv_closed m v H0 u H);
(**
Accepts two invertable monoid elements, x
and y, where y is a right inverse of x and
proves that y's projection into D is the
right inverse of x's.
*)
group_op_inv_r
: forall (u : E) (H : Monoid.has_inv m u) (v : E) (H0 : Monoid.has_inv m v),
Monoid.op_is_inv_r m u v ->
group_op_is_inv_r (D_cons u H) (D_cons v H0)
:= fun (u : E) (H : Monoid.has_inv m u) (v : E) (H0 : Monoid.has_inv m v)
=> D_eq E_0 (Monoid.op_has_inv_0 m) (monoid_op u v) (Monoid.op_inv_closed m u H v H0);
(**
Accepts two invertable monoid elements, x
and y, where y is the inverse of x and
proves that y's projection into D is the
inverse of x's.
*)
group_op_inv
: forall (u : E) (H : Monoid.has_inv m u) (v : E) (H0 : Monoid.has_inv m v),
Monoid.op_is_inv m u v ->
group_op_is_inv (D_cons u H) (D_cons v H0)
:= fun (u : E) (H : Monoid.has_inv m u) (v : E) (H0 : Monoid.has_inv m v) (H1 : Monoid.op_is_inv m u v)
=> conj (group_op_inv_l u H v H0 (proj1 H1))
(group_op_inv_r u H v H0 (proj2 H1));
(**
Accepts a group element and returns its
inverse, y, along with a proof that y is
x's inverse.
*)
group_op_neg_strong
: forall x : D, { y : D | group_op_is_inv x y }
:= sig_rec
(fun x => { y : D | group_op_is_inv x y })
(fun (u : E) (H : Monoid.has_inv m u)
=> let v
: E
:= Monoid.op_neg m u H in
let H0
: Monoid.op_is_inv m u v
:= Monoid.op_neg_def m u H in
let H1
: Monoid.has_inv m v
:= Monoid.op_neg_inv_ex m u H in
exist
(fun y : D => group_op_is_inv (D_cons u H) y)
(D_cons v H1)
(group_op_inv u H v H1 H0));
(**
Proves that every group element has an
inverse.
*)
group_op_inv_ex
: forall x : D, exists y : D, group_op_is_inv x y
:= fun x
=> let (y, H) := group_op_neg_strong x in
ex_intro
(fun y => group_op_is_inv x y)
y H;
(**
Proves that every group element has a left
inverse.
*)
group_op_inv_l_ex
: forall x : D, exists y : D, group_op_is_inv_l x y
:= fun x
=> ex_ind
(fun y (H : group_op_is_inv x y)
=> ex_intro (fun z => group_op_is_inv_l x z) y (proj1 H))
(group_op_inv_ex x);
(**
Proves that every group element has a right
inverse.
*)
group_op_inv_r_ex
: forall x : D, exists y : D, group_op_is_inv_r x y
:= fun x
=> ex_ind
(fun y (H : group_op_is_inv x y)
=> ex_intro (fun z => group_op_is_inv_r x z) y (proj2 H))
(group_op_inv_ex x);
(**
Proves that the set of invertable monoid
elements form a group over the monoid
operation.
*)
g := Group.group D D_0 group_op group_op_assoc
group_op_id_l group_op_id_r group_op_inv_l_ex
group_op_inv_r_ex
}.
End Monoid_Group.