-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmmt.py
948 lines (801 loc) · 30.2 KB
/
mmt.py
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
# -*- coding: utf-8 -*-
"""
EXAMPLES::
sage: from mygap import mygap
sage: mygap.SymmetricGroup(3).an_element()
(1,2,3)
sage: G = Sp(4,GF(3))
sage: G.random_element() # random
[2 1 1 1]
[1 0 2 1]
[0 1 1 0]
[1 0 0 1]
sage: G.random_element() in G
True
sage: F = GF(5); MS = MatrixSpace(F,2,2)
sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]
sage: G = MatrixGroup(gens)
sage: G.random_element() # random
[1 3]
[0 3]
sage: G.random_element().parent() is G
True
Missing features
================
We would want to use F.random_element from ``Sets.GAP``, not
:class:`ModulesWithBasis` or :class:`FiniteEnumeratedSets`::
sage: F = mygap.FiniteField(3); F
GF(3)
sage: F in Fields().Finite().Enumerated().GAP()
True
sage: F.random_element.__module__
'sage.categories.modules_with_basis'
sage: F.random_element()
Traceback (most recent call last):
...
AttributeError: ...
Other issue: in GAP, a ring is considered as a free module over
itself, and GAP fields are set according to be modules over rings with
basis (see the IsFreeLeftModule)::
sage: from sage.categories.modules import Modules
sage: F in Modules(Rings()).WithBasis()
True
This is unlike Sage's fields::
sage: GF(3) in VectorSpaces(Fields()).WithBasis()
False
We would want to recover some of the semantic, notably the codomain,
from mmt:
>> namespace = XXXXX("u'http://latin.omdoc.org/math")
>> M = namespace.get_theory("Monoid")
>> u = M["universe"] # Return the type of the elements of monoids (MonoidElement?)
>> u = M["objects"] # Return the type of the monoids (Monoid)
>> u = M["morphism"] # Return the type of the monoid morphisms (MonoidMorphism)
>> u = M["homsets"] # Return the type of the monoid homsets (MonoidHomset)
>> e = M["e"] # Return the identity constant (note that e is not defined in Monoid but in NeutralElementLeft/Right)
e.return_type() # Returns the type of the codomain
>> e.return_type() == u
True
>> e.arity() # (or a way to recover it)
2
# Assume f is a function of type X -> (Y -> Z), then
>> f.return_type()
Z
>> f.argument_types()
[X,Y]
"""
import inspect
import itertools
import textwrap
from sage.misc.misc import attrcall
from functools import partial
from recursive_monkey_patch import monkey_patch
from sage.misc.abstract_method import abstract_method, AbstractMethod
from sage.categories.category import Category
from sage.categories.category_types import Category_over_base_ring
from sage.categories.category_with_axiom import CategoryWithAxiom
from sage.libs.gap.libgap import libgap
import sage.categories
import sage.sets.family
def mmt_lookup_signature(mmt_theory, mmt_name):
"""
EXAMPLES::
sage: from mmt import mmt_lookup_signature
sage: mmt_lookup_signature("Magma", u"∘") # not tested
([OMID[u'http://latin.omdoc.org/math?Universe?u'],
OMID[u'http://latin.omdoc.org/math?Universe?u']],
OMID[u'http://latin.omdoc.org/math?Universe?u'])
"""
from MMTPy.objects import path
from MMTPy.connection import qmtclient
from MMTPy.library.lf import wrappers
# Create a client to connect to MMT
q = qmtclient.QMTClient("http://localhost:8080/")
# This is the namespace of the LATIN Math library
latin_math = path.Path.parse("http://latin.omdoc.org")/"math"
# We will now retrieve the types of an operation within that archive
try:
# build the path to the constant, in this case "∘", and request its type via MMT
op_tp = q.getType(getattr(latin_math, mmt_theory)[mmt_name])
# next we can unpack this function type into a triple of
#(Type Variables, argument types, return type)
(op_bd, op_tps, op_rt) = wrappers.lf_unpack_function_types(op_tp)
return op_tps, op_rt
except StandardError:
return None
class MMTWrap:
def __init__(self,
mmt_name=None,
variant=None,
module=None):
self.mmt_name = mmt_name
self.variant = variant
import typing
from typing import Any, List, Iterator
def specialize(type, value):
"""
Return a callable type that takes a GAP handle and make
"""
if hasattr(type, "specialize"):
return type.specialize(value)
else:
return type
def from_handle(type):
if hasattr(type, "from_handle"):
return type.from_handle
else:
return type
def GenericMeta_specialize(self, value):
if self.__origin__ is None:
return self
return self.__origin__[specialize(self.__args__[0], value)]
typing.GenericMeta.specialize = GenericMeta_specialize
import mygap
def Any_from_handle(self, handle):
return mygap.GAP(handle)
typing._Any.from_handle = Any_from_handle
def Iterator_from_handle(cls, handle):
value_type = from_handle(cls.__args__[0])
return itertools.imap(value_type, mygap.GAPIterator(handle))
Iterator.from_handle = classmethod(Iterator_from_handle)
def Container_from_handle(cls, handle):
container_type = cls.__extra__
if cls.__args__ is None:
return container_type(handle)
value_type = from_handle(cls.__args__[0])
return container_type(value_type(x) for x in handle)
typing.Container.from_handle = classmethod(Container_from_handle)
class Family(typing.Sequence[typing.T]):
__slots__ = ()
__extra__ = sage.sets.family.TrivialFamily
Sage = attrcall("sage")
# Construct a dependent type from a callable value -> type
#
class DependentType(typing._TypingBase): # Singleton
__metaclass__ = typing.TypingMeta
__slots__ = ("name", "specialize")
def __init__(self, specialize, name):
self.name = name
self.specialize = specialize
def __instancecheck__(self, object):
raise TypeError("Unspecialized {} cannot be used with isinstance()".format(self))
def __repr__(self):
return self.name
Self = DependentType(lambda x: x, name="Self")
FacadeFor = DependentType(attrcall("facade_for"), name="FacadeFor")
ParentOfSelf = DependentType(attrcall("parent" ), name="ParentOfSelf")
class Facade(typing.Sequence[typing.T]):
@classmethod
def from_handle(cls, handle):
value_type = cls.__args__[0]
result = mygap.GAP(handle)
result._refine_category_(result.category().Facade())
result.facade_for = lambda: value_type
return result
"""
sage: Any
typing.Any
sage: Self
Self
sage: ParentOfSelf
ParentOfSelf
sage: from mmt import Family
sage: from typing import Iterator, Set, List
sage: Family[Iterator[Set[List[Self]]]]
mmt.Family[typing.Iterator[typing.Set[typing.List[Self]]]]
"""
def gap_handle(x):
"""
Return a low-level libgap handle to the corresponding GAP object.
EXAMPLES::
sage: from mygap import mygap
sage: from mmt import gap_handle
sage: h = libgap.GF(3)
sage: F = mygap(h)
sage: gap_handle(F) is h
True
sage: l = gap_handle([1,2,F])
sage: l
[ 1, 2, GF(3) ]
sage: l[0] == 1
True
sage: l[2] == h
True
.. TODO::
Maybe we just want, for x a glorified hand, libgap(x) to
return the corresponding low level handle
"""
from mygap import GAPObject
if isinstance(x, (list, tuple)):
return libgap([gap_handle(y) for y in x])
elif isinstance(x, GAPObject):
return x.gap()
else:
return libgap(x)
class MMTWrapMethod(MMTWrap):
"""
.. TODO:: add real tests
EXAMPLES::
sage: from mmt import MMTWrapMethod
sage: def zero(self):
....: pass
sage: f = MMTWrapMethod(zero, "0", gap_name="Zero")
sage: c = f.generate_code("NeutralElement")
sage: c
<function zero at ...>
"""
def __init__(self, f, mmt_name=None, gap_name=None, codomain=None, **options):
MMTWrap.__init__(self, mmt_name, **options)
self.__imfunc__= f
self.gap_name = gap_name
self.codomain = codomain
if isinstance(f, AbstractMethod):
f = f._f
argspec = sage.misc.sageinspect.sage_getargspec(f)
self.arity = len(argspec.args)
def generate_code(self, mmt_theory):
codomain = self.codomain
arity = self.arity
gap_name = self.gap_name
if gap_name is None: # codomain is None
signature = mmt_lookup_signature(mmt_theory, self.mmt_name)
if signature is not None:
domains, codomain = signature
arity = len(domains)
if self.arity is not None:
assert self.arity == arity
# TODO: cleanup this logic
if all(domain == codomain for domain in domains):
codomain = ParentOfSelf
assert self.codomain is None or codomain == self.codomain
assert arity is not None
assert gap_name is not None
if codomain is None:
codomain = Any
#assert isinstance(codomain, DependentType)
def wrapper_method(self, *args):
return from_handle(specialize(codomain, self))(getattr(libgap, gap_name)(*gap_handle((self,)+args)))
wrapper_method.__name__ = self.__imfunc__.__name__
wrapper_method.__doc__ = textwrap.dedent("""
Wrapper around GAP's method {}
arity: {}
codomain: {}
""").format(gap_name, arity, codomain)
return wrapper_method
nested_classes_of_categories = [
"ParentMethods",
"ElementMethods",
"MorphismMethods",
"SubcategoryMethods",
]
def generate_interface(cls, mmt=None, gap=None, gap_super=None, gap_sub=None, gap_negation=None):
"""
INPUT:
- ``cls`` -- the class of a category
- ``mmt`` -- a string naming an mmt theory
- ``gap`` -- a string naming a gap property/category
"""
# Fetch cls.GAP, creating it if needed
try:
# Can't use cls.GAP because of the binding behavior
GAP_cls = cls.__dict__['GAP']
except KeyError:
GAP_cls = type(cls.__name__+".GAP", (CategoryWithAxiom,), {})
GAP_cls.__module__ = cls.__module__
setattr(cls, 'GAP', GAP_cls)
# Store the semantic information for later use
cls._semantic={
'gap': gap,
'gap_sub': gap_sub,
'gap_super': gap_super,
'gap_negation': gap_negation,
'mmt': mmt,
}
# Fill the database mapping gap categories / properties to their
# corresponding (super) Sage categories
if gap_sub is None:
gap_sub = gap
if gap_sub is not None or gap_negation is not None:
def fill_allignment_database(cls, source=None):
assert issubclass(cls, Category)
import mygap
if gap_sub is not None:
mygap.gap_category_to_structure[gap_sub] = mygap.add(category=cls)
if gap_negation is not None:
mygap.false_properties_to_structure[gap_negation] = mygap.add(category=cls)
if issubclass(cls, Category):
fill_allignment_database(cls)
else:
# cls is a fake class whose content will be monkey patched to an actual category
# Delay the database filling until the monkey patching, so
# that will actually know the category class
cls._monkey_patch_hook = classmethod(fill_allignment_database)
# Recurse in nested classes
for name in nested_classes_of_categories:
try:
source = getattr(cls, name)
except AttributeError:
continue
# Fetch the corresponding class in cls.GAP, creating it if needed
try:
target = getattr(GAP_cls, name)
except AttributeError:
target = type(name, (), {})
setattr(GAP_cls, name, target)
nested_class_semantic = {}
for (key, method) in source.__dict__.items():
if key in {'__module__', '__doc__'}:
continue
assert isinstance(method, MMTWrapMethod)
nested_class_semantic[key] = {
"__imfunc__": method.__imfunc__,
"codomain" : method.codomain,
"gap_name" : method.gap_name,
"mmt_name" : method.mmt_name
}
setattr(target, key, method.generate_code(mmt))
setattr(source, key, method.__imfunc__)
source._semantic = nested_class_semantic
def semantic(mmt=None, variant=None, codomain=None, gap=None, gap_negation=None, gap_sub=None, gap_super=None):
def f(cls_or_function):
if inspect.isclass(cls_or_function):
cls = cls_or_function
generate_interface(cls, mmt=mmt, gap=gap, gap_negation=gap_negation, gap_sub=gap_sub, gap_super=gap_super)
return cls
else:
return MMTWrapMethod(cls_or_function,
mmt_name=mmt,
variant=variant,
codomain=codomain,
gap_name=gap)
return f
@semantic(mmt="Set")
class Sets:
class ParentMethods:
@semantic(gap="IsFinite", codomain=Sage)
@abstract_method
def is_finite(self):
pass
@semantic(gap="Size", codomain=Sage)
@abstract_method
def cardinality(self):
pass
@semantic(gap="Representative", codomain=Self)
@abstract_method
def _an_element_(self):
pass
@semantic(gap="Random", codomain=Self)
@abstract_method
def random_element(self):
pass
@semantic(mmt="TODO", gap="IsFinite")
class Finite:
class ParentMethods:
@semantic(gap="List", codomain=List[Self])
@abstract_method
def list(self):
pass
@semantic()
class Facade(CategoryWithAxiom):
class ParentMethods:
@semantic(gap="List", codomain=List[FacadeFor])
@abstract_method
def list(self):
pass
@semantic(gap_negation="IsFinite")
class Infinite:
pass
monkey_patch(Sets, sage.categories.sets_cat.Sets)
@semantic(mmt="TODO") # TODO gap=""????
class EnumeratedSets:
class ParentMethods:
@semantic(gap="Iterator", codomain=Iterator[Self])
@abstract_method
def __iter__(self):
pass
@semantic(gap_sub="IsList")
class Finite:
pass
@semantic()
class Facade(CategoryWithAxiom):
class ParentMethods:
@semantic(gap="Iterator", codomain=Iterator[FacadeFor])
@abstract_method
def __iter__(self):
pass
monkey_patch(EnumeratedSets, sage.categories.enumerated_sets.EnumeratedSets)
# class Lists:
# def super_categories(self):
# return EnumeratedSets().Finite()
# class ParentMethods:
# @semantic(gap="")
# @abstract_method
# def __getitem__(self):
# pass
@semantic(mmt="Magma", variant="additive")
class AdditiveMagmas:
class ElementMethods:
@semantic(mmt=u"∘", gap=r"\+", codomain=ParentOfSelf) #, operator="+")
@abstract_method
def _add_(self, other):
pass
@semantic(mmt="NeutralElement", variant="additive", gap="IsAdditiveMagmaWithZero")
class AdditiveUnital:
class ParentMethods:
# Defined in NeutralElementLeft
# - How to retrieve it?
# - How to detect that this is a method into self?
@semantic(mmt="neutral", gap="Zero", codomain=Self)
@abstract_method
def zero(self):
# Generates automatically in the XXX.GAP category
# def zero(self): return self(self.gap().Zero())
pass
class ElementMethods:
@semantic(gap=r"\-", codomain=ParentOfSelf)
@abstract_method
def _sub_(self, other):
# Generates automatically
# def _sub_(self,other): return self(gap.Subtract(self.gap(), other.gap()))
pass
# TODO: Check Additive Inverse
@semantic(gap="AdditiveInverse", codomain=ParentOfSelf)
@abstract_method
def __neg__(self):
# Generates automatically
# def _neg_(self): return self.parent()(self.gap().AdditiveInverse())
pass
@semantic(gap="IsAdditivelyCommutative")
class AdditiveCommutative:
pass
monkey_patch(AdditiveMagmas, sage.categories.additive_magmas.AdditiveMagmas)
@semantic(mmt="Magma", gap="IsMagma", variant="multiplicative")
class Magmas:
class ElementMethods:
@semantic(mmt="*", gap=r"\*", codomain=ParentOfSelf) #, operator="*"
@abstract_method
def _mul_(self, other):
pass
class ParentMethods:
one = semantic(mmt="neutral", gap="One", codomain=Self)(sage.categories.magmas.Magmas.Unital.ParentMethods.__dict__['one'])
@semantic(mmt="NeutralElement", gap="IsMagmaWithOne")
class Unital:
class ParentMethods:
# Defined in NeutralElementLeft
# - How to retrieve it?
# - How to detect that this is a method into self?
#one = semantic(mmt="neutral", gap="One", codomain=Self)(sage.categories.magmas.Magmas.Unital.ParentMethods.__dict__['one'])
#@abstract_method
#def one(self):
# # Generates automatically in the XXX.GAP category
# # def one(self): return self(self.gap().One())
# pass
pass
class ElementMethods:
@semantic(mmt="inverse", gap="Inverse", codomain=ParentOfSelf)
@abstract_method
def __invert__(self): # TODO: deal with "fail"
pass
@semantic(gap="IsMagmaWithInverses")
class Inverse:
pass
@semantic(gap="IsCommutative")
class Commutative:
pass
monkey_patch(Magmas, sage.categories.magmas.Magmas)
# In GAP, NearAdditiveMagma assumes associative and AdditiveMagma
# further assumes commutative.
@semantic(mmt="Semigroup", variant="additive", gap="IsNearAdditiveMagma")
class AdditiveSemigroups:
# Additive Magmas are always assumed to be associative and commutative in GAP
# Near Additive Magmas don't require commutativity
# See http://www.gap-system.org/Manuals/doc/ref/chap55.html
@semantic(gap="IsAdditiveMagma")
class AdditiveCommutative:
pass
# In principle this is redundant with isAdditiveMagmaWithZero
# specified above; however IsAdditiveMagmaWithZero does not
# necessarily appear in the categories of an additive gap monoid
@semantic(gap="IsNearAdditiveMagmaWithZero")
class AdditiveUnital:
@semantic(gap="IsNearAdditiveGroup")
class AdditiveInverse:
pass
monkey_patch(AdditiveSemigroups, sage.categories.additive_semigroups.AdditiveSemigroups)
@semantic(mmt="Semigroup", variant="multiplicative", gap="IsAssociative")
class Semigroups:
class ParentMethods:
@semantic(gap="GeneratorsOfSemigroup", codomain=Family[Self])
@abstract_method
def semigroup_generators(self):
pass
@semantic(gap="\/")
@abstract_method
def __truediv__(self, relations):
pass
@semantic(gap="IsLTrivial", codomain=bool)
@abstract_method
def is_l_trivial(self):
pass
@semantic(gap="IsRTrivial", codomain=bool)
@abstract_method
def is_r_trivial(self):
pass
@semantic(gap="IsDTrivial", codomain=bool)
@abstract_method
def is_d_trivial(self):
pass
@semantic()
class Finite:
class ParentMethods:
@semantic(gap="GreensJClasses", codomain=Facade[Facade[Self]])
@abstract_method
def j_classes(self):
pass
@semantic(gap="GreensLClasses", codomain=Facade[Facade[Self]])
@abstract_method
def l_classes(self):
pass
@semantic(gap="GreensRClasses", codomain=Facade[Facade[Self]])
@abstract_method
def r_classes(self):
pass
@semantic(gap="GreensDClasses", codomain=Facade[Facade[Self]])
@abstract_method
def d_classes(self):
pass
@semantic(gap="StructureDescriptionMaximalSubgroups")
@abstract_method
def structure_description_maximal_subgroups(self):
pass
@semantic(gap="StructureDescriptionSchutzenbergerGroups")
@abstract_method
def structure_description_schutzenberger_groups(self):
pass
@semantic(gap="IsomorphismTransformationSemigroup")
@abstract_method
def isomorphism_transformation_semigroup(self):
pass
@semantic(gap="IsMonoidAsSemigroup")
class Unital:
class ParentMethods:
@semantic(gap="GeneratorsOfMonoid", codomain=Family[Self])
@abstract_method
def monoid_generators(self):
pass
@semantic()
class Finite:
class ParentMethods:
@semantic(gap="IsomorphismTransformationMonoid")
@abstract_method
def isomorphism_transformation_monoid(self):
pass
monkey_patch(Semigroups, sage.categories.semigroups.Semigroups)
@semantic(gap="IsGreensClass")
class GreensClass(Category):
def super_categories(self):
return [sage.categories.sets_cat.Sets()]
class ParentMethods:
@semantic(gap="SchutzenbergerGroup")
def schutzenberger_group(self):
pass
@semantic(mmt="Group", variant="multiplicative")
class Groups:
class ParentMethods:
@semantic(gap="IsAbelian", codomain=Sage)
@abstract_method
def is_abelian(self):
pass
@semantic(gap="GeneratorsOfGroup", codomain=Family[Self])
@abstract_method
def group_generators(self):
pass
@semantic(gap="\/")
@abstract_method
def __truediv__(self, relators):
pass
monkey_patch(Groups, sage.categories.groups.Groups)
sage.categories.modules.Modules.WithBasis.FiniteDimensional # workaround: triggers the lazy import
@semantic(mmt="Modules")
class Modules:
@semantic(gap="IsFreeLeftModule") # TODO: check that this is exactly equivalent
class WithBasis:
@semantic(gap="IsFiniteDimensional")
class FiniteDimensional:
class ParentMethods:
@semantic(gap="Dimension", codomain=Sage)
@abstract_method # FIXME: this overrides ModulesWithBasis.ParentMethods.dimension
def dimension(self):
pass
# TODO: find an idiom when you want to specify the semantic of
# a method in a subcategory of where it's defined, and don't
# want to override the original
@semantic(gap="Basis", codomain=Family[Self])
@abstract_method
def basis_disabled(self):
pass
monkey_patch(Modules, sage.categories.modules.Modules)
from sage.categories.magmatic_algebras import MagmaticAlgebras
# This should be gap_super="IsJacobianRing", and we would need to
# recover the other filters "IsLieAlegbra" is composed of. This will
# do for now
@semantic(mmt="LieAlgebra", gap="IsJacobianRing")
class LieAlgebras(Category_over_base_ring):
r"""
A class for Lie algebras.
The implementation is as handles to GAP objects.
EXAMPLE::
sage: from mmt import LieAlgebras
sage: L = LieAlgebras(Rings()).GAP().example()
sage: L
<Lie algebra over Rationals, with 2 generators>
sage: L.category()
Category of finite dimensional g a p lie algebras with basis over rings
sage: Z = L.lie_center()
sage: Z
<Lie algebra of dimension 0 over Rationals>
sage: Z.category()
Category of finite finite dimensional commutative associative g a p lie algebras with basis over rings
sage: L # we know more after computing the center!
<Lie algebra of dimension 3 over Rationals>
sage: CZ = L.lie_centralizer(Z)
sage: CZ
<Lie algebra of dimension 3 over Rationals>
sage: CZ.category()
Category of finite dimensional g a p lie algebras with basis over rings
sage: CL = L.lie_centralizer(L)
sage: CL
<Lie algebra of dimension 0 over Rationals>
sage: NL = L.lie_normalizer(L)
sage: NL
<Lie algebra of dimension 3 over Rationals>
sage: NZ = L.lie_normalizer(Z)
sage: NZ
<Lie algebra of dimension 3 over Rationals>
sage: L.lie_derived_subalgebra()
<Lie algebra of dimension 3 over Rationals>
sage: L.lie_nilradical()
<Lie algebra of dimension 0 over Rationals>
sage: L.lie_solvable_radical()
<Lie algebra of dimension 0 over Rationals>
sage: L.cartan_subalgebra()
<Lie algebra of dimension 1 over Rationals>
sage: L.lie_derived_series()
[<Lie algebra of dimension 3 over Rationals>]
sage: L.lie_derived_series()[0]
<Lie algebra of dimension 3 over Rationals>
sage: L.lie_lower_central_series()
[<Lie algebra of dimension 3 over Rationals>]
sage: L.lie_upper_central_series()
[<Lie algebra over Rationals, with 0 generators>]
sage: L.is_lie_abelian()
False
sage: Z.is_lie_abelian()
True
sage: L.is_lie_nilpotent()
False
sage: L.is_lie_solvable()
False
sage: L.semi_simple_type()
'A1'
sage: L.chevalley_basis()
[ [ LieObject( [ [ 0, 1 ], [ 0, 0 ] ] ) ],
[ LieObject( [ [ 0, 0 ], [ 1, 0 ] ] ) ],
[ LieObject( [ [ 1, 0 ], [ 0, -1 ] ] ) ] ]
sage: L.root_system()
<mygap.GAPObject object at 0x...>
sage: L.root_system().gap()
<root system of rank 1>
sage: L.is_restricted_lie_algebra()
False
"""
def super_categories(self):
"""
EXAMPLES::
sage: from mmt import LieAlgebras
sage: LieAlgebras(Rings()).super_categories()
[Category of magmatic algebras over rings]
"""
return [MagmaticAlgebras(self.base_ring())]
class ParentMethods:
@semantic(mmt="TODO", gap="GeneratorsOfAlgebra", codomain=List[Self]) # TODO: tuple_of_self
@abstract_method
def lie_algebra_generators(self):
r"""
Return generators for this Lie algebra.
OUTPUT:
A tuple of elements of ``self``
EXAMPLES::
sage: from mmt import LieAlgebras
sage: L = LieAlgebras(Rings()).GAP().example()
sage: a, b = L.lie_algebra_generators()
sage: a, b
(LieObject( [ [ 0, 1 ],
[ 0, 0 ] ] ),
LieObject( [ [ 0, 0 ],
[ 1, 0 ] ] ))
"""
# return tuple(self(handle) for handle in self.gap().GeneratorsOfAlgebra())
pass
@semantic(mmt="TODO", gap="LieCentre") # TODO: codomain
def lie_center(self):
pass
@semantic(mmt="TODO", gap="LieCentralizer") # TODO: codomain
def lie_centralizer(self, S):
pass
@semantic(mmt="TODO", gap="LieNormalizer") # TODO: codomain
def lie_normalizer(self, U):
pass
@semantic(mmt="TODO", gap="LieDerivedSubalgebra") # TODO: codomain
def lie_derived_subalgebra():
pass
@semantic(mmt="TODO", gap="LieNilRadical") # TODO: codomain
def lie_nilradical():
pass
@semantic(mmt="TODO", gap="LieSolvableRadical") # TODO: codomain
def lie_solvable_radical():
pass
@semantic(mmt="TODO", gap="CartanSubalgebra") # TODO: codomain
def cartan_subalgebra():
pass
@semantic(mmt="TODO", gap="LieDerivedSeries", codomain=List)
def lie_derived_series():
pass
@semantic(mmt="TODO", gap="LieLowerCentralSeries", codomain=List)
def lie_lower_central_series():
pass
@semantic(mmt="TODO", gap="LieUpperCentralSeries", codomain=List)
def lie_upper_central_series():
pass
@semantic(mmt="TODO", gap="IsLieAbelian", codomain=bool)
def is_lie_abelian():
pass
@semantic(mmt="TODO", gap="IsLieNilpotent", codomain=bool)
def is_lie_nilpotent():
pass
@semantic(mmt="TODO", gap="IsLieSolvable", codomain=bool)
def is_lie_solvable():
pass
@semantic(mmt="TODO", gap="SemiSimpleType", codomain=Sage)
def semi_simple_type():
pass
# TODO: so far the 2 following methods return GAP objects
@semantic(mmt="TODO", gap="ChevalleyBasis") # TODO: codomain
def chevalley_basis():
pass
@semantic(mmt="TODO", gap="RootSystem") # TODO: codomain
def root_system():
pass
@semantic(mmt="TODO", gap="IsRestrictedLieAlgebra", codomain=bool)
def is_restricted_lie_algebra():
pass
class ElementMethods:
pass
class GAP(CategoryWithAxiom):
def example(self):
r"""
Return an example of Lie algebra.
EXAMPLE::
sage: from mmt import LieAlgebras
sage: LieAlgebras(Rings()).GAP().example()
<Lie algebra over Rationals, with 2 generators>
"""
from mygap import mygap
from sage.matrix.constructor import matrix
from sage.rings.rational_field import QQ
a = matrix([[0, 1],
[0, 0]])
b = matrix([[0, 0],
[1, 0]])
return mygap.LieAlgebra( QQ, [a, b] )
class Category_over_base_ring:
@classmethod
def an_instance(cls):
return cls(sage.categories.rings.Rings())
monkey_patch(Category_over_base_ring, sage.categories.category_types.Category_over_base_ring)
@semantic()
class Fields:
@semantic(gap="Characteristic", codomain=Sage)
@abstract_method
def characteristic(self):
pass
monkey_patch(Fields, sage.categories.fields.Fields)