-
Notifications
You must be signed in to change notification settings - Fork 0
/
groups.dtx
2021 lines (2021 loc) · 69.4 KB
/
groups.dtx
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
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%
% \iffalse
%<*driver>
\documentclass{mtmtcl}
\begin{document}
\DocInput{groups.dtx}
\PrintIndex
\end{document}
%</driver>
% \fi
%
%
% \part{Groups and variants}
%
% While basic courses in abstract algebra typically begin with groups
% or fields, there is also the ``Bourbaki'' style of beginning with a
% magma (set with one binary operation not known to satisfy any
% axioms). Going that far is not immediately useful, but semigroups and
% monoids have the direct applications that it is not necessary to
% separately define associative rings and associative unital rings,
% since these are the same things as rings which also satisfy the
% axioms for a semigroup and monoid, respectively.
%
% Implementation-wise, there is one package |mtmtcl::groups::util|
% which collects utility commands that are useful for several groups,
% and some number of sibling packages which implement particular
% groups (or families of groups). For historical reasons, there is
% also a docstrip module {\Module{pkg}} which pretty much includes
% all code (sans that for package handling). The trend is to migrate
% code from this big combination to functionality-specific packages.
% The {\Module{common}} module is for code common to such packages
% (namely the |mtmtcl::groups| namespace declaration).
% \begin{tcl}
%<pkg,common>namespace eval ::mtmtcl::groups {}
%<*docstrip.tcl::catalogue>
pkgProvide mtmtcl::groups::util 1.0 util
%</docstrip.tcl::catalogue>
%<util,pkg>namespace eval ::mtmtcl::groups::util {}
% \end{tcl}
% \setnamespace{mtmtcl::groups}
%
%
% \section{Basic versions}
%
% The general trend for \texttt{group} and other group-related
% interface classes is that version~1.0 provides the fundamental
% operations, whereas higher version numbers add more and more derived
% operations (variadic operation, powers, power products). The
% \texttt{semigroup}, \texttt{monoid}, and \texttt{group} interfaces
% all employ a multiplicative notation; see \tclverb*|additive group|
% for the additive counterpart.
%
%
% \begin{APIspec}{semigroup}{1.0}
% The \texttt{semigroup} interface (v\,1.0) prescribes two methods:
% the binary operation |*| and the equality relation |=|.
% \begin{APIdescription}{semigroup}
% \begin{APImethod}{=}
% \word{element} \word{element}
% \end{APImethod}
% The |=| method satisfies version~1.0 of the \texttt{equality}
% interface.
%
% \begin{APImethod}{*}
% \word{element} \word{element}
% \end{APImethod}
% The |*| method is an associative binary operation. This implies
% that every \meta{semigroup} $G$ must have the property that the
% two expressions
% \begin{displaysyntax}
% [$G$ * [$G$ * $a$ $b$] $c$]\par
% [$G$ * $a$ [$G$ * $b$ $c$]]
% \end{displaysyntax}
% are |=|-equal for all elements $a$, $b$, and $c$.
% \end{APIdescription}
% The |*| method is congruent.
% \end{APIspec}
%
% \begin{APIspec}{monoid}{1.0}
% The \texttt{monoid} interface is an extension of \texttt{semigroup}
% which adds a multiplicative unit method.
% \begin{APIdescription}{monoid}
% \begin{APImethod}{=}
% \word{element} \word{element}
% \end{APImethod}
% The |=| method satisfies version~1.0 of the \texttt{equality}
% interface.
%
% \begin{APImethod}{*}
% \word{element} \word{element}
% \end{APImethod}
% The |*| method satisfies version~1.0 of the \texttt{semigroup}
% interface.
%
% \begin{APImethod}{1}
% \end{APImethod}
% The |1| method returns the identity element of the monoid. The
% relevant axiom says that the three expressions
% \begin{displaysyntax}
% [$G$ * [$G$ 1] $a$]\par
% [$G$ * $a$ [$G$ 1]]\par
% $a$
% \end{displaysyntax}
% are |=|-equal for every element $a$ of the \meta{monoid} $G$.
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
% \begin{proc}{string_free_monoid}
% This procedure is implements the free \texttt{monoid} of
% strings (over the Unicode alphabet). The overall syntax is
% \begin{displaysyntax}
% |::mtmtcl::groups::string_free_monoid|
% \word{subcommand} \word{argument}\regstar
% \end{displaysyntax}
% and the implemented subcommands are |API|, |=|, |*|, and |1|.
% \begin{tcl}
%<*docstrip.tcl::catalogue>
pkgProvide mtmtcl::groups::string_free_monoid 1.0 {stringmonoid common}
%</docstrip.tcl::catalogue>
%<*pkg,stringmonoid>
proc ::mtmtcl::groups::string_free_monoid {method args} {
switch -- $method {
% \end{tcl}
% \begin{procmethod}{=}
% String equality is implemented by the \Tcl\ core.
% \begin{tcl}
= {string equal [lindex $args 0] [lindex $args 1]}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{*}
% The product of two lists is their concatenation.
% \begin{tcl}
* {join $args ""}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{1}
% The identity element is the empty string.
% \begin{tcl}
1 {return ""}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{canonise}
% Every string is a value on canonical form, but an explicit
% |canonise| method that just returns the argument is a useful
% piece of glue.
% \begin{tcl}
canonise {return [lindex $args 0]}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{API}
% It just so happens that the definition of |*| above satifies
% not only v\,1.0 but also v\,1.1 of \texttt{semigroup} and
% \texttt{monoid}, so we might as well say so. Furthermore every
% string has a unique representation, so we can declare support
% for the \texttt{onlycanonical} and \texttt{autocanonical}
% interfaces as well.
% \begin{tcl}
API {
::API::static {equality 1.0 autocanonical 1.0 \
onlycanonical 1.0 semigroup 1.1 monoid 1.1} {*}$args
}
% \end{tcl}
% \end{procmethod}
%
% It doesn't hurt to give an informative error message.
% \begin{tcl}
default {
return -code error "Unknown method \"$method\": must be\
=, *, 1, canonise, or API"
}
}
}
%</pkg,stringmonoid>
% \end{tcl}
% \end{proc}
%
%
% \begin{APIspec}{group}{1.0}
% The \texttt{group} interface is an extension of \texttt{monoid}
% with a multplicative inverse operation.
%
% \begin{APIdescription}{group}
% \begin{APImethod}{=}
% \word{element} \word{element}
% \end{APImethod}
% The |=| method satisfies version~1.0 of the \texttt{equality}
% interface.
%
% \begin{APImethod}{*}
% \word{element} \word{element}
% \end{APImethod}
% The |*| method satisfies version~1.0 of the \texttt{semigroup}
% interface.
%
% \begin{APImethod}{1}
% \end{APImethod}
% The |1| method satisfies version~1.0 of the \texttt{monoid}
% interface.
%
% \begin{APImethod}{inverse}
% \word{element}
% \end{APImethod}
% The inversion operation |inverse| has the property that
% \begin{displaysyntax}
% [$G$ * $a$ [$G$ inverse $a$]]\par
% [$G$ * [$G$ inverse $a$] $a$]\par
% [$G$ 1]
% \end{displaysyntax}
% are |=|-equal for all elements $a$ of the \meta{group} $G$.
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
% Additive groups, like multiplicative groups, can be specified as
% extensions of additive semigroups or monoids, but these aren't all
% that common, so it is probably easier to do it all in one go.
%
% \begin{APIspec}{additive group}{2.0}
% In the additive notation for a group, the binary operation is $+$,
% the identity element is $0$, and the inversion operation is
% written |neg|.
%
% \changes{0.1}{2010/03/25}{Introduced version 2.0 and friends of
% \texttt{additive group}. Deprecating 1.0. (LH)}
%
% \begin{APIdescription}{group}
% \begin{APImethod}{=}
% \word{element} \word{element}
% \end{APImethod}
% The |=| method satisfies version~1.0 of the \texttt{equality}
% interface.
%
% \begin{APImethod}{+}
% \word{element} \word{element}
% \end{APImethod}
% The |+| operation is binary group operation. By
% associativity, the two expressions
% \begin{displaysyntax}
% [$G$ + [$G$ + $a$ $b$] $c$]\par
% [$G$ + $a$ [$G$ + $b$ $c$]]
% \end{displaysyntax}
% are |=|-equal for all elements $a$, $b$, and $c$ of a
% \meta{group} $G$.
%
% \begin{APImethod}{0}
% \end{APImethod}
% The |0| method returns the identity element of the
% group. The relevant axiom says that the three expressions
% \begin{displaysyntax}
% [$G$ + [$G$ 0] $a$]\par
% [$G$ + $a$ [$G$ 0]]\par
% $a$
% \end{displaysyntax}
% are |=|-equal for each element $a$ of a \meta{group} $G$.
%
% \begin{APImethod}{neg}
% \word{element}
% \end{APImethod}
% The inversion operation |neg| has the property that
% \begin{displaysyntax}
% [$G$ + $a$ [$G$ neg $a$]]\par
% [$G$ + [$G$ neg $a$] $a$]\par
% [$G$ 0]
% \end{displaysyntax}
% are |=|-equal for each element $a$ of a \meta{group} $G$.
% \end{APIdescription}
% All methods are congruent. Note that |additive group| does
% \emph{not} require the group to be abelian.
% \end{APIspec}
%
% Version~1.0 of |additive group| was the same as version~2.0,
% except that the inversion operation was named |-|. It turns out
% that it is more practical to reserve |-| as the name for
% subtraction, as implementations would have to determine at runtime
% which is wanted if they both have the same name.
%
% \begin{APIspec}{additive group}{1.0}
% \begin{APIdescription}{group}
% \begin{APImethod}{=}
% \word{element} \word{element}
% \end{APImethod}
% The |=| method satisfies version~1.0 of the
% \APIref{equality}{1.0} interface.
%
% \begin{APImethod}{+}
% \word{element} \word{element}
% \end{APImethod}
% The |+| operation is binary group operation. By
% associativity, the two expressions
% \begin{displaysyntax}
% [$G$ + [$G$ + $a$ $b$] $c$]\par
% [$G$ + $a$ [$G$ + $b$ $c$]]
% \end{displaysyntax}
% are |=|-equal for all elements $a$, $b$, and $c$ of a
% \meta{group} $G$.
%
% \begin{APImethod}{0}
% \end{APImethod}
% The |0| method returns the identity element of the
% group. The relevant axiom says that the three expressions
% \begin{displaysyntax}
% [$G$ + [$G$ 0] $a$]\par
% [$G$ + $a$ [$G$ 0]]\par
% $a$
% \end{displaysyntax}
% are |=|-equal for each element $a$ of a \meta{group} $G$.
%
% \begin{APImethod}{-}
% \word{element}
% \end{APImethod}
% The inversion operation |-| has the property that
% \begin{displaysyntax}
% [$G$ + $a$ [$G$ - $a$]]\par
% [$G$ + [$G$ - $a$] $a$]\par
% [$G$ 0]
% \end{displaysyntax}
% are |=|-equal for each element $a$ of a \meta{group} $G$.
% \end{APIdescription}
% All methods are congruent. Note that |additive group| does
% \emph{not} require the group to be abelian.
% \end{APIspec}
%
%
% The above are pretty obvious translations of standard textbook
% definitions, but there are also some computational subtleties in
% them that disappear among the mathematical content. Defining the
% minimalistic structure of a \texttt{magma} serves, if nothing else,
% the purpose of letting these details be discussed.
%
% \begin{APIspec}{magma}{1.0}
% A magma is mathematically a set $M$ together with a binary
% operation \(*\colon M \times M \longrightarrow M\).
% \begin{APIdescription}{magma}
% \begin{APImethod}{*}
% \word{element} \word{element}
% \end{APImethod}
% The |*| method returns an element of the magma.
% \end{APIdescription}
% \end{APIspec}
%
% Does that capture the conventional sense of what it means to be a
% magma, though? A slightly stronger formalisation is the following.
%
% \begin{APIspec}{magma}{1.1}
% A magma is a set $M$ together with the equality relation on $M$
% and a binary operation \(*\colon M \times M \longrightarrow M\).
% \begin{APIdescription}{magma}
% \begin{APImethod}{=}
% \word{element} \word{element}
% \end{APImethod}
% The |=| method satisfies version~1.0 of the
% \APIref{equality}{1.0} interface.
%
% \begin{APImethod}{*}
% \word{element} \word{element}
% \end{APImethod}
% The |*| method returns an element of the magma, and is congruent.
% \end{APIdescription}
% \end{APIspec}
%
% What \APIref+{magma}{1.1} claims in addition to the conjunction of
% \APIref+{magma}{1.0} and \APIref+{equality}{1.0} is that |*| is
% congruent, which is not a trivial claim\Dash indeed, it is often a
% claim that is required for a construction to make sense. It is
% however traditionally not given the status of axiom, since it is
% trivial for the set-theoretic equality relation.
%
% \begin{APIspec}{commutative *}{1.0}
% This interface is simply the statement that the |*| operation,
% whatever it computes, is commutative.
% \begin{APIdescription}{magma}
% \begin{APImethod}{=}
% \word{element} \word{element}
% \end{APImethod}
% The |=| method satisfies version~1.0 of the
% \APIref{equality}{1.0} interface.
%
% \begin{APImethod}{*}
% \word{element} \word{element}
% \end{APImethod}
% The |*| method returns an element of the magma.
% The |*| method has the property that
% \begin{displaysyntax}
% [$M$ * $a$ $b$]\par
% [$M$ * $b$ $a$]
% \end{displaysyntax}
% are |=|-equal for any two elements $a$ and $b$ of a
% \meta{magma} $M$.
% \end{APIdescription}
% \end{APIspec}
%
% Why not call \APIref{commutative *}{1.0} something like
% \tclverb*|commutative magma|, though? While that would be more in
% line with traditional mathematical terminology, it doesn't
% generalise all that well\Dash commutativity is a property that one
% might require for quite a number of different operations (besides
% addition and the main multiplication). By including the operation
% name in the interface name, one opens up for having multiple such
% interfaces around. On the other hand, something like dot-product
% commutativity would be slightly different, as in that case the
% equality in the axiom is equality in a different (but related)
% structure.
%
%
%
% \section{User-friendly extensions}
%
% \subsection{Variadic operation versions}
%
% While the methods specified by interfaces in the previous section
% suffice for any computation with elements in a magma, semigroup,
% monoid, or group, it is often possible to provide more optimised
% implementation of specific operations. One example is that one
% $n$-ary product might be quicker to compute than $n-1$ binary
% products.
%
% \begin{APIspec}{semigroup}{1.1}
% Version~1.1 of \texttt{semigroup} extends the |*| operation to be
% variadic:
% \begin{APIdescription}{semigroup}
% \begin{APImethod}{*}
% \word{element}\regplus
% \end{APImethod}
% The unary form of this method returns the original
% element, or more precisely, the two expressions
% \begin{displaysyntax}
% [$G$ * $a$]
% \par
% $a$
% \end{displaysyntax}
% are |=|-equal for every element $a$ of the \meta{semigroup}
% $G$. The general identity for the variadic form is that the
% two expressions
% \begin{displaysyntax}
% [$G$ * [$G$ * \meta{$L_a$}] [$G$ * \meta{$L_b$}]]
% \par
% [$G$ * \meta{$L_a$} \meta{$L_b$}]
% \end{displaysyntax}
% are |=|-equal for any two nonempty lists $L_a$ and $L_b$ of
% elements of the \meta{semigroup} $G$.
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
%
% \begin{APIspec}{monoid}{1.1}
% Version~1.1 of \texttt{monoid} extends the |*| operation to be
% variadic. It goes one step further than its \texttt{semigroup}
% counterpart by allowing also a nullary multiplication.
% \begin{APIdescription}{monoid}
% \begin{APImethod}{*}
% \word{element}\regstar
% \end{APImethod}
% This method satisfies version 1.1 of the |semigroup| interface,
% and in addition the two expressions
% \begin{displaysyntax}
% [$G$ * [$G$ * \meta{$L_a$}] [$G$ * \meta{$L_b$}]]
% \par
% [$G$ * \meta{$L_a$} \meta{$L_b$}]
% \end{displaysyntax}
% are |=|-equal for any two lists (not just nonempty lists)
% $L_a$ and $L_b$ of elements of the \meta{monoid} $G$.
%
% It follows that the nullary form of the |*| method returns
% the unit element, because \texttt{[$G$ *]} is by the unit axiom
% equal to \texttt{[$G$ * [$G$ 1] [$G$ *]]}, which by the unary
% |*| axiom is equal to \texttt{[$G$ * [$G$ * [$G$ 1]] [$G$ *]]},
% which by the variadic axiom is equal to
% \texttt{[$G$ * [$G$ 1]]}, which by the unary |*| axiom is equal
% to \texttt{[$G$ 1]}.
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
%
% \begin{APIspec}{group}{1.1}
% Version~1.1 of \texttt{group} extends the |*| operation to be
% variadic:
% \begin{APIdescription}{group}
% \begin{APImethod}{*}
% \word{element}\regstar
% \end{APImethod}
% This method satisfies version 1.1 of the |monoid| interface.
%
% \begin{remark}
% When the |inverse| is available, the unary |*| axiom becomes
% redundant.
% \end{remark}
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
%
% \begin{proc}{list_free_monoid_1.1_do}
% This procedure implements the free \APIref+{monoid}{1.1} over a
% structure with \APIref{equality}{1.0}. The overall syntax is
% \begin{displaysyntax}
% |::mtmtcl::groups::list_free_monoid_1.1_do| \word{base structure}
% \word{API-dict} \word{subcommand} \word{argument}\regstar
% \end{displaysyntax}
% and the return value depends on the \word{subcommand}.
% \changes{0.2}{2010/05/02}{Rewritten as constructor with
% do-procedure. (LH)}
%
% \begin{tcl}
%<*docstrip.tcl::catalogue>
pkgProvide mtmtcl::groups::list_free_monoid 1.0 {listmonoid common}
%</docstrip.tcl::catalogue>
%<*pkg,listmonoid>
proc ::mtmtcl::groups::list_free_monoid_1.1_do {base API method args} {
switch -- $method {
% \end{tcl}
% \begin{procmethod}{=}
% Two lists are equal if they are the same length and
% corresponding list elements are equal.
% \begin{tcl}
= {
if {[llength [lindex $args 0]] != [llength [lindex $args 1]]}\
then {return 0}
foreach x [lindex $args 0] y [lindex $args 1] {
if {![{*}$base = $x $y]} then {return 0}
}
return 1
}
% \end{tcl}
% This completes the \APIref+{equality}{1.0} interface. Doing
% version 1.1 would be an unnecessary complication.
% \end{procmethod}
%
% \begin{procmethod}{*}
% The product of a collection of lists is their concatenation.
% \begin{tcl}
* {
return [concat {*}$args]
}
% \end{tcl}
% That this is so easy to implement is the reason why this
% implementation does not stop at \APIref+{monoid}{1.0}, but
% instead goes on to version~1.0.
% \end{procmethod}
%
% \begin{procmethod}{1}
% The identity element is the empty list.
% \begin{tcl}
1 {return [list]}
% \end{tcl}
% This completes the \APIref+{monoid}{1.1} interface.
% \end{procmethod}
%
% \begin{procmethod}{canonise}
% Canonisation means canonise each list element and rebuild the
% list with canonical representation.
% \begin{tcl}
canonise {
set res [list]
foreach item [lindex $args 0] {
lappend res [{*}$base canonise $item]
}
return $res
}
% \end{tcl}
% This is supported if the base structure supports it.
% \end{procmethod}
%
% \begin{procmethod}{named}
% Named elements of the base structure are accepted as names
% for the length $1$ list containing that element.
% \begin{tcl}
named {return [list [{*}$base named [lindex $args 0]]]}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{* decomposition}
% There is a trivial element decomposition which puts the power
% $1$ on everything.
% \begin{tcl}
{* decomposition} {
%<*trivial>
set res {}
foreach item [lindex $args 0] {
lappend res $item 1
}
%</trivial>
% \end{tcl}
% But it is nicer to recognise sequences of identical elements
% and express those as powers; \APIref{equality}{1.0} in the
% base structure is sufficient for this.
% \begin{tcl}
%<*!trivial>
if {[llength [lindex $args 0]] > 1} then {
set res [list [lindex $args 0 0]]
set count 1
foreach item [lrange [lindex $args 0] 1 end] {
if {[{*}$base = [lindex $res end] $item]} then {
incr count
} else {
lappend res $count $item
set count 1
}
}
lappend res $count
} elseif {[llength [lindex $args 0]] == 1} then {
set res [list [lindex $args 0 0] 1]
} else {
set res {}
}
%</!trivial>
return $res
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{generator}
% The |generator| method returns a list of length one whose only
% element is the argument.
% \begin{tcl}
generator {return [lrange $args 0 0]}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{generators}
% The base structure is made available via the |generators|
% method.
% \changes{0.2}{2010/05/02}{Renamed from \texttt{namestructure}.
% (LH)}
% \begin{tcl}
generators {uplevel 1 $base $args}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{export}
% Exporting is pretty straightforward: just form the product of
% the exports of each element separately. This may serve as an
% example of how to handle the paths.
% \begin{tcl}
export {
lassign $args L attr
set sattr [dict replace $attr cd arith1 name times]
dict lappend sattr mtmtcl:path *
set childL [list [list OMS $sattr {}]]
set battr $attr
dict lappend battr mtmtcl:path generators
foreach factor $L {
lappend childL [{*}$base export $factor $battr]
}
return [list OMA $attr $childL]
}
% \end{tcl}
% In a free monoid with power operation, it might be more
% appropriate to use powers as much as possible when expressing
% the element.
% \end{procmethod}
%
% \begin{procmethod}{API}
% Since the base structure is cached in a parameter, the
% implementation of this is trivial.
% \begin{tcl}
API {::API::static $API {*}$args}
% \end{tcl}
% \end{procmethod}
%
% It doesn't hurt to give an informative error message.
% \begin{tcl}
default {
return -code error "Unknown method \"$method\""
}
}
}
% \end{tcl}
% \end{proc}
%
% \begin{proc}{list_free_monoid_1.1}
% The constructor for the list free monoid has the call syntax
% \begin{displaysyntax}
% |mtmtcl::groups::list_free_monoid_1.1| \word{base structure}
% \end{displaysyntax}
% i.e., it takes the underlying base structure as only argument and
% returns the corresponding free monoid.
%
% \begin{tcl}
proc ::mtmtcl::groups::list_free_monoid_1.1 {base} {
set D [dict create]
if {[{*}$base API equality 1.0]} then {
dict lappend D equality 1.0
dict lappend D semigroup 1.1
dict lappend D monoid 1.1
% \end{tcl}
% The claim to support \APIref{generated semigroup}{1.0} is
% commented out until the actual specification has been done.
% \begin{tcl}
# dict lappend D "generated semigroup" 1.0
}
if {[{*}$base API canonise 1.0]} then {
if {[{*}$base API canonise 1.1]} then {
dict set D canonise 1.1
} else {
dict set D canonise 1.0
}
}
if {[{*}$base API "named element" 1.0]} then {
dict lappend D "named element" 1.0
}
if {[{*}$base API export 2.0]} then {
dict set D export 2.0
}
return [list [namespace which list_free_monoid_1.1_do] $base D]
}
%</pkg,listmonoid>
% \end{tcl}
% \end{proc}
%
%
% \subsection{Powers}
%
% A power operation makes sense for two reasons. First, it is
% customary to express things using powers whenever possible. Second,
% there might be quicker ways of computing powers than just what you
% get from repeated multiplication (even when repeated multiplication
% includes squaring in $O(\log_2 n)$ multiplications rather the $n-1$
% required by the trivial algorithm of multiplying by the base).
% Examples include:
% \begin{enumerate}
% \item
% In a power product monoid, taking a power just means taking a
% multiple of the exponents.
% \item
% Large powers of a matrix can be mostly reduced to large powers
% of scalars, by diagonalising the matrix (or more generally,
% transformation to Jordan normal form). Although for practical
% computations, it often works out the other way around.
% \item
% Employing knowledge about periods to limit the powers that need
% to be computed. A permutation can be factorised into
% cycles, and the order of each cycle is equal to its length.
% \end{enumerate}
% In such cases, an implementation of a power method constitutes a
% useful addition to a group.
%
% \begin{APIspec}{semigroup}{1.2}
% Version 1.2 of \texttt{semigroup} improves on v\,1.1 by adding
% a power method.
% \begin{APIdescription}{semigroup}
% \begin{APImethod}{^}
% \word{element} \word{integer}
% \end{APImethod}
% The \word{integer} must be positive.
% The value of \texttt{[\meta{group} \^{} $a$ $n$]} is $a^n$.
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
% \begin{APIspec}{monoid}{1.2}
% Version 1.2 of \texttt{monoid} improves on v\,1.1 by adding
% a power method.
% \begin{APIdescription}{monoid}
% \begin{APImethod}{^}
% \word{element} \word{integer}
% \end{APImethod}
% The \word{integer} must be nonnegative.
% The value of \texttt{[\meta{group} \^{} $a$ $n$]} is $a^n$.
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
% \begin{APIspec}{group}{1.2}
% Version 1.2 of \texttt{group} improves on v\,1.1 by adding a power
% method.
% \begin{APIdescription}{group}
% \begin{APImethod}{^}
% \word{element} \word{integer}
% \end{APImethod}
% The value of \texttt{[\meta{group} \^{} $a$ $n$]} is $a^n$.
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
% A \APIref+{group}{1.2} satisfies \APIref+{monoid}{1.2} and
% \APIref+{semigroup}{1.2}, but a \APIref+{group}{1.1} that satisfies
% \APIref+{monoid}{1.2} is not necessarily a \APIref+{group}{1.2},
% since the latter makes claims about e.g.~\texttt{[\meta{group} \^{} $a$
% -1]} whereas the former does not\Dash there an exponent of $-1$
% could cause the power operation to error out as not implemented.
%
% ---
%
% \begin{APIspec}{group}{1.3}
% Version 1.3 of \texttt{group} improves on v\,1.2 by adding a power
% product method |*^|, analogous to a linear combination.
% \begin{APIdescription}{group}
% \begin{APImethod}{*^}
% \begin{regblock}[\regstar] \word{element} \word{integer}
% \end{regblock}
% \end{APImethod}
% The value of
% \begin{displaysyntax}
% [\meta{group} *\^{} $a_1$ $n_1$ $\dots$ $a_k$ $n_k$]
% \end{displaysyntax}
% is $a_1^{n_1} \dotsb a_k^{n_k}$, i.e., on one hand
% \begin{displaysyntax}
% [$G$ |*^| $a$ $n$]\par
% [$G$ |^| $a$ $n$]
% \end{displaysyntax}
% are |=|-equal for every element $a$ and integer $n$, and on the
% other,
% \begin{displaysyntax}
% [$G$ |*^| \splode$L_a$ \splode$L_b$]\par
% [$G$ * [$G$ |*^| \splode$L_a$] [$G$ |*^| \splode$L_b$]]
% \end{displaysyntax}
% are |=|-equal for all lists $L_a$ and $L_b$ with the structure
% \begin{quote}
% \begin{regblock}[\regstar] \word{element} \word{integer}
% \end{regblock}
% \end{quote}
% \end{APIdescription}
% All methods are congruent.
% \end{APIspec}
%
%
% \begin{proc}{power_product_monoid_1.3}
% The |power_product_monoid_1.3| procedure implements
% multiplicative free abelian monoids, denoted as power products.
% The \meta{monoid} command prefix is
% \begin{displaysyntax}
% |power_product_monoid| \word{generator set}
% \end{displaysyntax}
% where the \word{generator set} is the command prefix of a
% \APIref+{finite set}{1.1}.
%
% Elements are lists of exponents, where the $i$th exponent
% corresponds to the $i$th generator. The exponents are native
% non-negative integers.
%
% \begin{tcl}
%<*pkg>
proc ::mtmtcl::groups::power_product_monoid_1.3 {base method args} {
switch -- $method {
% \end{tcl}
% \begin{procmethod}{=}
% Since all elements are lists of the same length, two lists
% are equal if corresponding list elements are equal.
% \begin{tcl}
= {
foreach x [lindex $args 0] y [lindex $args 1] {
if {$x != $y]} then {return 0}
}
return 1
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{1}
% The identity element is a list of zeroes, but one must look at
% the set of generators to figure out how many.
% \begin{tcl}
1 {
set res {}
foreach x [{*}$base elements] {lappend res 0}
return $res
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{*}
% The product of a collection of lists is their pointwise sum.
% \begin{tcl}
* {
if {![llength $args]} then {
return [power_product_monoid_1.3 $base 1]
}
set res [lindex $args 0]
foreach factor [lrange $args 1 end] {
set nres {}
foreach x $res y $factor {lappend nres [expr {$x+$y}]}
set res $nres
}
return $res
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{^}
% The power operation is similarly a pointwise multiplication by
% scalar.
% \begin{tcl}
^ {
set res {}
foreach item [lindex $args 0] {
lappend res [expr {$item * [lindex $args 1]}]
}
return $res
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{*^}
% The product-of-powers operation combines pointwise sum and
% multiplication by scalar.
% \begin{tcl}
* {
if {![llength $args]} then {
return [power_product_monoid_1.3 $base 1]
}
set res {}
foreach item [lindex $args 0] {
lappend res [expr {$item * [lindex $args 1]}]
}
foreach {factor exp} [lrange $args 2 end] {
set nres {}
foreach x $res y $factor {lappend nres [expr {$x+$y*$exp}]}
set res $nres
}
return $res
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{canonise}
% Canonisation means canonise each list element and rebuild the
% list with canonical representation.
% \begin{tcl}
canonise {
set res [list]
foreach item [lindex $args 0] {
lappend res [format %d $item]
}
return $res
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{named}
% Elements of the base structure are accepted as names for
% element with exponent $1$ for that generator and $0$ for all
% others.
% \begin{tcl}
named {
set res {}
foreach name [{*}$base elements] {
lappend res [::tcl::mathfunc::bool [
{*}$base = $name [lindex $args 0]
]]
}
return $res
}
% \end{tcl}
% It wouldn't be correct to merely |lsearch| for the wanted
% argument, as the set of generators is not required to be
% |onlycanonical|.
% \end{procmethod}
%
% \begin{procmethod}{namestructure}
% The base structure is made available via the |namestructure|
% method.
% \begin{tcl}
namestructure {uplevel 1 $base $args}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{* decomposition}
% The element decomposition is straightforward.
% \begin{tcl}
{* decomposition} {
set res {}
foreach name [{*}$base elements] exp [lindex $args 0] {
lappend res $name $exp
}
return $res
}
% \end{tcl}
% \end{procmethod}
%
% \begin{procmethod}{export}
% Not surprisingly, power products are exported as products of
% powers. The format is somewhat prolix in that it has a power
% for \emph{every} generator (even those with exponent $0$ or
% $1$), but it is easier to get rid of these than to reinsert
% them.
% \begin{tcl}
export {
lassign $args L attr
set pattr [dict replace $attr cd arith1 name power]
set mattr [dict replace $attr cd arith1 name times]
set battr $attr
dict lappend pattr mtmtcl:path ^
dict lappend mattr mtmtcl:path *
dict lappend battr mtmtcl:path namestructure
set pow [list OMS $pattr {}]
set childL [list [list OMS $mattr {}]]
foreach name [{*}$base elements] exponent $L {
lappend childL [list OMA $attr [list $pow [
{*}$base export $name $battr
] [
list integer [dict create value $exponent] {}
]]]
}