Skip to content

Commit ba40387

Browse files
author
Release Manager
committed
gh-36865: `sage.groups`, `sage.rings.number_field`: Modularization fixes, `# needs` <!-- ^^^^^ Please provide a concise, informative and self-explanatory title. Don't put issue numbers in there, do this in the PR body below. For example, instead of "Fixes #1234" use "Introduce new method to calculate 1+1" --> <!-- Describe your changes here in detail --> - Cherry-picked from #35095 Standard modularization work: - a new dynamically detected feature `sage.libs.braiding` - using file-level and block-level `# needs` to simplify decorations - adding some `# needs`, in particular for `sage.libs.gap` - splitting GAP-dependent classes out from `sage.groups.galois_group` - using more `lazy_import`s - some doctest cosmetics <!-- Why is this change required? What problem does it solve? --> <!-- If this PR resolves an open issue, please link to it here. For example "Fixes #12345". --> Part of: - #29705 <!-- If your change requires a documentation PR, please link it appropriately. --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> <!-- If your change requires a documentation PR, please link it appropriately --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> <!-- Feel free to remove irrelevant items. --> - [x] The title is concise, informative, and self-explanatory. - [ ] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation accordingly. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on - #12345: short description why this is a dependency - #34567: ... --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> URL: #36865 Reported by: Matthias Köppe Reviewer(s): David Coudert
2 parents bfb861b + 1d77a49 commit ba40387

29 files changed

+419
-314
lines changed

src/sage/crypto/lattice.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None,
211211
[-4 -3 2 -5 0 0 0 0 0 1]
212212
]
213213
214-
sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, lattice=True)
214+
sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, lattice=True) # needs fpylll
215215
Free module of degree 10 and rank 10 over Integer Ring
216216
User basis matrix:
217217
[ 0 0 1 1 0 -1 -1 -1 1 0]

src/sage/features/sagemath.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,29 @@ def __init__(self):
311311
spkg='sagemath_groups', type='standard')
312312

313313

314+
class sage__libs__braiding(PythonModule):
315+
r"""
316+
A :class:`~sage.features.Feature` describing the presence of :mod:`sage.libs.braiding`.
317+
318+
EXAMPLES::
319+
320+
sage: from sage.features.sagemath import sage__libs__braiding
321+
sage: sage__libs__braiding().is_present() # needs sage.libs.braiding
322+
FeatureTestResult('sage.libs.braiding', True)
323+
"""
324+
325+
def __init__(self):
326+
r"""
327+
TESTS::
328+
329+
sage: from sage.features.sagemath import sage__libs__braiding
330+
sage: isinstance(sage__libs__braiding(), sage__libs__braiding)
331+
True
332+
"""
333+
PythonModule.__init__(self, 'sage.libs.braiding',
334+
spkg='sagemath_libbraiding', type='standard')
335+
336+
314337
class sage__libs__ecl(PythonModule):
315338
r"""
316339
A :class:`~sage.features.Feature` describing the presence of :mod:`sage.libs.ecl`.
@@ -330,7 +353,8 @@ def __init__(self):
330353
sage: isinstance(sage__libs__ecl(), sage__libs__ecl)
331354
True
332355
"""
333-
PythonModule.__init__(self, 'sage.libs.ecl')
356+
PythonModule.__init__(self, 'sage.libs.ecl',
357+
spkg='sagemath_symbolics', type='standard')
334358

335359

336360
class sage__libs__flint(JoinFeature):
@@ -1076,6 +1100,7 @@ def all_features():
10761100
sage__geometry__polyhedron(),
10771101
sage__graphs(),
10781102
sage__groups(),
1103+
sage__libs__braiding(),
10791104
sage__libs__ecl(),
10801105
sage__libs__flint(),
10811106
sage__libs__gap(),

src/sage/groups/abelian_gps/dual_abelian_group.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# sage.doctest: needs sage.rings.number_field
12
r"""
23
Dual groups of Finite Multiplicative Abelian Groups
34
@@ -25,7 +26,6 @@
2526
sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
2627
sage: (a, b, c, d, e) = F.gens()
2728
28-
sage: # needs sage.rings.number_field
2929
sage: Fd = F.dual_group(names='ABCDE')
3030
sage: Fd.base_ring()
3131
Cyclotomic Field of order 2520 and degree 576
@@ -82,7 +82,6 @@ def is_DualAbelianGroup(x):
8282
8383
EXAMPLES::
8484
85-
sage: # needs sage.rings.number_field
8685
sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup
8786
sage: F = AbelianGroup(5,[3,5,7,8,9], names=list("abcde"))
8887
sage: Fd = F.dual_group()
@@ -105,7 +104,7 @@ class DualAbelianGroup_class(UniqueRepresentation, AbelianGroupBase):
105104
EXAMPLES::
106105
107106
sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")
108-
sage: F.dual_group() # needs sage.rings.number_field
107+
sage: F.dual_group()
109108
Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
110109
over Cyclotomic Field of order 2520 and degree 576
111110
@@ -123,7 +122,7 @@ def __init__(self, G, names, base_ring):
123122
EXAMPLES::
124123
125124
sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")
126-
sage: F.dual_group() # needs sage.rings.number_field
125+
sage: F.dual_group()
127126
Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
128127
over Cyclotomic Field of order 2520 and degree 576
129128
"""
@@ -180,9 +179,9 @@ def _repr_(self):
180179
EXAMPLES::
181180
182181
sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
183-
sage: Fd = F.dual_group(names='ABCDE', # needs sage.rings.number_field
182+
sage: Fd = F.dual_group(names='ABCDE',
184183
....: base_ring=CyclotomicField(2*5*7*8*9))
185-
sage: Fd # indirect doctest # needs sage.rings.number_field
184+
sage: Fd # indirect doctest
186185
Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
187186
over Cyclotomic Field of order 5040 and degree 1152
188187
sage: Fd = F.dual_group(names='ABCDE', base_ring=CC) # needs sage.rings.real_mpfr
@@ -209,8 +208,8 @@ def _latex_(self):
209208
EXAMPLES::
210209
211210
sage: F = AbelianGroup(3, [2]*3)
212-
sage: Fd = F.dual_group() # needs sage.rings.number_field
213-
sage: Fd._latex_() # needs sage.rings.number_field
211+
sage: Fd = F.dual_group()
212+
sage: Fd._latex_()
214213
'$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, (2, 2, 2) ) )$'
215214
"""
216215
return r"$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$" % (self.ngens(), self.gens_orders())
@@ -251,7 +250,6 @@ def gen(self, i=0):
251250
252251
EXAMPLES::
253252
254-
sage: # needs sage.rings.number_field
255253
sage: F = AbelianGroup(3, [1,2,3], names='a')
256254
sage: Fd = F.dual_group(names="A")
257255
sage: Fd.0
@@ -279,8 +277,8 @@ def gens(self):
279277
280278
EXAMPLES::
281279
282-
sage: F = AbelianGroup([7,11]).dual_group() # needs sage.rings.number_field
283-
sage: F.gens() # needs sage.rings.number_field
280+
sage: F = AbelianGroup([7,11]).dual_group()
281+
sage: F.gens()
284282
(X0, X1)
285283
"""
286284
n = self.group().ngens()
@@ -293,8 +291,8 @@ def ngens(self):
293291
EXAMPLES::
294292
295293
sage: F = AbelianGroup([7]*100)
296-
sage: Fd = F.dual_group() # needs sage.rings.number_field
297-
sage: Fd.ngens() # needs sage.rings.number_field
294+
sage: Fd = F.dual_group()
295+
sage: Fd.ngens()
298296
100
299297
"""
300298
return self.group().ngens()
@@ -310,8 +308,8 @@ def gens_orders(self):
310308
EXAMPLES::
311309
312310
sage: F = AbelianGroup([5]*1000)
313-
sage: Fd = F.dual_group() # needs sage.rings.number_field
314-
sage: invs = Fd.gens_orders(); len(invs) # needs sage.rings.number_field
311+
sage: Fd = F.dual_group()
312+
sage: invs = Fd.gens_orders(); len(invs)
315313
1000
316314
"""
317315
return self.group().gens_orders()
@@ -325,8 +323,8 @@ def invariants(self):
325323
EXAMPLES::
326324
327325
sage: F = AbelianGroup([5]*1000)
328-
sage: Fd = F.dual_group() # needs sage.rings.number_field
329-
sage: invs = Fd.gens_orders(); len(invs) # needs sage.rings.number_field
326+
sage: Fd = F.dual_group()
327+
sage: invs = Fd.gens_orders(); len(invs)
330328
1000
331329
"""
332330
# TODO: deprecate
@@ -340,9 +338,9 @@ def __contains__(self, X):
340338
341339
sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
342340
sage: a,b,c,d,e = F.gens()
343-
sage: Fd = F.dual_group(names="ABCDE") # needs sage.rings.number_field
344-
sage: A,B,C,D,E = Fd.gens() # needs sage.rings.number_field
345-
sage: A*B^2*D^7 in Fd # needs sage.rings.number_field
341+
sage: Fd = F.dual_group(names="ABCDE")
342+
sage: A,B,C,D,E = Fd.gens()
343+
sage: A*B^2*D^7 in Fd
346344
True
347345
"""
348346
return X.parent() == self and is_DualAbelianGroupElement(X)
@@ -354,8 +352,8 @@ def order(self):
354352
EXAMPLES::
355353
356354
sage: G = AbelianGroup([2,3,9])
357-
sage: Gd = G.dual_group() # needs sage.rings.number_field
358-
sage: Gd.order() # needs sage.rings.number_field
355+
sage: Gd = G.dual_group()
356+
sage: Gd.order()
359357
54
360358
"""
361359
G = self.group()
@@ -368,10 +366,10 @@ def is_commutative(self):
368366
EXAMPLES::
369367
370368
sage: G = AbelianGroup([2,3,9])
371-
sage: Gd = G.dual_group() # needs sage.rings.number_field
372-
sage: Gd.is_commutative() # needs sage.rings.number_field
369+
sage: Gd = G.dual_group()
370+
sage: Gd.is_commutative()
373371
True
374-
sage: Gd.is_abelian() # needs sage.rings.number_field
372+
sage: Gd.is_abelian()
375373
True
376374
"""
377375
return True
@@ -384,8 +382,8 @@ def list(self):
384382
EXAMPLES::
385383
386384
sage: G = AbelianGroup([2,3], names="ab")
387-
sage: Gd = G.dual_group(names="AB") # needs sage.rings.number_field
388-
sage: Gd.list() # needs sage.rings.number_field
385+
sage: Gd = G.dual_group(names="AB")
386+
sage: Gd.list()
389387
(1, B, B^2, A, A*B, A*B^2)
390388
"""
391389
if not self.is_finite():
@@ -400,8 +398,8 @@ def __iter__(self):
400398
EXAMPLES::
401399
402400
sage: G = AbelianGroup([2,3], names="ab")
403-
sage: Gd = G.dual_group(names="AB") # needs sage.rings.number_field
404-
sage: [X for X in Gd] # needs sage.rings.number_field
401+
sage: Gd = G.dual_group(names="AB")
402+
sage: [X for X in Gd]
405403
[1, B, B^2, A, A*B, A*B^2]
406404
407405
sage: # needs sage.rings.real_mpfr

src/sage/groups/abelian_gps/dual_abelian_group_element.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# sage.doctest: needs sage.rings.number_field
12
"""
23
Elements (characters) of the dual group of a finite Abelian group
34
@@ -8,13 +9,12 @@
89
sage: F
910
Multiplicative Abelian group isomorphic to C2 x C3 x C5 x C7 x C8
1011
11-
sage: Fd = F.dual_group(names="ABCDE"); Fd # needs sage.rings.number_field
12+
sage: Fd = F.dual_group(names="ABCDE"); Fd
1213
Dual of Abelian Group isomorphic to Z/2Z x Z/3Z x Z/5Z x Z/7Z x Z/8Z
1314
over Cyclotomic Field of order 840 and degree 192
1415
1516
The elements of the dual group can be evaluated on elements of the original group::
1617
17-
sage: # needs sage.rings.number_field
1818
sage: a,b,c,d,e = F.gens()
1919
sage: A,B,C,D,E = Fd.gens()
2020
sage: A*B^2*D^7
@@ -71,10 +71,10 @@ def is_DualAbelianGroupElement(x) -> bool:
7171
EXAMPLES::
7272
7373
sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroupElement
74-
sage: F = AbelianGroup(5, [5,5,7,8,9], names=list("abcde")).dual_group() # needs sage.rings.number_field
75-
sage: is_DualAbelianGroupElement(F) # needs sage.rings.number_field
74+
sage: F = AbelianGroup(5, [5,5,7,8,9], names=list("abcde")).dual_group()
75+
sage: is_DualAbelianGroupElement(F)
7676
False
77-
sage: is_DualAbelianGroupElement(F.an_element()) # needs sage.rings.number_field
77+
sage: is_DualAbelianGroupElement(F.an_element())
7878
True
7979
"""
8080
return isinstance(x, DualAbelianGroupElement)
@@ -96,7 +96,6 @@ def __call__(self, g):
9696
9797
EXAMPLES::
9898
99-
sage: # needs sage.rings.number_field
10099
sage: F = AbelianGroup(5, [2,3,5,7,8], names="abcde")
101100
sage: a,b,c,d,e = F.gens()
102101
sage: Fd = F.dual_group(names="ABCDE")
@@ -147,7 +146,6 @@ def word_problem(self, words):
147146
148147
EXAMPLES::
149148
150-
sage: # needs sage.rings.number_field
151149
sage: G = AbelianGroup(5,[3, 5, 5, 7, 8], names="abcde")
152150
sage: Gd = G.dual_group(names="abcde")
153151
sage: a,b,c,d,e = Gd.gens()
@@ -156,7 +154,7 @@ def word_problem(self, words):
156154
sage: w = a^7*b^3*c^5*d^4*e^4
157155
sage: x = a^3*b^2*c^2*d^3*e^5
158156
sage: y = a^2*b^4*c^2*d^4*e^5
159-
sage: e.word_problem([u,v,w,x,y])
157+
sage: e.word_problem([u,v,w,x,y]) # needs sage.libs.gap
160158
[[b^2*c^2*d^3*e^5, 245]]
161159
"""
162160
from sage.libs.gap.libgap import libgap

src/sage/groups/affine_gps/affine_group.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,10 @@ def __init__(self, degree, ring):
204204
205205
sage: G = AffineGroup(2, GF(5)); G
206206
Affine Group of degree 2 over Finite Field of size 5
207+
208+
sage: # needs sage.libs.gap (for gens)
207209
sage: TestSuite(G).run()
210+
208211
sage: G.category()
209212
Category of finite groups
210213
@@ -289,8 +292,10 @@ def cardinality(self):
289292
290293
EXAMPLES::
291294
295+
sage: # needs sage.libs.gap
292296
sage: AffineGroup(6, GF(5)).cardinality()
293297
172882428468750000000000000000
298+
294299
sage: AffineGroup(6, ZZ).cardinality()
295300
+Infinity
296301
"""
@@ -464,6 +469,7 @@ def random_element(self):
464469
465470
EXAMPLES::
466471
472+
sage: # needs sage.libs.gap
467473
sage: G = AffineGroup(4, GF(3))
468474
sage: G.random_element() # random
469475
[2 0 1 2] [1]
@@ -498,6 +504,7 @@ def some_elements(self):
498504
499505
EXAMPLES::
500506
507+
sage: # needs sage.libs.gap
501508
sage: G = AffineGroup(4,5)
502509
sage: G.some_elements()
503510
[ [2 0 0 0] [1]

src/sage/groups/affine_gps/euclidean_group.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ class EuclideanGroup(AffineGroup):
146146
True
147147
sage: G = EuclideanGroup(2, GF(5)); G
148148
Euclidean Group of degree 2 over Finite Field of size 5
149+
150+
sage: # needs sage.libs.gap (for gens)
149151
sage: TestSuite(G).run()
150152
151153
REFERENCES:

src/sage/groups/affine_gps/group_element.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,14 @@ class AffineGroupElement(MultiplicativeGroupElement):
7878
EXAMPLES::
7979
8080
sage: G = AffineGroup(2, GF(3))
81+
82+
sage: # needs sage.libs.gap
8183
sage: g = G.random_element()
8284
sage: type(g)
8385
<class 'sage.groups.affine_gps.affine_group.AffineGroup_with_category.element_class'>
8486
sage: G(g.matrix()) == g
8587
True
88+
8689
sage: G(2)
8790
[2 0] [0]
8891
x |-> [0 2] x + [0]
@@ -107,6 +110,7 @@ def __init__(self, parent, A, b=0, convert=True, check=True):
107110
108111
TESTS::
109112
113+
sage: # needs sage.libs.gap
110114
sage: G = AffineGroup(4, GF(5))
111115
sage: g = G.random_element()
112116
sage: TestSuite(g).run()
@@ -200,6 +204,7 @@ def matrix(self):
200204
Composition of affine group elements equals multiplication of
201205
the matrices::
202206
207+
sage: # needs sage.libs.gap
203208
sage: g1 = G.random_element()
204209
sage: g2 = G.random_element()
205210
sage: g1.matrix() * g2.matrix() == (g1*g2).matrix()

src/sage/groups/braid.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,14 @@
7272
from sage.combinat.permutation import Permutation
7373
from sage.combinat.permutation import Permutations
7474
from sage.combinat.subset import Subsets
75-
from sage.features import PythonModule
75+
from sage.features.sagemath import sage__libs__braiding
7676
from sage.groups.artin import FiniteTypeArtinGroup, FiniteTypeArtinGroupElement
7777
from sage.groups.finitely_presented import FinitelyPresentedGroup
7878
from sage.groups.finitely_presented import GroupMorphismWithGensImages
7979
from sage.groups.free_group import FreeGroup, is_FreeGroup
8080
from sage.functions.generalized import sign
8181
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
8282
from sage.groups.perm_gps.permgroup_named import SymmetricGroupElement
83-
from sage.knots.knot import Knot
8483
from sage.libs.gap.libgap import libgap
8584
from sage.matrix.constructor import identity_matrix, matrix
8685
from sage.misc.lazy_attribute import lazy_attribute
@@ -98,7 +97,8 @@
9897
['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor',
9998
'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset',
10099
'thurston_type', 'rigidity', 'sliding_circuits'],
101-
feature=PythonModule('sage.libs.braiding', spkg='libbraiding', type='standard'))
100+
feature=sage__libs__braiding())
101+
lazy_import('sage.knots.knot', 'Knot')
102102

103103

104104
class Braid(FiniteTypeArtinGroupElement):

0 commit comments

Comments
 (0)