Ticket #10963: consistency.py

File consistency.py, 5.4 KB (added by SimonKing, 6 years ago)

A routine to test whether the default choice of axiomatic category constructions is consistent

Line 
1import inspect
2import sage.categories
3from sage.categories.category_with_axiom import CategoryWithAxiom, all_axioms
4from sage.categories.category import Category
5from sage.all import BooleanPolynomialRing
6
7visited = set([])
8
9def get_submodules_and_catclasses(M):
10    visited.add(M)
11    SubmoduleList = []
12    ClassList = []
13    for m in dir(M):
14        try:
15            S = getattr(M,m)
16        except StandardError:
17            continue
18        if inspect.ismodule(S) and S not in visited:
19            SubmoduleList.append(S)
20        elif inspect.isclass(S) and S not in visited:
21            if issubclass(S, Category):
22                ClassList.append(S)
23    return SubmoduleList, ClassList
24
25def all_category_classes(M):
26    SubmoduleList, ClassList = get_submodules_and_catclasses(M)
27    S = set(ClassList)
28    for subM in SubmoduleList+ClassList:
29        S = S.union(all_category_classes(subM))
30    return S
31
32def TestCategoryModel():
33    print "Import all category classes"
34    global visited
35    visited = set([])
36    AllClasses = all_category_classes(sage.categories)
37    BasicClasses = set([])
38    AxiomClasses = set([])
39    Ignorable = []
40    for C in AllClasses:
41        if issubclass(C, CategoryWithAxiom):
42            if not hasattr(C, '_base_category_class_and_axiom'):
43                #print "ignoring",C
44                continue
45            AxiomClasses.add(C)
46        elif issubclass(C, Category):
47            BasicClasses.add(C)
48    BasicClasses = tuple(sorted(BasicClasses))
49    AxiomClasses = tuple(sorted(AxiomClasses))
50    AllClasses = set(BasicClasses+AxiomClasses)
51    # The basic classes are those that have no axiom.
52    # In our model, they generate a boolean polynomial ring,
53    # multiplication given by the join of categories
54    print "Create boolean polynomial ring with",len(BasicClasses),"generators"
55    R = BooleanPolynomialRing(names=tuple(C.__name__.replace('.','_') for C in BasicClasses)+all_axioms)
56    # Now we collect all possible constructions of categories with axiom
57    print "Collect all available axiomatic constructions"
58    Constructions = dict((C,[]) for C in AxiomClasses)
59    for C in BasicClasses:
60        Constructions[C] = [R(C.__name__.replace('.','_'))]
61    StrangeResults = []
62    InstanceWarnings = []
63    while AllClasses:
64        C = AllClasses.pop()
65        if not Constructions[C]:
66            AllClasses.add(C)
67            continue
68        for A in all_axioms:
69            try:
70                X = getattr(C,A)
71            except AttributeError:
72                try:
73                    O = C.an_instance()
74                except StandardError:
75                    if C not in InstanceWarnings:
76                        #print "Warning: Can't get an instance of %s"%(C)
77                        InstanceWarnings.append(C)
78                    continue
79                if not isinstance(O, C):
80                    # Happens for Modules.an_instance()
81                    if C not in InstanceWarnings:
82                        InstanceWarnings.append(C)
83                    continue
84                try:
85                    X = getattr(O,A)().__class__.__base__
86                except AttributeError:
87                    continue
88                except StandardError:
89                    print "Warning: Can't apply %s to %s"%(A,C)
90                    continue
91            except StandardError, msg:
92                print "Warning",msg
93                continue
94            if X==C:
95                # The applied axiom is part of the original category
96                continue
97            if X not in AllClasses:
98                if not (inspect.isclass(X) and issubclass(X,Category)):
99                    #print "WARNING: Axiom %s on %s not yielding a category"%(A,C)
100                    StrangeResults.append((A,C))
101                    continue
102                else:
103                    AllClasses.add(X)
104                    Constructions[X] = []
105            try:
106                Constructions[X].append(Constructions[C][0]*R(A))
107            except StandardError:
108                print "Problem:"
109                print "  Base",C
110                print "  Axiom",A
111                print "  Result",X
112                raise
113    print " => Found",add(len(C) for C in Constructions.values()),"constructions for",len(Constructions),"category classes"
114    Relations = []
115    for con in Constructions.itervalues():
116        if len(con)>1:
117            for i in range(1,len(con)):
118                if con[0]!=con[i]:
119                    Relations.append(con[0]+con[i])
120    Relations = Relations*R
121    print
122    print len(Relations.gens()), "cases of alternative axiomatic constructions"
123    print "Testing that default constructions are compatible"
124    BadResults = []
125    for C in AxiomClasses:
126        try:
127            B,A = C._base_category_class_and_axiom
128        except StandardError:
129            print C,"has no _base_category_class_and_axiom"
130        b_monomial = Relations.reduce(Constructions[B][0])
131        c_monomial = b_monomial*R(A)
132        if c_monomial != Relations.reduce(c_monomial):
133            print "Bad:",C,"= %s.%s"%(B,A)
134            print "expected default", Relations.reduce(c_monomial)
135            print "got", c_monomial
136            print "Basis is given by", Relations.reduce(b_monomial)
137            print "but",Relations.reduce(b_monomial)*R(A),"is no standard monomial"
138            BadResults.append((C,c_monomial,Relations.reduce(c_monomial)))
139    return BadResults, InstanceWarnings, StrangeResults, Relations