From 1e9d096aa8ceb0dea200f47a693fbc0f7f0faa05 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 16:19:22 -0700 Subject: [PATCH 01/18] sage.groups.matrix_gps: Move ..._gap classes to separate ..._gap modules --- .../groups/matrix_gps/finitely_generated.py | 858 +----------------- .../matrix_gps/finitely_generated_gap.py | 853 +++++++++++++++++ src/sage/groups/matrix_gps/linear.py | 23 +- src/sage/groups/matrix_gps/linear_gap.py | 23 + src/sage/groups/matrix_gps/matrix_group.py | 259 +----- .../groups/matrix_gps/matrix_group_gap.py | 291 ++++++ src/sage/groups/matrix_gps/named_group.py | 43 +- src/sage/groups/matrix_gps/named_group_gap.py | 44 + src/sage/groups/matrix_gps/orthogonal.py | 121 +-- src/sage/groups/matrix_gps/orthogonal_gap.py | 125 +++ src/sage/groups/matrix_gps/symplectic.py | 47 +- src/sage/groups/matrix_gps/symplectic_gap.py | 51 ++ src/sage/groups/matrix_gps/unitary.py | 40 - src/sage/groups/matrix_gps/unitary_gap.py | 48 + 14 files changed, 1447 insertions(+), 1379 deletions(-) create mode 100644 src/sage/groups/matrix_gps/finitely_generated_gap.py create mode 100644 src/sage/groups/matrix_gps/linear_gap.py create mode 100644 src/sage/groups/matrix_gps/matrix_group_gap.py create mode 100644 src/sage/groups/matrix_gps/named_group_gap.py create mode 100644 src/sage/groups/matrix_gps/orthogonal_gap.py create mode 100644 src/sage/groups/matrix_gps/symplectic_gap.py create mode 100644 src/sage/groups/matrix_gps/unitary_gap.py diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index e177b180840..229c4d0af07 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -77,8 +77,8 @@ from sage.rings.number_field.number_field import CyclotomicField from sage.combinat.integer_vector import IntegerVectors -from sage.groups.matrix_gps.matrix_group import (MatrixGroup_generic, - MatrixGroup_gap) +from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic +from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap from sage.groups.matrix_gps.group_element import is_MatrixGroupElement @@ -474,857 +474,3 @@ def _test_matrix_generators(self, **options): tester = self._tester(**options) for g,h in zip(self.gens(), MatrixGroup(self.gens()).gens()): tester.assertEqual(g.matrix(), h.matrix()) - -################################################################### -# -# Matrix group over a ring that GAP understands -# -################################################################### - - -class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap): - """ - Matrix group generated by a finite number of matrices. - - EXAMPLES:: - - sage: m1 = matrix(GF(11), [[1,2],[3,4]]) - sage: m2 = matrix(GF(11), [[1,3],[10,0]]) - sage: G = MatrixGroup(m1, m2); G - Matrix group over Finite Field of size 11 with 2 generators ( - [1 2] [ 1 3] - [3 4], [10 0] - ) - sage: type(G) - - sage: TestSuite(G).run() - """ - - def __reduce__(self): - """ - Implement pickling. - - EXAMPLES:: - - sage: m1 = matrix(QQ, [[1,2],[3,4]]) - sage: m2 = matrix(QQ, [[1,3],[-1,0]]) - sage: loads(MatrixGroup(m1, m2).dumps()) - Matrix group over Rational Field with 2 generators ( - [1 2] [ 1 3] - [3 4], [-1 0] - ) - """ - return (MatrixGroup, - tuple(g.matrix() for g in self.gens()) + ({'check':False},)) - - def as_permutation_group(self, algorithm=None, seed=None): - r""" - Return a permutation group representation for the group. - - In most cases occurring in practice, this is a permutation - group of minimal degree (the degree being determined from - orbits under the group action). When these orbits are hard to - compute, the procedure can be time-consuming and the degree - may not be minimal. - - INPUT: - - - ``algorithm`` -- ``None`` or ``'smaller'``. In the latter - case, try harder to find a permutation representation of - small degree. - - ``seed`` -- ``None`` or an integer specifying the seed - to fix results depending on pseudo-random-numbers. Here - it makes sense to be used with respect to the ``'smaller'`` - option, since gap produces random output in that context. - - OUTPUT: - - A permutation group isomorphic to ``self``. The - ``algorithm='smaller'`` option tries to return an isomorphic - group of low degree, but is not guaranteed to find the - smallest one and must not even differ from the one obtained - without the option. In that case repeating the invocation - may help (see the example below). - - EXAMPLES:: - - sage: MS = MatrixSpace(GF(2), 5, 5) - sage: A = MS([[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0]]) - sage: G = MatrixGroup([A]) - sage: G.as_permutation_group().order() - 2 - - A finite subgroup of GL(12,Z) as a permutation group:: - - sage: imf = libgap.function_factory('ImfMatrixGroup') - sage: GG = imf( 12, 3 ) - sage: G = MatrixGroup(GG.GeneratorsOfGroup()) - sage: G.cardinality() - 21499084800 - sage: P = G.as_permutation_group() - sage: Psmaller = G.as_permutation_group(algorithm="smaller", seed=6) - sage: P == Psmaller # see the note below - True - sage: Psmaller = G.as_permutation_group(algorithm="smaller") - sage: P == Psmaller - False - sage: P.cardinality() - 21499084800 - sage: P.degree() - 144 - sage: Psmaller.cardinality() - 21499084800 - sage: Psmaller.degree() - 80 - - .. NOTE:: - - In this case, the "smaller" option returned an isomorphic - group of lower degree. The above example used GAP's library - of irreducible maximal finite ("imf") integer matrix groups - to construct the MatrixGroup G over GF(7). The section - "Irreducible Maximal Finite Integral Matrix Groups" in the - GAP reference manual has more details. - - .. NOTE:: - - Concerning the option ``algorithm='smaller'`` you should note - the following from GAP documentation: "The methods used might - involve the use of random elements and the permutation - representation (or even the degree of the representation) is - not guaranteed to be the same for different calls of - SmallerDegreePermutationRepresentation." - - To obtain a reproducible result the optional argument ``seed`` - may be used as in the example above. - - TESTS:: - - sage: A = matrix(QQ, 2, [0, 1, 1, 0]) - sage: B = matrix(QQ, 2, [1, 0, 0, 1]) - sage: a, b = MatrixGroup([A, B]).as_permutation_group().gens() - sage: a.order(), b.order() - (2, 1) - - The above example in GL(12,Z), reduced modulo 7:: - - sage: MS = MatrixSpace(GF(7), 12, 12) - sage: G = MatrixGroup([MS(g) for g in GG.GeneratorsOfGroup()]) - sage: G.cardinality() - 21499084800 - sage: P = G.as_permutation_group() - sage: P.cardinality() - 21499084800 - - Check that large degree is still working:: - - sage: Sp(6,3).as_permutation_group().cardinality() - 9170703360 - - Check that :trac:`25706` still works after :trac:`26903`:: - - sage: MG = GU(3,2).as_matrix_group() - sage: PG = MG.as_permutation_group() - sage: mg = MG.an_element() - sage: PG(mg).order() # particular element depends on the set of GAP packages installed - 6 - """ - # Note that the output of IsomorphismPermGroup() depends on - # memory locations and will change if you change the order of - # doctests and/or architecture - from sage.groups.perm_gps.permgroup import PermutationGroup - if not self.is_finite(): - raise NotImplementedError("group must be finite") - if seed is not None: - from sage.libs.gap.libgap import libgap - libgap.set_seed(ZZ(seed)) - iso = self._libgap_().IsomorphismPermGroup() - if algorithm == "smaller": - iso = iso.Image().SmallerDegreePermutationRepresentation() - return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), - canonicalize=False) - - def module_composition_factors(self, algorithm=None): - r""" - Return a list of triples consisting of [base field, dimension, - irreducibility], for each of the Meataxe composition factors - modules. The ``algorithm="verbose"`` option returns more information, - but in Meataxe notation. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,4,4) - sage: M = MS(0) - sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1 - sage: G = MatrixGroup([M]) - sage: G.module_composition_factors() - [(Finite Field of size 3, 1, True), - (Finite Field of size 3, 1, True), - (Finite Field of size 3, 2, True)] - sage: F = GF(7); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])] - sage: G = MatrixGroup(gens) - sage: G.module_composition_factors() - [(Finite Field of size 7, 2, True)] - - Type ``G.module_composition_factors(algorithm='verbose')`` to get a - more verbose version. - - For more on MeatAxe notation, see - https://www.gap-system.org/Manuals/doc/ref/chap69.html - """ - from sage.libs.gap.libgap import libgap - F = self.base_ring() - if not F.is_finite(): - raise NotImplementedError("base ring must be finite") - n = self.degree() - MS = MatrixSpace(F, n, n) - mats = [MS(g.matrix()) for g in self.gens()] - # initializing list of mats by which the gens act on self - mats_gap = libgap(mats) - M = mats_gap.GModuleByMats(F) - compo = libgap.function_factory('MTX.CompositionFactors') - MCFs = compo(M) - if algorithm == "verbose": - print(str(MCFs) + "\n") - return sorted((MCF['field'].sage(), - MCF['dimension'].sage(), - MCF['IsIrreducible'].sage()) for MCF in MCFs) - - def invariant_generators(self): - r""" - Return invariant ring generators. - - Computes generators for the polynomial ring - `F[x_1,\ldots,x_n]^G`, where `G` in `GL(n,F)` is a finite matrix - group. - - In the "good characteristic" case the polynomials returned - form a minimal generating set for the algebra of `G`-invariant - polynomials. In the "bad" case, the polynomials returned - are primary and secondary invariants, forming a not - necessarily minimal generating set for the algebra of - `G`-invariant polynomials. - - ALGORITHM: - - Wraps Singular's ``invariant_algebra_reynolds`` and ``invariant_ring`` - in ``finvar.lib``. - - EXAMPLES:: - - sage: F = GF(7); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])] - sage: G = MatrixGroup(gens) - sage: G.invariant_generators() - [x1^7*x2 - x1*x2^7, - x1^12 - 2*x1^9*x2^3 - x1^6*x2^6 + 2*x1^3*x2^9 + x2^12, - x1^18 + 2*x1^15*x2^3 + 3*x1^12*x2^6 + 3*x1^6*x2^12 - 2*x1^3*x2^15 + x2^18] - - sage: q = 4; a = 2 - sage: MS = MatrixSpace(QQ, 2, 2) - sage: gen1 = [[1/a,(q-1)/a],[1/a, -1/a]]; gen2 = [[1,0],[0,-1]]; gen3 = [[-1,0],[0,1]] - sage: G = MatrixGroup([MS(gen1),MS(gen2),MS(gen3)]) - sage: G.cardinality() - 12 - sage: G.invariant_generators() - [x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6] - - sage: F = CyclotomicField(8) - sage: z = F.gen() - sage: a = z+1/z - sage: b = z^2 - sage: MS = MatrixSpace(F,2,2) - sage: g1 = MS([[1/a, 1/a], [1/a, -1/a]]) - sage: g2 = MS([[-b, 0], [0, b]]) - sage: G = MatrixGroup([g1,g2]) - sage: G.invariant_generators() - [x1^4 + 2*x1^2*x2^2 + x2^4, - x1^5*x2 - x1*x2^5, - x1^8 + 28/9*x1^6*x2^2 + 70/9*x1^4*x2^4 + 28/9*x1^2*x2^6 + x2^8] - - AUTHORS: - - - David Joyner, Simon King and Martin Albrecht. - - REFERENCES: - - - Singular reference manual - - - [Stu1993]_ - - - S. King, "Minimal Generating Sets of non-modular invariant - rings of finite groups", :arxiv:`math/0703035`. - """ - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.interfaces.singular import singular - gens = self.gens() - singular.LIB("finvar.lib") - n = self.degree() # len((gens[0].matrix()).rows()) - F = self.base_ring() - q = F.characteristic() - # test if the field is admissible - if F.gen() == 1: # we got the rationals or GF(prime) - FieldStr = str(F.characteristic()) - elif hasattr(F,'polynomial'): # we got an algebraic extension - if len(F.gens()) > 1: - raise NotImplementedError("can only deal with finite fields and (simple algebraic extensions of) the rationals") - FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen())) - else: # we have a transcendental extension - FieldStr = '(%d,%s)' % (F.characteristic(), - ','.join(str(p) for p in F.gens())) - - # Setting Singular's variable names - # We need to make sure that field generator and variables get different names. - if str(F.gen())[0] == 'x': - VarStr = 'y' - else: - VarStr = 'x' - VarNames = '(' + ','.join((VarStr+str(i) for i in range(1, n+1)))+')' - # The function call and affectation below have side-effects. Do not remove! - # (even if pyflakes say so) - R = singular.ring(FieldStr, VarNames, 'dp') - if hasattr(F, 'polynomial') and F.gen() != 1: - # we have to define minpoly - singular.eval('minpoly = '+str(F.polynomial()).replace('x',str(F.gen()))) - A = [singular.matrix(n,n,str((x.matrix()).list())) for x in gens] - Lgens = ','.join((x.name() for x in A)) - PR = PolynomialRing(F, n, [VarStr+str(i) for i in range(1,n+1)]) - - if q == 0 or (q > 0 and self.cardinality() % q): - from sage.all import Matrix - try: - elements = [g.matrix() for g in self.list()] - except (TypeError, ValueError): - elements - if elements is not None: - ReyName = 't'+singular._next_var_name() - singular.eval('matrix %s[%d][%d]' % (ReyName, - self.cardinality(), n)) - for i in range(1,self.cardinality()+1): - M = Matrix(F, elements[i-1]) - D = [{} for foobar in range(self.degree())] - for x,y in M.dict().items(): - D[x[0]][x[1]] = y - for row in range(self.degree()): - for t in D[row].items(): - singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' - % (ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1)) - IRName = 't'+singular._next_var_name() - singular.eval('matrix %s = invariant_algebra_reynolds(%s)' % (IRName,ReyName)) - else: - ReyName = 't'+singular._next_var_name() - singular.eval('list %s=group_reynolds((%s))' % (ReyName, Lgens)) - IRName = 't'+singular._next_var_name() - singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' % (IRName, ReyName)) - - OUT = [singular.eval(IRName+'[1,%d]' % (j)) - for j in range(1, 1+int(singular('ncols('+IRName+')')))] - return [PR(gen) for gen in OUT] - if self.cardinality() % q == 0: - PName = 't' + singular._next_var_name() - SName = 't' + singular._next_var_name() - singular.eval('matrix %s,%s=invariant_ring(%s)' % (PName, SName, Lgens)) - OUT = [singular.eval(PName+'[1,%d]' % (j)) - for j in range(1,1+singular('ncols('+PName+')'))] - OUT += [singular.eval(SName+'[1,%d]' % (j)) - for j in range(2,1+singular('ncols('+SName+')'))] - return [PR(gen) for gen in OUT] - - def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): - r""" - Compute the Molien series of this finite group with respect to the - character ``chi``. It can be returned either as a rational function - in one variable or a power series in one variable. The base field - must be a finite field, the rationals, or a cyclotomic field. - - Note that the base field characteristic cannot divide the group - order (i.e., the non-modular case). - - ALGORITHM: - - For a finite group `G` in characteristic zero we construct the Molien series as - - .. MATH:: - - \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\text{det}(I-tg)}, - - where `I` is the identity matrix and `t` an indeterminate. - - For characteristic `p` not dividing the order of `G`, let `k` be the base field - and `N` the order of `G`. Define `\lambda` as a primitive `N`-th root of unity over `k` - and `\omega` as a primitive `N`-th root of unity over `\QQ`. For each `g \in G` - define `k_i(g)` to be the positive integer such that - `e_i = \lambda^{k_i(g)}` for each eigenvalue `e_i` of `g`. Then the Molien series - is computed as - - .. MATH:: - - \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\prod_{i=1}^n(1 - t\omega^{k_i(g)})}, - - where `t` is an indeterminant. [Dec1998]_ - - INPUT: - - - ``chi`` -- (default: trivial character) a linear group character of this group - - - ``return_series`` -- boolean (default: ``True``) if ``True``, then returns - the Molien series as a power series, ``False`` as a rational function - - - ``prec`` -- integer (default: 20); power series default precision - - - ``variable`` -- string (default: ``'t'``); Variable name for the Molien series - - OUTPUT: single variable rational function or power series with integer coefficients - - EXAMPLES:: - - sage: MatrixGroup(matrix(QQ,2,2,[1,1,0,1])).molien_series() - Traceback (most recent call last): - ... - NotImplementedError: only implemented for finite groups - sage: MatrixGroup(matrix(GF(3),2,2,[1,1,0,1])).molien_series() - Traceback (most recent call last): - ... - NotImplementedError: characteristic cannot divide group order - - Tetrahedral Group:: - - sage: K. = CyclotomicField(4) - sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) - sage: Tetra.molien_series(prec=30) - 1 + t^8 + 2*t^12 + t^16 + 2*t^20 + 3*t^24 + 2*t^28 + O(t^30) - sage: mol = Tetra.molien_series(return_series=False); mol - (t^8 - t^4 + 1)/(t^16 - t^12 - t^4 + 1) - sage: mol.parent() - Fraction Field of Univariate Polynomial Ring in t over Integer Ring - sage: chi = Tetra.character(Tetra.character_table()[1]) - sage: Tetra.molien_series(chi, prec=30, variable='u') - u^6 + u^14 + 2*u^18 + u^22 + 2*u^26 + 3*u^30 + 2*u^34 + O(u^36) - sage: chi = Tetra.character(Tetra.character_table()[2]) - sage: Tetra.molien_series(chi) - t^10 + t^14 + t^18 + 2*t^22 + 2*t^26 + O(t^30) - - :: - - sage: S3 = MatrixGroup(SymmetricGroup(3)) - sage: mol = S3.molien_series(prec=10); mol - 1 + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 7*t^6 + 8*t^7 + 10*t^8 + 12*t^9 + O(t^10) - sage: mol.parent() - Power Series Ring in t over Integer Ring - - Octahedral Group:: - - sage: K. = CyclotomicField(8) - sage: a = v-v^3 #sqrt(2) - sage: i = v^2 - sage: Octa = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [(1+i)/a,0, 0,(1-i)/a]) - sage: Octa.molien_series(prec=30) - 1 + t^8 + t^12 + t^16 + t^18 + t^20 + 2*t^24 + t^26 + t^28 + O(t^30) - - Icosahedral Group:: - - sage: K. = CyclotomicField(10) - sage: z5 = v^2 - sage: i = z5^5 - sage: a = 2*z5^3 + 2*z5^2 + 1 #sqrt(5) - sage: Ico = MatrixGroup([[z5^3,0, 0,z5^2], [0,1, -1,0], [(z5^4-z5)/a, (z5^2-z5^3)/a, (z5^2-z5^3)/a, -(z5^4-z5)/a]]) - sage: Ico.molien_series(prec=40) - 1 + t^12 + t^20 + t^24 + t^30 + t^32 + t^36 + O(t^40) - - :: - - sage: G = MatrixGroup(CyclicPermutationGroup(3)) - sage: chi = G.character(G.character_table()[1]) - sage: G.molien_series(chi, prec=10) - t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 9*t^6 + 12*t^7 + 15*t^8 + 18*t^9 + 22*t^10 + O(t^11) - - :: - - sage: K = GF(5) - sage: S = MatrixGroup(SymmetricGroup(4)) - sage: G = MatrixGroup([matrix(K,4,4,[K(y) for u in m.list() for y in u])for m in S.gens()]) - sage: G.molien_series(return_series=False) - 1/(t^10 - t^9 - t^8 + 2*t^5 - t^2 - t + 1) - - :: - - sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) - sage: chi = G.character(G.character_table()[4]) - sage: G.molien_series(chi) - 3*t^5 + 6*t^11 + 9*t^17 + 12*t^23 + O(t^25) - """ - if not self.is_finite(): - raise NotImplementedError("only implemented for finite groups") - if chi is None: - chi = self.trivial_character() - M = self.matrix_space() - R = FractionField(self.base_ring()) - N = self.order() - if R.characteristic() == 0: - P = PolynomialRing(R, variable) - t = P.gen() - # it is possible the character is over a larger cyclotomic field - K = chi.values()[0].parent() - if K.degree() != 1: - if R.degree() != 1: - L = K.composite_fields(R)[0] - else: - L = K - else: - L = R - mol = P(0) - for g in self: - mol += L(chi(g)) / (M.identity_matrix()-t*g.matrix()).det().change_ring(L) - elif R.characteristic().divides(N): - raise NotImplementedError("characteristic cannot divide group order") - else: # char p>0 - # find primitive Nth roots of unity over base ring and QQ - F = cyclotomic_polynomial(N).change_ring(R) - w = F.roots(ring=R.algebraic_closure(), multiplicities=False)[0] - # don't need to extend further in this case since the order of - # the roots of unity in the character divide the order of the group - L = CyclotomicField(N, 'v') - v = L.gen() - # construct Molien series - P = PolynomialRing(L, variable) - t = P.gen() - mol = P(0) - for g in self: - # construct Phi - phi = L(chi(g)) - for e in g.matrix().eigenvalues(): - # find power such that w**n = e - n = 1 - while w**n != e and n < N+1: - n += 1 - # raise v to that power - phi *= (1-t*v**n) - mol += P(1)/phi - # We know the coefficients will be integers - mol = mol.numerator().change_ring(ZZ) / mol.denominator().change_ring(ZZ) - # divide by group order - mol /= N - if return_series: - PS = PowerSeriesRing(ZZ, variable, default_prec=prec) - return PS(mol) - return mol - - def reynolds_operator(self, poly, chi=None): - r""" - Compute the Reynolds operator of this finite group `G`. - - This is the projection from a polynomial ring to the ring of - relative invariants [Stu1993]_. If possible, the invariant is - returned defined over the base field of the given polynomial - ``poly``, otherwise, it is returned over the compositum of the - fields involved in the computation. - Only implemented for absolute fields. - - ALGORITHM: - - Let `K[x]` be a polynomial ring and `\chi` a linear character for `G`. Let - - .. MATH: - - K[x]^G_{\chi} = \{f \in K[x] | \pi f = \chi(\pi) f \forall \pi\in G\} - - be the ring of invariants of `G` relative to `\chi`. Then the Reynold's operator - is a map `R` from `K[x]` into `K[x]^G_{\chi}` defined by - - .. MATH: - - f \mapsto \frac{1}{|G|} \sum_{ \pi \in G} \chi(\pi) f. - - INPUT: - - - ``poly`` -- a polynomial - - - ``chi`` -- (default: trivial character) a linear group character of this group - - OUTPUT: an invariant polynomial relative to `\chi` - - AUTHORS: - - Rebecca Lauren Miller and Ben Hutz - - EXAMPLES:: - - sage: S3 = MatrixGroup(SymmetricGroup(3)) - sage: R. = QQ[] - sage: f = x*y*z^3 - sage: S3.reynolds_operator(f) - 1/3*x^3*y*z + 1/3*x*y^3*z + 1/3*x*y*z^3 - - :: - - sage: G = MatrixGroup(CyclicPermutationGroup(4)) - sage: chi = G.character(G.character_table()[3]) - sage: K. = CyclotomicField(4) - sage: R. = K[] - sage: G.reynolds_operator(x, chi) - 1/4*x + (1/4*v)*y - 1/4*z + (-1/4*v)*w - sage: chi = G.character(G.character_table()[2]) - sage: R. = QQ[] - sage: G.reynolds_operator(x*y, chi) - 1/4*x*y + (-1/4*zeta4)*y*z + (1/4*zeta4)*x*w - 1/4*z*w - - :: - - sage: K. = CyclotomicField(4) - sage: G = MatrixGroup(CyclicPermutationGroup(3)) - sage: chi = G.character(G.character_table()[1]) - sage: R. = K[] - sage: G.reynolds_operator(x*y^5, chi) - 1/3*x*y^5 + (-2/3*izeta3^3 - izeta3^2 - 8/3*izeta3 - 4/3)*x^5*z + (2/3*izeta3^3 + izeta3^2 + 8/3*izeta3 + 1)*y*z^5 - sage: R. = QQbar[] - sage: G.reynolds_operator(x*y^5, chi) - 1/3*x*y^5 + (-0.1666666666666667? + 0.2886751345948129?*I)*x^5*z + (-0.1666666666666667? - 0.2886751345948129?*I)*y*z^5 - - :: - - sage: K. = CyclotomicField(4) - sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) - sage: chi = Tetra.character(Tetra.character_table()[4]) - sage: L. = QuadraticField(-3) - sage: R. = L[] - sage: Tetra.reynolds_operator(x^4) - 0 - sage: Tetra.reynolds_operator(x^4, chi) - 1/4*x^4 + (1/2*v)*x^2*y^2 + 1/4*y^4 - sage: R.=L[] - sage: LL. = L.extension(x^2+v) - sage: R. = LL[] - sage: Tetra.reynolds_operator(x^4, chi) - Traceback (most recent call last): - ... - NotImplementedError: only implemented for absolute fields - - :: - - sage: G = MatrixGroup(DihedralGroup(4)) - sage: chi = G.character(G.character_table()[1]) - sage: R. = QQ[] - sage: f = x^4 - sage: G.reynolds_operator(f, chi) - Traceback (most recent call last): - ... - TypeError: number of variables in polynomial must match size of matrices - sage: R. = QQ[] - sage: f = x^3*y - sage: G.reynolds_operator(f, chi) - 1/8*x^3*y - 1/8*x*y^3 + 1/8*y^3*z - 1/8*y*z^3 - 1/8*x^3*w + 1/8*z^3*w + - 1/8*x*w^3 - 1/8*z*w^3 - - Characteristic p>0 examples:: - - sage: G = MatrixGroup([[0,1,1,0]]) - sage: R. = GF(2)[] - sage: G.reynolds_operator(x) - Traceback (most recent call last): - ... - NotImplementedError: not implemented when characteristic divides group order - - :: - - sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) - sage: chi = G.character(G.character_table()[4]) - sage: R. = GF(7)[] - sage: f = w^5*x + x^6 - sage: G.reynolds_operator(f, chi) - Traceback (most recent call last): - ... - NotImplementedError: nontrivial characters not implemented for characteristic > 0 - sage: G.reynolds_operator(f) - x^6 - - :: - - sage: K = GF(3^2,'t') - sage: G = MatrixGroup([matrix(K,2,2, [0,K.gen(),1,0])]) - sage: R. = GF(3)[] - sage: G.reynolds_operator(x^8) - -x^8 - y^8 - - :: - - sage: K = GF(3^2,'t') - sage: G = MatrixGroup([matrix(GF(3),2,2, [0,1,1,0])]) - sage: R. = K[] - sage: f = -K.gen()*x - sage: G.reynolds_operator(f) - t*x + t*y - """ - if poly.parent().ngens() != self.degree(): - raise TypeError("number of variables in polynomial must match size of matrices") - R = FractionField(poly.base_ring()) - C = FractionField(self.base_ring()) - if chi is None: # then this is the trivial character - if R.characteristic() == 0: - # non-modular case - if C == QQbar or R == QQbar: - L = QQbar - elif not C.is_absolute() or not R.is_absolute(): - raise NotImplementedError("only implemented for absolute fields") - else: # create the compositum - if C.absolute_degree() == 1: - L = R - elif R.absolute_degree() == 1: - L = C - else: - L = C.composite_fields(R)[0] - elif not R.characteristic().divides(self.order()): - if R.characteristic() != C.characteristic(): - raise ValueError("base fields must have same characteristic") - else: - if R.degree() >= C.degree(): - L = R - else: - L = C - else: - raise NotImplementedError("not implemented when characteristic divides group order") - poly = poly.change_ring(L) - poly_gens = vector(poly.parent().gens()) - F = L.zero() - for g in self: - F += poly(*g.matrix()*vector(poly.parent().gens())) - F /= self.order() - return F - # non-trivial character case - K = chi.values()[0].parent() - if R.characteristic() == 0: - # extend base_ring to compositum - if C == QQbar or K == QQbar or R == QQbar: - L = QQbar - elif not C.is_absolute() or not K.is_absolute() or not R.is_absolute(): - raise NotImplementedError("only implemented for absolute fields") - else: - fields = [] - for M in [R,K,C]: - if M.absolute_degree() != 1: - fields.append(M) - l = len(fields) - if l == 0: - # all are QQ - L = R - elif l == 1: - # only one is an extension - L = fields[0] - elif l == 2: - # only two are extensions - L = fields[0].composite_fields(fields[1])[0] - else: - # all three are extensions - L1 = fields[0].composite_fields(fields[1])[0] - L = L1.composite_fields(fields[2])[0] - else: - raise NotImplementedError("nontrivial characters not implemented for characteristic > 0") - poly = poly.change_ring(L) - poly_gens = vector(poly.parent().gens()) - F = L.zero() - for g in self: - F += L(chi(g)) * poly(*g.matrix().change_ring(L)*poly_gens) - F /= self.order() - try: # attempt to move F to base_ring of polynomial - F = F.change_ring(R) - except (TypeError, ValueError): - pass - return F - - def invariants_of_degree(self, deg, chi=None, R=None): - r""" - Return the (relative) invariants of given degree for this group. - - For this group, compute the invariants of degree ``deg`` - with respect to the group character ``chi``. The method - is to project each possible monomial of degree ``deg`` via - the Reynolds operator. Note that if the polynomial ring ``R`` - is specified it's base ring may be extended if the resulting - invariant is defined over a bigger field. - - INPUT: - - - ``degree`` -- a positive integer - - - ``chi`` -- (default: trivial character) a linear group character of this group - - - ``R`` -- (optional) a polynomial ring - - OUTPUT: list of polynomials - - EXAMPLES:: - - sage: Gr = MatrixGroup(SymmetricGroup(2)) - sage: sorted(Gr.invariants_of_degree(3)) - [x0^2*x1 + x0*x1^2, x0^3 + x1^3] - sage: R. = QQ[] - sage: sorted(Gr.invariants_of_degree(4, R=R)) - [x^2*y^2, x^3*y + x*y^3, x^4 + y^4] - - :: - - sage: R. = QQ[] - sage: Gr = MatrixGroup(DihedralGroup(3)) - sage: ct = Gr.character_table() - sage: chi = Gr.character(ct[0]) - sage: all(f(*(g.matrix()*vector(R.gens()))) == chi(g)*f - ....: for f in Gr.invariants_of_degree(3, R=R, chi=chi) for g in Gr) - True - - :: - - sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) - sage: G.invariants_of_degree(25) - [] - - :: - - sage: G = MatrixGroup(SymmetricGroup(5)) - sage: R = QQ['x,y'] - sage: G.invariants_of_degree(3, R=R) - Traceback (most recent call last): - ... - TypeError: number of variables in polynomial ring must match size of matrices - - :: - - sage: K. = CyclotomicField(4) - sage: G = MatrixGroup(CyclicPermutationGroup(3)) - sage: chi = G.character(G.character_table()[1]) - sage: R. = K[] - sage: sorted(G.invariants_of_degree(2, R=R, chi=chi)) - [x*y + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*x*z + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y*z, - x^2 + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y^2 + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*z^2] - - :: - - sage: S3 = MatrixGroup(SymmetricGroup(3)) - sage: chi = S3.character(S3.character_table()[0]) - sage: sorted(S3.invariants_of_degree(5, chi=chi)) - [x0^3*x1^2 - x0^2*x1^3 - x0^3*x2^2 + x1^3*x2^2 + x0^2*x2^3 - x1^2*x2^3, - x0^4*x1 - x0*x1^4 - x0^4*x2 + x1^4*x2 + x0*x2^4 - x1*x2^4] - """ - D = self.degree() - deg = int(deg) - if deg <= 0: - raise ValueError("degree must be a positive integer") - if R is None: - R = PolynomialRing(self.base_ring(), 'x', D) - elif R.ngens() != D: - raise TypeError("number of variables in polynomial ring must match size of matrices") - - ms = self.molien_series(prec=deg+1,chi=chi) - if ms[deg].is_zero(): - return [] - inv = set() - for e in IntegerVectors(deg, D): - F = self.reynolds_operator(R.monomial(*e), chi=chi) - if not F.is_zero(): - F = F / F.lc() - inv.add(F) - if len(inv) == ms[deg]: - break - return list(inv) diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py new file mode 100644 index 00000000000..6fe8cad2891 --- /dev/null +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -0,0 +1,853 @@ +""" +Finitely Generated Matrix Groups with GAP +""" + +from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap + + +class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap): + """ + Matrix group generated by a finite number of matrices. + + EXAMPLES:: + + sage: m1 = matrix(GF(11), [[1,2],[3,4]]) + sage: m2 = matrix(GF(11), [[1,3],[10,0]]) + sage: G = MatrixGroup(m1, m2); G + Matrix group over Finite Field of size 11 with 2 generators ( + [1 2] [ 1 3] + [3 4], [10 0] + ) + sage: type(G) + + sage: TestSuite(G).run() + """ + + def __reduce__(self): + """ + Implement pickling. + + EXAMPLES:: + + sage: m1 = matrix(QQ, [[1,2],[3,4]]) + sage: m2 = matrix(QQ, [[1,3],[-1,0]]) + sage: loads(MatrixGroup(m1, m2).dumps()) + Matrix group over Rational Field with 2 generators ( + [1 2] [ 1 3] + [3 4], [-1 0] + ) + """ + return (MatrixGroup, + tuple(g.matrix() for g in self.gens()) + ({'check':False},)) + + def as_permutation_group(self, algorithm=None, seed=None): + r""" + Return a permutation group representation for the group. + + In most cases occurring in practice, this is a permutation + group of minimal degree (the degree being determined from + orbits under the group action). When these orbits are hard to + compute, the procedure can be time-consuming and the degree + may not be minimal. + + INPUT: + + - ``algorithm`` -- ``None`` or ``'smaller'``. In the latter + case, try harder to find a permutation representation of + small degree. + - ``seed`` -- ``None`` or an integer specifying the seed + to fix results depending on pseudo-random-numbers. Here + it makes sense to be used with respect to the ``'smaller'`` + option, since gap produces random output in that context. + + OUTPUT: + + A permutation group isomorphic to ``self``. The + ``algorithm='smaller'`` option tries to return an isomorphic + group of low degree, but is not guaranteed to find the + smallest one and must not even differ from the one obtained + without the option. In that case repeating the invocation + may help (see the example below). + + EXAMPLES:: + + sage: MS = MatrixSpace(GF(2), 5, 5) + sage: A = MS([[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0]]) + sage: G = MatrixGroup([A]) + sage: G.as_permutation_group().order() + 2 + + A finite subgroup of GL(12,Z) as a permutation group:: + + sage: imf = libgap.function_factory('ImfMatrixGroup') + sage: GG = imf( 12, 3 ) + sage: G = MatrixGroup(GG.GeneratorsOfGroup()) + sage: G.cardinality() + 21499084800 + sage: P = G.as_permutation_group() + sage: Psmaller = G.as_permutation_group(algorithm="smaller", seed=6) + sage: P == Psmaller # see the note below + True + sage: Psmaller = G.as_permutation_group(algorithm="smaller") + sage: P == Psmaller + False + sage: P.cardinality() + 21499084800 + sage: P.degree() + 144 + sage: Psmaller.cardinality() + 21499084800 + sage: Psmaller.degree() + 80 + + .. NOTE:: + + In this case, the "smaller" option returned an isomorphic + group of lower degree. The above example used GAP's library + of irreducible maximal finite ("imf") integer matrix groups + to construct the MatrixGroup G over GF(7). The section + "Irreducible Maximal Finite Integral Matrix Groups" in the + GAP reference manual has more details. + + .. NOTE:: + + Concerning the option ``algorithm='smaller'`` you should note + the following from GAP documentation: "The methods used might + involve the use of random elements and the permutation + representation (or even the degree of the representation) is + not guaranteed to be the same for different calls of + SmallerDegreePermutationRepresentation." + + To obtain a reproducible result the optional argument ``seed`` + may be used as in the example above. + + TESTS:: + + sage: A = matrix(QQ, 2, [0, 1, 1, 0]) + sage: B = matrix(QQ, 2, [1, 0, 0, 1]) + sage: a, b = MatrixGroup([A, B]).as_permutation_group().gens() + sage: a.order(), b.order() + (2, 1) + + The above example in GL(12,Z), reduced modulo 7:: + + sage: MS = MatrixSpace(GF(7), 12, 12) + sage: G = MatrixGroup([MS(g) for g in GG.GeneratorsOfGroup()]) + sage: G.cardinality() + 21499084800 + sage: P = G.as_permutation_group() + sage: P.cardinality() + 21499084800 + + Check that large degree is still working:: + + sage: Sp(6,3).as_permutation_group().cardinality() + 9170703360 + + Check that :trac:`25706` still works after :trac:`26903`:: + + sage: MG = GU(3,2).as_matrix_group() + sage: PG = MG.as_permutation_group() + sage: mg = MG.an_element() + sage: PG(mg).order() # particular element depends on the set of GAP packages installed + 6 + """ + # Note that the output of IsomorphismPermGroup() depends on + # memory locations and will change if you change the order of + # doctests and/or architecture + from sage.groups.perm_gps.permgroup import PermutationGroup + if not self.is_finite(): + raise NotImplementedError("group must be finite") + if seed is not None: + from sage.libs.gap.libgap import libgap + libgap.set_seed(ZZ(seed)) + iso = self._libgap_().IsomorphismPermGroup() + if algorithm == "smaller": + iso = iso.Image().SmallerDegreePermutationRepresentation() + return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), + canonicalize=False) + + def module_composition_factors(self, algorithm=None): + r""" + Return a list of triples consisting of [base field, dimension, + irreducibility], for each of the Meataxe composition factors + modules. The ``algorithm="verbose"`` option returns more information, + but in Meataxe notation. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,4,4) + sage: M = MS(0) + sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1 + sage: G = MatrixGroup([M]) + sage: G.module_composition_factors() + [(Finite Field of size 3, 1, True), + (Finite Field of size 3, 1, True), + (Finite Field of size 3, 2, True)] + sage: F = GF(7); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])] + sage: G = MatrixGroup(gens) + sage: G.module_composition_factors() + [(Finite Field of size 7, 2, True)] + + Type ``G.module_composition_factors(algorithm='verbose')`` to get a + more verbose version. + + For more on MeatAxe notation, see + https://www.gap-system.org/Manuals/doc/ref/chap69.html + """ + from sage.libs.gap.libgap import libgap + F = self.base_ring() + if not F.is_finite(): + raise NotImplementedError("base ring must be finite") + n = self.degree() + MS = MatrixSpace(F, n, n) + mats = [MS(g.matrix()) for g in self.gens()] + # initializing list of mats by which the gens act on self + mats_gap = libgap(mats) + M = mats_gap.GModuleByMats(F) + compo = libgap.function_factory('MTX.CompositionFactors') + MCFs = compo(M) + if algorithm == "verbose": + print(str(MCFs) + "\n") + return sorted((MCF['field'].sage(), + MCF['dimension'].sage(), + MCF['IsIrreducible'].sage()) for MCF in MCFs) + + def invariant_generators(self): + r""" + Return invariant ring generators. + + Computes generators for the polynomial ring + `F[x_1,\ldots,x_n]^G`, where `G` in `GL(n,F)` is a finite matrix + group. + + In the "good characteristic" case the polynomials returned + form a minimal generating set for the algebra of `G`-invariant + polynomials. In the "bad" case, the polynomials returned + are primary and secondary invariants, forming a not + necessarily minimal generating set for the algebra of + `G`-invariant polynomials. + + ALGORITHM: + + Wraps Singular's ``invariant_algebra_reynolds`` and ``invariant_ring`` + in ``finvar.lib``. + + EXAMPLES:: + + sage: F = GF(7); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])] + sage: G = MatrixGroup(gens) + sage: G.invariant_generators() + [x1^7*x2 - x1*x2^7, + x1^12 - 2*x1^9*x2^3 - x1^6*x2^6 + 2*x1^3*x2^9 + x2^12, + x1^18 + 2*x1^15*x2^3 + 3*x1^12*x2^6 + 3*x1^6*x2^12 - 2*x1^3*x2^15 + x2^18] + + sage: q = 4; a = 2 + sage: MS = MatrixSpace(QQ, 2, 2) + sage: gen1 = [[1/a,(q-1)/a],[1/a, -1/a]]; gen2 = [[1,0],[0,-1]]; gen3 = [[-1,0],[0,1]] + sage: G = MatrixGroup([MS(gen1),MS(gen2),MS(gen3)]) + sage: G.cardinality() + 12 + sage: G.invariant_generators() + [x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6] + + sage: F = CyclotomicField(8) + sage: z = F.gen() + sage: a = z+1/z + sage: b = z^2 + sage: MS = MatrixSpace(F,2,2) + sage: g1 = MS([[1/a, 1/a], [1/a, -1/a]]) + sage: g2 = MS([[-b, 0], [0, b]]) + sage: G = MatrixGroup([g1,g2]) + sage: G.invariant_generators() + [x1^4 + 2*x1^2*x2^2 + x2^4, + x1^5*x2 - x1*x2^5, + x1^8 + 28/9*x1^6*x2^2 + 70/9*x1^4*x2^4 + 28/9*x1^2*x2^6 + x2^8] + + AUTHORS: + + - David Joyner, Simon King and Martin Albrecht. + + REFERENCES: + + - Singular reference manual + + - [Stu1993]_ + + - S. King, "Minimal Generating Sets of non-modular invariant + rings of finite groups", :arxiv:`math/0703035`. + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.interfaces.singular import singular + gens = self.gens() + singular.LIB("finvar.lib") + n = self.degree() # len((gens[0].matrix()).rows()) + F = self.base_ring() + q = F.characteristic() + # test if the field is admissible + if F.gen() == 1: # we got the rationals or GF(prime) + FieldStr = str(F.characteristic()) + elif hasattr(F,'polynomial'): # we got an algebraic extension + if len(F.gens()) > 1: + raise NotImplementedError("can only deal with finite fields and (simple algebraic extensions of) the rationals") + FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen())) + else: # we have a transcendental extension + FieldStr = '(%d,%s)' % (F.characteristic(), + ','.join(str(p) for p in F.gens())) + + # Setting Singular's variable names + # We need to make sure that field generator and variables get different names. + if str(F.gen())[0] == 'x': + VarStr = 'y' + else: + VarStr = 'x' + VarNames = '(' + ','.join((VarStr+str(i) for i in range(1, n+1)))+')' + # The function call and affectation below have side-effects. Do not remove! + # (even if pyflakes say so) + R = singular.ring(FieldStr, VarNames, 'dp') + if hasattr(F, 'polynomial') and F.gen() != 1: + # we have to define minpoly + singular.eval('minpoly = '+str(F.polynomial()).replace('x',str(F.gen()))) + A = [singular.matrix(n,n,str((x.matrix()).list())) for x in gens] + Lgens = ','.join((x.name() for x in A)) + PR = PolynomialRing(F, n, [VarStr+str(i) for i in range(1,n+1)]) + + if q == 0 or (q > 0 and self.cardinality() % q): + from sage.all import Matrix + try: + elements = [g.matrix() for g in self.list()] + except (TypeError, ValueError): + elements + if elements is not None: + ReyName = 't'+singular._next_var_name() + singular.eval('matrix %s[%d][%d]' % (ReyName, + self.cardinality(), n)) + for i in range(1,self.cardinality()+1): + M = Matrix(F, elements[i-1]) + D = [{} for foobar in range(self.degree())] + for x,y in M.dict().items(): + D[x[0]][x[1]] = y + for row in range(self.degree()): + for t in D[row].items(): + singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' + % (ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1)) + IRName = 't'+singular._next_var_name() + singular.eval('matrix %s = invariant_algebra_reynolds(%s)' % (IRName,ReyName)) + else: + ReyName = 't'+singular._next_var_name() + singular.eval('list %s=group_reynolds((%s))' % (ReyName, Lgens)) + IRName = 't'+singular._next_var_name() + singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' % (IRName, ReyName)) + + OUT = [singular.eval(IRName+'[1,%d]' % (j)) + for j in range(1, 1+int(singular('ncols('+IRName+')')))] + return [PR(gen) for gen in OUT] + if self.cardinality() % q == 0: + PName = 't' + singular._next_var_name() + SName = 't' + singular._next_var_name() + singular.eval('matrix %s,%s=invariant_ring(%s)' % (PName, SName, Lgens)) + OUT = [singular.eval(PName+'[1,%d]' % (j)) + for j in range(1,1+singular('ncols('+PName+')'))] + OUT += [singular.eval(SName+'[1,%d]' % (j)) + for j in range(2,1+singular('ncols('+SName+')'))] + return [PR(gen) for gen in OUT] + + def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): + r""" + Compute the Molien series of this finite group with respect to the + character ``chi``. It can be returned either as a rational function + in one variable or a power series in one variable. The base field + must be a finite field, the rationals, or a cyclotomic field. + + Note that the base field characteristic cannot divide the group + order (i.e., the non-modular case). + + ALGORITHM: + + For a finite group `G` in characteristic zero we construct the Molien series as + + .. MATH:: + + \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\text{det}(I-tg)}, + + where `I` is the identity matrix and `t` an indeterminate. + + For characteristic `p` not dividing the order of `G`, let `k` be the base field + and `N` the order of `G`. Define `\lambda` as a primitive `N`-th root of unity over `k` + and `\omega` as a primitive `N`-th root of unity over `\QQ`. For each `g \in G` + define `k_i(g)` to be the positive integer such that + `e_i = \lambda^{k_i(g)}` for each eigenvalue `e_i` of `g`. Then the Molien series + is computed as + + .. MATH:: + + \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\prod_{i=1}^n(1 - t\omega^{k_i(g)})}, + + where `t` is an indeterminant. [Dec1998]_ + + INPUT: + + - ``chi`` -- (default: trivial character) a linear group character of this group + + - ``return_series`` -- boolean (default: ``True``) if ``True``, then returns + the Molien series as a power series, ``False`` as a rational function + + - ``prec`` -- integer (default: 20); power series default precision + + - ``variable`` -- string (default: ``'t'``); Variable name for the Molien series + + OUTPUT: single variable rational function or power series with integer coefficients + + EXAMPLES:: + + sage: MatrixGroup(matrix(QQ,2,2,[1,1,0,1])).molien_series() + Traceback (most recent call last): + ... + NotImplementedError: only implemented for finite groups + sage: MatrixGroup(matrix(GF(3),2,2,[1,1,0,1])).molien_series() + Traceback (most recent call last): + ... + NotImplementedError: characteristic cannot divide group order + + Tetrahedral Group:: + + sage: K. = CyclotomicField(4) + sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) + sage: Tetra.molien_series(prec=30) + 1 + t^8 + 2*t^12 + t^16 + 2*t^20 + 3*t^24 + 2*t^28 + O(t^30) + sage: mol = Tetra.molien_series(return_series=False); mol + (t^8 - t^4 + 1)/(t^16 - t^12 - t^4 + 1) + sage: mol.parent() + Fraction Field of Univariate Polynomial Ring in t over Integer Ring + sage: chi = Tetra.character(Tetra.character_table()[1]) + sage: Tetra.molien_series(chi, prec=30, variable='u') + u^6 + u^14 + 2*u^18 + u^22 + 2*u^26 + 3*u^30 + 2*u^34 + O(u^36) + sage: chi = Tetra.character(Tetra.character_table()[2]) + sage: Tetra.molien_series(chi) + t^10 + t^14 + t^18 + 2*t^22 + 2*t^26 + O(t^30) + + :: + + sage: S3 = MatrixGroup(SymmetricGroup(3)) + sage: mol = S3.molien_series(prec=10); mol + 1 + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 7*t^6 + 8*t^7 + 10*t^8 + 12*t^9 + O(t^10) + sage: mol.parent() + Power Series Ring in t over Integer Ring + + Octahedral Group:: + + sage: K. = CyclotomicField(8) + sage: a = v-v^3 #sqrt(2) + sage: i = v^2 + sage: Octa = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [(1+i)/a,0, 0,(1-i)/a]) + sage: Octa.molien_series(prec=30) + 1 + t^8 + t^12 + t^16 + t^18 + t^20 + 2*t^24 + t^26 + t^28 + O(t^30) + + Icosahedral Group:: + + sage: K. = CyclotomicField(10) + sage: z5 = v^2 + sage: i = z5^5 + sage: a = 2*z5^3 + 2*z5^2 + 1 #sqrt(5) + sage: Ico = MatrixGroup([[z5^3,0, 0,z5^2], [0,1, -1,0], [(z5^4-z5)/a, (z5^2-z5^3)/a, (z5^2-z5^3)/a, -(z5^4-z5)/a]]) + sage: Ico.molien_series(prec=40) + 1 + t^12 + t^20 + t^24 + t^30 + t^32 + t^36 + O(t^40) + + :: + + sage: G = MatrixGroup(CyclicPermutationGroup(3)) + sage: chi = G.character(G.character_table()[1]) + sage: G.molien_series(chi, prec=10) + t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 9*t^6 + 12*t^7 + 15*t^8 + 18*t^9 + 22*t^10 + O(t^11) + + :: + + sage: K = GF(5) + sage: S = MatrixGroup(SymmetricGroup(4)) + sage: G = MatrixGroup([matrix(K,4,4,[K(y) for u in m.list() for y in u])for m in S.gens()]) + sage: G.molien_series(return_series=False) + 1/(t^10 - t^9 - t^8 + 2*t^5 - t^2 - t + 1) + + :: + + sage: i = GF(7)(3) + sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) + sage: chi = G.character(G.character_table()[4]) + sage: G.molien_series(chi) + 3*t^5 + 6*t^11 + 9*t^17 + 12*t^23 + O(t^25) + """ + if not self.is_finite(): + raise NotImplementedError("only implemented for finite groups") + if chi is None: + chi = self.trivial_character() + M = self.matrix_space() + R = FractionField(self.base_ring()) + N = self.order() + if R.characteristic() == 0: + P = PolynomialRing(R, variable) + t = P.gen() + # it is possible the character is over a larger cyclotomic field + K = chi.values()[0].parent() + if K.degree() != 1: + if R.degree() != 1: + L = K.composite_fields(R)[0] + else: + L = K + else: + L = R + mol = P(0) + for g in self: + mol += L(chi(g)) / (M.identity_matrix()-t*g.matrix()).det().change_ring(L) + elif R.characteristic().divides(N): + raise NotImplementedError("characteristic cannot divide group order") + else: # char p>0 + # find primitive Nth roots of unity over base ring and QQ + F = cyclotomic_polynomial(N).change_ring(R) + w = F.roots(ring=R.algebraic_closure(), multiplicities=False)[0] + # don't need to extend further in this case since the order of + # the roots of unity in the character divide the order of the group + L = CyclotomicField(N, 'v') + v = L.gen() + # construct Molien series + P = PolynomialRing(L, variable) + t = P.gen() + mol = P(0) + for g in self: + # construct Phi + phi = L(chi(g)) + for e in g.matrix().eigenvalues(): + # find power such that w**n = e + n = 1 + while w**n != e and n < N+1: + n += 1 + # raise v to that power + phi *= (1-t*v**n) + mol += P(1)/phi + # We know the coefficients will be integers + mol = mol.numerator().change_ring(ZZ) / mol.denominator().change_ring(ZZ) + # divide by group order + mol /= N + if return_series: + PS = PowerSeriesRing(ZZ, variable, default_prec=prec) + return PS(mol) + return mol + + def reynolds_operator(self, poly, chi=None): + r""" + Compute the Reynolds operator of this finite group `G`. + + This is the projection from a polynomial ring to the ring of + relative invariants [Stu1993]_. If possible, the invariant is + returned defined over the base field of the given polynomial + ``poly``, otherwise, it is returned over the compositum of the + fields involved in the computation. + Only implemented for absolute fields. + + ALGORITHM: + + Let `K[x]` be a polynomial ring and `\chi` a linear character for `G`. Let + + .. MATH: + + K[x]^G_{\chi} = \{f \in K[x] | \pi f = \chi(\pi) f \forall \pi\in G\} + + be the ring of invariants of `G` relative to `\chi`. Then the Reynold's operator + is a map `R` from `K[x]` into `K[x]^G_{\chi}` defined by + + .. MATH: + + f \mapsto \frac{1}{|G|} \sum_{ \pi \in G} \chi(\pi) f. + + INPUT: + + - ``poly`` -- a polynomial + + - ``chi`` -- (default: trivial character) a linear group character of this group + + OUTPUT: an invariant polynomial relative to `\chi` + + AUTHORS: + + Rebecca Lauren Miller and Ben Hutz + + EXAMPLES:: + + sage: S3 = MatrixGroup(SymmetricGroup(3)) + sage: R. = QQ[] + sage: f = x*y*z^3 + sage: S3.reynolds_operator(f) + 1/3*x^3*y*z + 1/3*x*y^3*z + 1/3*x*y*z^3 + + :: + + sage: G = MatrixGroup(CyclicPermutationGroup(4)) + sage: chi = G.character(G.character_table()[3]) + sage: K. = CyclotomicField(4) + sage: R. = K[] + sage: G.reynolds_operator(x, chi) + 1/4*x + (1/4*v)*y - 1/4*z + (-1/4*v)*w + sage: chi = G.character(G.character_table()[2]) + sage: R. = QQ[] + sage: G.reynolds_operator(x*y, chi) + 1/4*x*y + (-1/4*zeta4)*y*z + (1/4*zeta4)*x*w - 1/4*z*w + + :: + + sage: K. = CyclotomicField(4) + sage: G = MatrixGroup(CyclicPermutationGroup(3)) + sage: chi = G.character(G.character_table()[1]) + sage: R. = K[] + sage: G.reynolds_operator(x*y^5, chi) + 1/3*x*y^5 + (-2/3*izeta3^3 - izeta3^2 - 8/3*izeta3 - 4/3)*x^5*z + (2/3*izeta3^3 + izeta3^2 + 8/3*izeta3 + 1)*y*z^5 + sage: R. = QQbar[] + sage: G.reynolds_operator(x*y^5, chi) + 1/3*x*y^5 + (-0.1666666666666667? + 0.2886751345948129?*I)*x^5*z + (-0.1666666666666667? - 0.2886751345948129?*I)*y*z^5 + + :: + + sage: K. = CyclotomicField(4) + sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) + sage: chi = Tetra.character(Tetra.character_table()[4]) + sage: L. = QuadraticField(-3) + sage: R. = L[] + sage: Tetra.reynolds_operator(x^4) + 0 + sage: Tetra.reynolds_operator(x^4, chi) + 1/4*x^4 + (1/2*v)*x^2*y^2 + 1/4*y^4 + sage: R.=L[] + sage: LL. = L.extension(x^2+v) + sage: R. = LL[] + sage: Tetra.reynolds_operator(x^4, chi) + Traceback (most recent call last): + ... + NotImplementedError: only implemented for absolute fields + + :: + + sage: G = MatrixGroup(DihedralGroup(4)) + sage: chi = G.character(G.character_table()[1]) + sage: R. = QQ[] + sage: f = x^4 + sage: G.reynolds_operator(f, chi) + Traceback (most recent call last): + ... + TypeError: number of variables in polynomial must match size of matrices + sage: R. = QQ[] + sage: f = x^3*y + sage: G.reynolds_operator(f, chi) + 1/8*x^3*y - 1/8*x*y^3 + 1/8*y^3*z - 1/8*y*z^3 - 1/8*x^3*w + 1/8*z^3*w + + 1/8*x*w^3 - 1/8*z*w^3 + + Characteristic p>0 examples:: + + sage: G = MatrixGroup([[0,1,1,0]]) + sage: R. = GF(2)[] + sage: G.reynolds_operator(x) + Traceback (most recent call last): + ... + NotImplementedError: not implemented when characteristic divides group order + + :: + + sage: i = GF(7)(3) + sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) + sage: chi = G.character(G.character_table()[4]) + sage: R. = GF(7)[] + sage: f = w^5*x + x^6 + sage: G.reynolds_operator(f, chi) + Traceback (most recent call last): + ... + NotImplementedError: nontrivial characters not implemented for characteristic > 0 + sage: G.reynolds_operator(f) + x^6 + + :: + + sage: K = GF(3^2,'t') + sage: G = MatrixGroup([matrix(K,2,2, [0,K.gen(),1,0])]) + sage: R. = GF(3)[] + sage: G.reynolds_operator(x^8) + -x^8 - y^8 + + :: + + sage: K = GF(3^2,'t') + sage: G = MatrixGroup([matrix(GF(3),2,2, [0,1,1,0])]) + sage: R. = K[] + sage: f = -K.gen()*x + sage: G.reynolds_operator(f) + t*x + t*y + """ + if poly.parent().ngens() != self.degree(): + raise TypeError("number of variables in polynomial must match size of matrices") + R = FractionField(poly.base_ring()) + C = FractionField(self.base_ring()) + if chi is None: # then this is the trivial character + if R.characteristic() == 0: + # non-modular case + if C == QQbar or R == QQbar: + L = QQbar + elif not C.is_absolute() or not R.is_absolute(): + raise NotImplementedError("only implemented for absolute fields") + else: # create the compositum + if C.absolute_degree() == 1: + L = R + elif R.absolute_degree() == 1: + L = C + else: + L = C.composite_fields(R)[0] + elif not R.characteristic().divides(self.order()): + if R.characteristic() != C.characteristic(): + raise ValueError("base fields must have same characteristic") + else: + if R.degree() >= C.degree(): + L = R + else: + L = C + else: + raise NotImplementedError("not implemented when characteristic divides group order") + poly = poly.change_ring(L) + poly_gens = vector(poly.parent().gens()) + F = L.zero() + for g in self: + F += poly(*g.matrix()*vector(poly.parent().gens())) + F /= self.order() + return F + # non-trivial character case + K = chi.values()[0].parent() + if R.characteristic() == 0: + # extend base_ring to compositum + if C == QQbar or K == QQbar or R == QQbar: + L = QQbar + elif not C.is_absolute() or not K.is_absolute() or not R.is_absolute(): + raise NotImplementedError("only implemented for absolute fields") + else: + fields = [] + for M in [R,K,C]: + if M.absolute_degree() != 1: + fields.append(M) + l = len(fields) + if l == 0: + # all are QQ + L = R + elif l == 1: + # only one is an extension + L = fields[0] + elif l == 2: + # only two are extensions + L = fields[0].composite_fields(fields[1])[0] + else: + # all three are extensions + L1 = fields[0].composite_fields(fields[1])[0] + L = L1.composite_fields(fields[2])[0] + else: + raise NotImplementedError("nontrivial characters not implemented for characteristic > 0") + poly = poly.change_ring(L) + poly_gens = vector(poly.parent().gens()) + F = L.zero() + for g in self: + F += L(chi(g)) * poly(*g.matrix().change_ring(L)*poly_gens) + F /= self.order() + try: # attempt to move F to base_ring of polynomial + F = F.change_ring(R) + except (TypeError, ValueError): + pass + return F + + def invariants_of_degree(self, deg, chi=None, R=None): + r""" + Return the (relative) invariants of given degree for this group. + + For this group, compute the invariants of degree ``deg`` + with respect to the group character ``chi``. The method + is to project each possible monomial of degree ``deg`` via + the Reynolds operator. Note that if the polynomial ring ``R`` + is specified it's base ring may be extended if the resulting + invariant is defined over a bigger field. + + INPUT: + + - ``degree`` -- a positive integer + + - ``chi`` -- (default: trivial character) a linear group character of this group + + - ``R`` -- (optional) a polynomial ring + + OUTPUT: list of polynomials + + EXAMPLES:: + + sage: Gr = MatrixGroup(SymmetricGroup(2)) + sage: sorted(Gr.invariants_of_degree(3)) + [x0^2*x1 + x0*x1^2, x0^3 + x1^3] + sage: R. = QQ[] + sage: sorted(Gr.invariants_of_degree(4, R=R)) + [x^2*y^2, x^3*y + x*y^3, x^4 + y^4] + + :: + + sage: R. = QQ[] + sage: Gr = MatrixGroup(DihedralGroup(3)) + sage: ct = Gr.character_table() + sage: chi = Gr.character(ct[0]) + sage: all(f(*(g.matrix()*vector(R.gens()))) == chi(g)*f + ....: for f in Gr.invariants_of_degree(3, R=R, chi=chi) for g in Gr) + True + + :: + + sage: i = GF(7)(3) + sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) + sage: G.invariants_of_degree(25) + [] + + :: + + sage: G = MatrixGroup(SymmetricGroup(5)) + sage: R = QQ['x,y'] + sage: G.invariants_of_degree(3, R=R) + Traceback (most recent call last): + ... + TypeError: number of variables in polynomial ring must match size of matrices + + :: + + sage: K. = CyclotomicField(4) + sage: G = MatrixGroup(CyclicPermutationGroup(3)) + sage: chi = G.character(G.character_table()[1]) + sage: R. = K[] + sage: sorted(G.invariants_of_degree(2, R=R, chi=chi)) + [x*y + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*x*z + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y*z, + x^2 + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y^2 + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*z^2] + + :: + + sage: S3 = MatrixGroup(SymmetricGroup(3)) + sage: chi = S3.character(S3.character_table()[0]) + sage: sorted(S3.invariants_of_degree(5, chi=chi)) + [x0^3*x1^2 - x0^2*x1^3 - x0^3*x2^2 + x1^3*x2^2 + x0^2*x2^3 - x1^2*x2^3, + x0^4*x1 - x0*x1^4 - x0^4*x2 + x1^4*x2 + x0*x2^4 - x1*x2^4] + """ + D = self.degree() + deg = int(deg) + if deg <= 0: + raise ValueError("degree must be a positive integer") + if R is None: + R = PolynomialRing(self.base_ring(), 'x', D) + elif R.ngens() != D: + raise TypeError("number of variables in polynomial ring must match size of matrices") + + ms = self.molien_series(prec=deg+1,chi=chi) + if ms[deg].is_zero(): + return [] + inv = set() + for e in IntegerVectors(deg, D): + F = self.reynolds_operator(R.monomial(*e), chi=chi) + if not F.is_zero(): + F = F / F.lc() + inv.add(F) + if len(inv) == ms[deg]: + break + return list(inv) diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index 4d100d01aec..15714ca81bf 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -59,12 +59,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.latex import latex -from sage.groups.matrix_gps.named_group import ( - normalize_args_vectorspace, NamedMatrixGroup_generic, NamedMatrixGroup_gap ) from sage.categories.fields import Fields from sage.categories.groups import Groups -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group import ( + normalize_args_vectorspace, NamedMatrixGroup_generic) +from sage.misc.latex import latex ############################################################################### @@ -282,19 +281,3 @@ def _check_matrix(self, x, *args): else: if x.determinant() == 0: raise TypeError('matrix must non-zero determinant') - - -class LinearMatrixGroup_gap(NamedMatrixGroup_gap, LinearMatrixGroup_generic, FinitelyGeneratedMatrixGroup_gap): - r""" - The general or special linear group in GAP. - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = GL(3,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - pass diff --git a/src/sage/groups/matrix_gps/linear_gap.py b/src/sage/groups/matrix_gps/linear_gap.py new file mode 100644 index 00000000000..7f2be376d2f --- /dev/null +++ b/src/sage/groups/matrix_gps/linear_gap.py @@ -0,0 +1,23 @@ +""" +Linear Groups with GAP +""" + +from sage.groups.matrix_gps.linear import LinearMatrixGroup_generic +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + + +class LinearMatrixGroup_gap(NamedMatrixGroup_gap, LinearMatrixGroup_generic, FinitelyGeneratedMatrixGroup_gap): + r""" + The general or special linear group in GAP. + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: G = GL(3,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + pass diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 8cea6a6ef66..3c3a4e321fd 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -58,11 +58,8 @@ richcmp_method, richcmp) from sage.misc.cachefunc import cached_method from sage.groups.group import Group -from sage.groups.libgap_wrapper import ParentLibGAP -from sage.groups.libgap_mixin import GroupMixinLibGAP -from sage.groups.matrix_gps.group_element import ( - MatrixGroupElement_generic, MatrixGroupElement_gap) +from sage.groups.matrix_gps.group_element import MatrixGroupElement_generic def is_MatrixGroup(x): @@ -188,7 +185,7 @@ def subgroup(self, generators, check=True): sage: UCF = UniversalCyclotomicField() sage: G = GL(3, UCF) - sage: e3 = UCF.gen(3); e5 =UCF.gen(5) + sage: e3 = UCF.gen(3); e5 = UCF.gen(5) sage: m = matrix(UCF, 3,3, [[e3, 1, 0], [0, e5, 7],[4, 3, 2]]) sage: S = G.subgroup([m]); S Subgroup with 1 generators ( @@ -212,29 +209,12 @@ def subgroup(self, generators, check=True): sage: TestSuite(G).run() sage: TestSuite(S).run() - - sage: W = CoxeterGroup(['I',7]) - sage: s = W.simple_reflections() - sage: G = W.subgroup([s[1]]) - sage: G.category() - Category of finite groups - - sage: W = WeylGroup(['A',2]) - sage: s = W.simple_reflections() - sage: G = W.subgroup([s[1]]) - sage: G.category() - Category of finite groups """ try: test = self.is_finite() except NotImplementedError: test = self in Groups().Finite() cat = Groups().Finite() if test else Groups() - # this method enlarges the method with same name of - # ParentLibGAP to cases where the ambient group is not - # inherited from ParentLibGAP. - if isinstance(self, ParentLibGAP): - return ParentLibGAP.subgroup(self, generators) for g in generators: if g not in self: @@ -548,238 +528,3 @@ def __richcmp__(self, other, op): if lx != rx: return richcmp_not_equal(lx, rx, op) return rich_to_bool(op, 0) - -################################################################### -# -# Matrix group over a ring that GAP understands -# -################################################################### - - -class MatrixGroup_gap(GroupMixinLibGAP, MatrixGroup_generic, ParentLibGAP): - - Element = MatrixGroupElement_gap - - def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None): - """ - Base class for matrix groups that implements GAP interface. - - INPUT: - - - ``degree`` -- integer. The degree (matrix size) of the - matrix group. - - - ``base_ring`` -- ring. The base ring of the matrices. - - - ``libgap_group`` -- the defining libgap group. - - - ``ambient`` -- A derived class of :class:`ParentLibGAP` or - ``None`` (default). The ambient class if ``libgap_group`` - has been defined as a subgroup. - - TESTS: - - :: - - sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_gap - sage: MatrixGroup_gap(2, ZZ, libgap.eval('GL(2, Integers)')) - Matrix group over Integer Ring with 3 generators ( - [0 1] [-1 0] [1 1] - [1 0], [ 0 1], [0 1] - ) - - Check that the slowness of GAP iterators and enumerators for matrix groups - (cf. http://tracker.gap-system.org/issues/369) has been fixed:: - - sage: i = iter(GL(6,5)) - sage: [ next(i) for j in range(8) ] - [ - [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] - [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] - [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] - [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] - [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] - [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0], - [3 0 0 0 0 1] [4 0 0 1 3 3] [0 0 0 2 0 0] [1 0 0 0 4 4] - [3 0 0 0 0 0] [4 0 0 0 3 3] [0 0 0 0 4 0] [1 0 0 0 0 4] - [0 4 0 0 0 0] [3 0 0 0 0 1] [2 2 0 0 0 2] [1 0 0 0 0 0] - [0 0 4 0 0 0] [3 0 0 0 0 0] [1 4 0 0 0 0] [0 1 0 0 0 0] - [0 0 0 4 0 0] [0 4 0 0 0 0] [0 2 4 0 0 0] [0 0 1 0 0 0] - [4 0 0 0 2 3], [2 0 3 4 4 4], [0 0 1 4 0 0], [0 0 0 1 0 0] - ] - - And the same for listing the group elements, as well as few other issues:: - - sage: F = GF(3) - sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])] - sage: G = MatrixGroup(gens) - sage: G.cardinality() - 24 - sage: v = G.list() - sage: len(v) - 24 - sage: v[:5] - ( - [1 0] [2 0] [0 1] [0 2] [1 2] - [0 1], [0 2], [2 0], [1 0], [2 2] - ) - sage: all(g in G for g in G.list()) - True - - An example over a ring (see :trac:`5241`):: - - sage: M1 = matrix(ZZ,2,[[-1,0],[0,1]]) - sage: M2 = matrix(ZZ,2,[[1,0],[0,-1]]) - sage: M3 = matrix(ZZ,2,[[-1,0],[0,-1]]) - sage: MG = MatrixGroup([M1, M2, M3]) - sage: MG.list() - ( - [1 0] [ 1 0] [-1 0] [-1 0] - [0 1], [ 0 -1], [ 0 1], [ 0 -1] - ) - sage: MG.list()[1] - [ 1 0] - [ 0 -1] - sage: MG.list()[1].parent() - Matrix group over Integer Ring with 3 generators ( - [-1 0] [ 1 0] [-1 0] - [ 0 1], [ 0 -1], [ 0 -1] - ) - - An example over a field (see :trac:`10515`):: - - sage: gens = [matrix(QQ,2,[1,0,0,1])] - sage: MatrixGroup(gens).list() - ( - [1 0] - [0 1] - ) - - Another example over a ring (see :trac:`9437`):: - - sage: len(SL(2, Zmod(4)).list()) - 48 - - An error is raised if the group is not finite:: - - sage: GL(2,ZZ).list() - Traceback (most recent call last): - ... - NotImplementedError: group must be finite - - """ - ParentLibGAP.__init__(self, libgap_group, ambient=ambient) - MatrixGroup_generic.__init__(self, degree, base_ring, category=category) - - def __iter__(self): - """ - Iterate over the elements of the group. - - This method overrides the matrix group enumerator in GAP which - does not (and often just cannot) work for infinite groups. - - TESTS: - - infinite groups can be dealt with:: - - sage: import itertools - sage: W = WeylGroup(["A",3,1]) - sage: list(itertools.islice(W, int(4))) - [ - [1 0 0 0] [-1 1 0 1] [ 1 0 0 0] [ 1 0 0 0] - [0 1 0 0] [ 0 1 0 0] [ 1 -1 1 0] [ 0 1 0 0] - [0 0 1 0] [ 0 0 1 0] [ 0 0 1 0] [ 0 1 -1 1] - [0 0 0 1], [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1] - ] - - and finite groups, too:: - - sage: G = GL(6,5) - sage: list(itertools.islice(G, int(4))) - [ - [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] - [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] - [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] - [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] - [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] - [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0] - ] - """ - if not self.is_finite(): - # use implementation from category framework - for g in super(Group, self).__iter__(): - yield g - return - # Use the standard GAP iterator for finite groups - for g in super().__iter__(): - yield g - return - - def _check_matrix(self, x_sage, x_gap): - """ - Check whether the matrix ``x`` defines a group element. - - This is used by the element constructor (if you pass - ``check=True``, the default) that the defining matrix is valid - for this parent. Derived classes must override this to verify - that the matrix is, for example, orthogonal or symplectic. - - INPUT: - - - ``x_sage`` -- a Sage matrix in the correct matrix space (degree - and base ring). - - - ``x_gap`` -- the corresponding LibGAP matrix. - - OUTPUT: - - A ``TypeError`` must be raised if ``x`` is invalid. - - EXAMPLES:: - - sage: m1 = matrix(GF(11), [(0, -1), (1, 0)]) - sage: m2 = matrix(GF(11), [(0, -1), (1, -1)]) - sage: G = MatrixGroup([m1, m2]) - sage: G([1,2,0,1]) - [1 2] - [0 1] - sage: G([1,1,1,0]) - Traceback (most recent call last): - ... - TypeError: matrix is not in the finitely generated group - """ - from sage.libs.gap.libgap import libgap - libgap_contains = libgap.eval(r'\in') - is_contained = libgap_contains(x_gap, self.gap()) - if not is_contained.sage(): - raise TypeError('matrix is not in the finitely generated group') - - def _subgroup_constructor(self, libgap_subgroup): - """ - Return a finitely generated subgroup. - - See - :meth:`sage.groups.libgap_wrapper.ParentLibGAP._subgroup_constructor` - for details. - - TESTS:: - - sage: SL2Z = SL(2,ZZ) - sage: S, T = SL2Z.gens() - sage: G = SL2Z.subgroup([T^2]); G # indirect doctest - Subgroup with 1 generators ( - [1 2] - [0 1] - ) of Special Linear Group of degree 2 over Integer Ring - sage: G.ambient() is SL2Z - True - """ - cat = Groups() - if self in Groups().Finite(): - cat = cat.Finite() - from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(), - libgap_subgroup, ambient=self, - category=cat) - - from sage.groups.generic import structure_description diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py new file mode 100644 index 00000000000..fe5a465d734 --- /dev/null +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -0,0 +1,291 @@ +r""" +Matrix group over a ring that GAP understands +""" + +from sage.groups.libgap_mixin import GroupMixinLibGAP +from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap +from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic + + +class MatrixGroup_gap(GroupMixinLibGAP, MatrixGroup_generic, ParentLibGAP): + + Element = MatrixGroupElement_gap + + def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None): + """ + Base class for matrix groups that implements GAP interface. + + INPUT: + + - ``degree`` -- integer. The degree (matrix size) of the + matrix group. + + - ``base_ring`` -- ring. The base ring of the matrices. + + - ``libgap_group`` -- the defining libgap group. + + - ``ambient`` -- A derived class of :class:`ParentLibGAP` or + ``None`` (default). The ambient class if ``libgap_group`` + has been defined as a subgroup. + + TESTS: + + :: + + sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_gap + sage: MatrixGroup_gap(2, ZZ, libgap.eval('GL(2, Integers)')) + Matrix group over Integer Ring with 3 generators ( + [0 1] [-1 0] [1 1] + [1 0], [ 0 1], [0 1] + ) + + Check that the slowness of GAP iterators and enumerators for matrix groups + (cf. http://tracker.gap-system.org/issues/369) has been fixed:: + + sage: i = iter(GL(6,5)) + sage: [ next(i) for j in range(8) ] + [ + [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] + [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] + [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] + [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] + [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] + [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0], + [3 0 0 0 0 1] [4 0 0 1 3 3] [0 0 0 2 0 0] [1 0 0 0 4 4] + [3 0 0 0 0 0] [4 0 0 0 3 3] [0 0 0 0 4 0] [1 0 0 0 0 4] + [0 4 0 0 0 0] [3 0 0 0 0 1] [2 2 0 0 0 2] [1 0 0 0 0 0] + [0 0 4 0 0 0] [3 0 0 0 0 0] [1 4 0 0 0 0] [0 1 0 0 0 0] + [0 0 0 4 0 0] [0 4 0 0 0 0] [0 2 4 0 0 0] [0 0 1 0 0 0] + [4 0 0 0 2 3], [2 0 3 4 4 4], [0 0 1 4 0 0], [0 0 0 1 0 0] + ] + + And the same for listing the group elements, as well as few other issues:: + + sage: F = GF(3) + sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])] + sage: G = MatrixGroup(gens) + sage: G.cardinality() + 24 + sage: v = G.list() + sage: len(v) + 24 + sage: v[:5] + ( + [1 0] [2 0] [0 1] [0 2] [1 2] + [0 1], [0 2], [2 0], [1 0], [2 2] + ) + sage: all(g in G for g in G.list()) + True + + An example over a ring (see :trac:`5241`):: + + sage: M1 = matrix(ZZ,2,[[-1,0],[0,1]]) + sage: M2 = matrix(ZZ,2,[[1,0],[0,-1]]) + sage: M3 = matrix(ZZ,2,[[-1,0],[0,-1]]) + sage: MG = MatrixGroup([M1, M2, M3]) + sage: MG.list() + ( + [1 0] [ 1 0] [-1 0] [-1 0] + [0 1], [ 0 -1], [ 0 1], [ 0 -1] + ) + sage: MG.list()[1] + [ 1 0] + [ 0 -1] + sage: MG.list()[1].parent() + Matrix group over Integer Ring with 3 generators ( + [-1 0] [ 1 0] [-1 0] + [ 0 1], [ 0 -1], [ 0 -1] + ) + + An example over a field (see :trac:`10515`):: + + sage: gens = [matrix(QQ,2,[1,0,0,1])] + sage: MatrixGroup(gens).list() + ( + [1 0] + [0 1] + ) + + Another example over a ring (see :trac:`9437`):: + + sage: len(SL(2, Zmod(4)).list()) + 48 + + An error is raised if the group is not finite:: + + sage: GL(2,ZZ).list() + Traceback (most recent call last): + ... + NotImplementedError: group must be finite + + """ + ParentLibGAP.__init__(self, libgap_group, ambient=ambient) + MatrixGroup_generic.__init__(self, degree, base_ring, category=category) + + def __iter__(self): + """ + Iterate over the elements of the group. + + This method overrides the matrix group enumerator in GAP which + does not (and often just cannot) work for infinite groups. + + TESTS: + + infinite groups can be dealt with:: + + sage: import itertools + sage: W = WeylGroup(["A",3,1]) + sage: list(itertools.islice(W, int(4))) + [ + [1 0 0 0] [-1 1 0 1] [ 1 0 0 0] [ 1 0 0 0] + [0 1 0 0] [ 0 1 0 0] [ 1 -1 1 0] [ 0 1 0 0] + [0 0 1 0] [ 0 0 1 0] [ 0 0 1 0] [ 0 1 -1 1] + [0 0 0 1], [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1] + ] + + and finite groups, too:: + + sage: G = GL(6,5) + sage: list(itertools.islice(G, int(4))) + [ + [1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0] + [0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0] + [0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0] + [0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0] + [0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4] + [0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0] + ] + """ + if not self.is_finite(): + # use implementation from category framework + for g in super(Group, self).__iter__(): + yield g + return + # Use the standard GAP iterator for finite groups + for g in super().__iter__(): + yield g + return + + def _check_matrix(self, x_sage, x_gap): + """ + Check whether the matrix ``x`` defines a group element. + + This is used by the element constructor (if you pass + ``check=True``, the default) that the defining matrix is valid + for this parent. Derived classes must override this to verify + that the matrix is, for example, orthogonal or symplectic. + + INPUT: + + - ``x_sage`` -- a Sage matrix in the correct matrix space (degree + and base ring). + + - ``x_gap`` -- the corresponding LibGAP matrix. + + OUTPUT: + + A ``TypeError`` must be raised if ``x`` is invalid. + + EXAMPLES:: + + sage: m1 = matrix(GF(11), [(0, -1), (1, 0)]) + sage: m2 = matrix(GF(11), [(0, -1), (1, -1)]) + sage: G = MatrixGroup([m1, m2]) + sage: G([1,2,0,1]) + [1 2] + [0 1] + sage: G([1,1,1,0]) + Traceback (most recent call last): + ... + TypeError: matrix is not in the finitely generated group + """ + from sage.libs.gap.libgap import libgap + libgap_contains = libgap.eval(r'\in') + is_contained = libgap_contains(x_gap, self.gap()) + if not is_contained.sage(): + raise TypeError('matrix is not in the finitely generated group') + + def subgroup(self, generators, check=True): + """ + Return the subgroup generated by the given generators. + + INPUT: + + - ``generators`` -- a list/tuple/iterable of group elements of self + - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. + + OUTPUT: The subgroup generated by ``generators`` as an instance of FinitelyGeneratedMatrixGroup_gap + + EXAMPLES:: + + sage: UCF = UniversalCyclotomicField() + sage: G = GL(3, UCF) + sage: e3 = UCF.gen(3); e5 = UCF.gen(5) + sage: m = matrix(UCF, 3,3, [[e3, 1, 0], [0, e5, 7],[4, 3, 2]]) + sage: S = G.subgroup([m]); S + Subgroup with 1 generators ( + [E(3) 1 0] + [ 0 E(5) 7] + [ 4 3 2] + ) of General Linear Group of degree 3 over Universal Cyclotomic Field + + sage: CF3 = CyclotomicField(3) + sage: G = GL(3, CF3) + sage: e3 = CF3.gen() + sage: m = matrix(CF3, 3,3, [[e3, 1, 0], [0, ~e3, 7],[4, 3, 2]]) + sage: S = G.subgroup([m]); S + Subgroup with 1 generators ( + [ zeta3 1 0] + [ 0 -zeta3 - 1 7] + [ 4 3 2] + ) of General Linear Group of degree 3 over Cyclotomic Field of order 3 and degree 2 + + TESTS:: + + sage: TestSuite(G).run() + sage: TestSuite(S).run() + + sage: W = CoxeterGroup(['I',7]) + sage: s = W.simple_reflections() + sage: G = W.subgroup([s[1]]) + sage: G.category() + Category of finite groups + + sage: W = WeylGroup(['A',2]) + sage: s = W.simple_reflections() + sage: G = W.subgroup([s[1]]) + sage: G.category() + Category of finite groups + """ + # Override MatrixGroup_generic.subgroup + return ParentLibGAP.subgroup(self, generators) + + def _subgroup_constructor(self, libgap_subgroup): + """ + Return a finitely generated subgroup. + + See + :meth:`sage.groups.libgap_wrapper.ParentLibGAP._subgroup_constructor` + for details. + + TESTS:: + + sage: SL2Z = SL(2,ZZ) + sage: S, T = SL2Z.gens() + sage: G = SL2Z.subgroup([T^2]); G # indirect doctest + Subgroup with 1 generators ( + [1 2] + [0 1] + ) of Special Linear Group of degree 2 over Integer Ring + sage: G.ambient() is SL2Z + True + """ + cat = Groups() + if self in Groups().Finite(): + cat = cat.Finite() + from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(), + libgap_subgroup, ambient=self, + category=cat) + + from sage.groups.generic import structure_description diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index 39bb43c710a..f2770a3ec9f 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -40,9 +40,9 @@ # http://www.gnu.org/licenses/ ############################################################################## +from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic +form sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap from sage.structure.unique_representation import CachedRepresentation -from sage.groups.matrix_gps.matrix_group import ( - MatrixGroup_generic, MatrixGroup_gap ) def normalize_args_vectorspace(*args, **kwds): @@ -298,42 +298,3 @@ def __richcmp__(self, other, op): False """ return MatrixGroup_generic.__richcmp__(self, other, op) - - -class NamedMatrixGroup_gap(NamedMatrixGroup_generic, MatrixGroup_gap): - - def __init__(self, degree, base_ring, special, sage_name, latex_string, - gap_command_string, category=None): - """ - Base class for "named" matrix groups using LibGAP - - INPUT: - - - ``degree`` -- integer. The degree (number of rows/columns of - matrices). - - - ``base_ring`` -- ring. The base ring of the matrices. - - - ``special`` -- boolean. Whether the matrix group is special, - that is, elements have determinant one. - - - ``latex_string`` -- string. The latex representation. - - - ``gap_command_string`` -- string. The GAP command to construct - the matrix group. - - EXAMPLES:: - - sage: G = GL(2, GF(3)) - sage: from sage.groups.matrix_gps.named_group import NamedMatrixGroup_gap - sage: isinstance(G, NamedMatrixGroup_gap) - True - """ - from sage.libs.gap.libgap import libgap - group = libgap.eval(gap_command_string) - MatrixGroup_gap.__init__(self, degree, base_ring, group, - category=category) - self._special = special - self._gap_string = gap_command_string - self._name_string = sage_name - self._latex_string = latex_string diff --git a/src/sage/groups/matrix_gps/named_group_gap.py b/src/sage/groups/matrix_gps/named_group_gap.py new file mode 100644 index 00000000000..ff2b3c66eae --- /dev/null +++ b/src/sage/groups/matrix_gps/named_group_gap.py @@ -0,0 +1,44 @@ +""" +Base for Classical Matrix Groups with GAP +""" + +from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap +from sage.groups.matrix_gps.named_group import NamedMatrixGroup_generic + +class NamedMatrixGroup_gap(NamedMatrixGroup_generic, MatrixGroup_gap): + + def __init__(self, degree, base_ring, special, sage_name, latex_string, + gap_command_string, category=None): + """ + Base class for "named" matrix groups using LibGAP + + INPUT: + + - ``degree`` -- integer. The degree (number of rows/columns of + matrices). + + - ``base_ring`` -- ring. The base ring of the matrices. + + - ``special`` -- boolean. Whether the matrix group is special, + that is, elements have determinant one. + + - ``latex_string`` -- string. The latex representation. + + - ``gap_command_string`` -- string. The GAP command to construct + the matrix group. + + EXAMPLES:: + + sage: G = GL(2, GF(3)) + sage: from sage.groups.matrix_gps.named_group import NamedMatrixGroup_gap + sage: isinstance(G, NamedMatrixGroup_gap) + True + """ + from sage.libs.gap.libgap import libgap + group = libgap.eval(gap_command_string) + MatrixGroup_gap.__init__(self, degree, base_ring, group, + category=category) + self._special = special + self._gap_string = gap_command_string + self._name_string = sage_name + self._latex_string = latex_string diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 8ff96051a8b..8db16de0e90 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -90,8 +90,8 @@ from sage.misc.cachefunc import cached_method from sage.groups.matrix_gps.named_group import ( normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic, NamedMatrixGroup_gap) -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + NamedMatrixGroup_generic) + def normalize_args_e(degree, ring, e): """ @@ -531,120 +531,3 @@ def _check_matrix(self, x, *args): else: raise TypeError('matrix must be orthogonal with respect to the symmetric form\n%s' %(F)) # TODO: check that quadratic form is preserved in characteristic two - -class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): - r""" - The general or special orthogonal group in GAP. - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = GO(3,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - @cached_method - def invariant_bilinear_form(self): - """ - Return the symmetric bilinear form preserved by the orthogonal - group. - - OUTPUT: - - A matrix `M` such that, for every group element g, the - identity `g m g^T = m` holds. In characteristic different from - two, this uniquely determines the orthogonal group. - - EXAMPLES:: - - sage: G = GO(4, GF(7), -1) - sage: G.invariant_bilinear_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - - sage: G = GO(4, GF(7), +1) - sage: G.invariant_bilinear_form() - [0 1 0 0] - [1 0 0 0] - [0 0 6 0] - [0 0 0 2] - - sage: G = SO(4, GF(7), -1) - sage: G.invariant_bilinear_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - - TESTS:: - - sage: G.invariant_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - """ - m = self.gap().InvariantBilinearForm()['matrix'].matrix() - m.set_immutable() - return m - - invariant_form = invariant_bilinear_form # alias (analogues to symplectic and unitary cases) - - @cached_method - def invariant_quadratic_form(self): - r""" - Return the quadratic form preserved by the orthogonal group. - - OUTPUT: - - The matrix `Q` defining "orthogonal" as follows. The matrix - determines a quadratic form `q` on the natural vector space - `V`, on which `G` acts, by `q(v) = v Q v^t`. A matrix `M` is - an element of the orthogonal group if `q(v) = q(v M)` for all - `v \in V`. - - EXAMPLES:: - - sage: G = GO(4, GF(7), -1) - sage: G.invariant_quadratic_form() - [0 1 0 0] - [0 0 0 0] - [0 0 1 0] - [0 0 0 1] - - sage: G = GO(4, GF(7), +1) - sage: G.invariant_quadratic_form() - [0 1 0 0] - [0 0 0 0] - [0 0 3 0] - [0 0 0 1] - - sage: G = GO(4, QQ) - sage: G.invariant_quadratic_form() - [1 0 0 0] - [0 1 0 0] - [0 0 1 0] - [0 0 0 1] - - sage: G = SO(4, GF(7), -1) - sage: G.invariant_quadratic_form() - [0 1 0 0] - [0 0 0 0] - [0 0 1 0] - [0 0 0 1] - - TESTS:: - - sage: GO(4, GF(7), -1).invariant_form() - [0 1 0 0] - [1 0 0 0] - [0 0 2 0] - [0 0 0 2] - """ - m = self.gap().InvariantQuadraticForm()['matrix'].matrix() - m.set_immutable() - return m diff --git a/src/sage/groups/matrix_gps/orthogonal_gap.py b/src/sage/groups/matrix_gps/orthogonal_gap.py new file mode 100644 index 00000000000..e1ad894eedf --- /dev/null +++ b/src/sage/groups/matrix_gps/orthogonal_gap.py @@ -0,0 +1,125 @@ +r""" +Orthogonal Linear Groups with GAP +""" + +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.orthogonal import OrthogonalMatrixGroup_generic + + +class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): + r""" + The general or special orthogonal group in GAP. + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: G = GO(3,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + @cached_method + def invariant_bilinear_form(self): + """ + Return the symmetric bilinear form preserved by the orthogonal + group. + + OUTPUT: + + A matrix `M` such that, for every group element g, the + identity `g m g^T = m` holds. In characteristic different from + two, this uniquely determines the orthogonal group. + + EXAMPLES:: + + sage: G = GO(4, GF(7), -1) + sage: G.invariant_bilinear_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + + sage: G = GO(4, GF(7), +1) + sage: G.invariant_bilinear_form() + [0 1 0 0] + [1 0 0 0] + [0 0 6 0] + [0 0 0 2] + + sage: G = SO(4, GF(7), -1) + sage: G.invariant_bilinear_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + + TESTS:: + + sage: G.invariant_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + """ + m = self.gap().InvariantBilinearForm()['matrix'].matrix() + m.set_immutable() + return m + + invariant_form = invariant_bilinear_form # alias (analogues to symplectic and unitary cases) + + @cached_method + def invariant_quadratic_form(self): + r""" + Return the quadratic form preserved by the orthogonal group. + + OUTPUT: + + The matrix `Q` defining "orthogonal" as follows. The matrix + determines a quadratic form `q` on the natural vector space + `V`, on which `G` acts, by `q(v) = v Q v^t`. A matrix `M` is + an element of the orthogonal group if `q(v) = q(v M)` for all + `v \in V`. + + EXAMPLES:: + + sage: G = GO(4, GF(7), -1) + sage: G.invariant_quadratic_form() + [0 1 0 0] + [0 0 0 0] + [0 0 1 0] + [0 0 0 1] + + sage: G = GO(4, GF(7), +1) + sage: G.invariant_quadratic_form() + [0 1 0 0] + [0 0 0 0] + [0 0 3 0] + [0 0 0 1] + + sage: G = GO(4, QQ) + sage: G.invariant_quadratic_form() + [1 0 0 0] + [0 1 0 0] + [0 0 1 0] + [0 0 0 1] + + sage: G = SO(4, GF(7), -1) + sage: G.invariant_quadratic_form() + [0 1 0 0] + [0 0 0 0] + [0 0 1 0] + [0 0 0 1] + + TESTS:: + + sage: GO(4, GF(7), -1).invariant_form() + [0 1 0 0] + [1 0 0 0] + [0 0 2 0] + [0 0 0 2] + """ + m = self.gap().InvariantQuadraticForm()['matrix'].matrix() + m.set_immutable() + return m diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index 3715f531913..a1814e7cd79 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -45,8 +45,7 @@ from sage.rings.finite_rings.finite_field_base import is_FiniteField from sage.groups.matrix_gps.named_group import ( normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic, NamedMatrixGroup_gap) -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + NamedMatrixGroup_generic) ############################################################################### @@ -238,47 +237,3 @@ def _check_matrix(self, x, *args): F = self.invariant_form() if x * F * x.transpose() != F: raise TypeError('matrix must be symplectic with respect to the alternating form\n{}'.format(F)) - - -class SymplecticMatrixGroup_gap(SymplecticMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): - r""" - Symplectic group in GAP. - - EXAMPLES:: - - sage: Sp(2,4) - Symplectic Group of degree 2 over Finite Field in a of size 2^2 - - sage: latex(Sp(4,5)) - \text{Sp}_{4}(\Bold{F}_{5}) - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = Sp(4,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - - @cached_method - def invariant_form(self): - """ - Return the quadratic form preserved by the symplectic group. - - OUTPUT: - - A matrix. - - EXAMPLES:: - - sage: Sp(4, GF(3)).invariant_form() - [0 0 0 1] - [0 0 1 0] - [0 2 0 0] - [2 0 0 0] - """ - m = self.gap().InvariantBilinearForm()['matrix'].matrix() - m.set_immutable() - return m diff --git a/src/sage/groups/matrix_gps/symplectic_gap.py b/src/sage/groups/matrix_gps/symplectic_gap.py new file mode 100644 index 00000000000..d05f87323a3 --- /dev/null +++ b/src/sage/groups/matrix_gps/symplectic_gap.py @@ -0,0 +1,51 @@ +""" +Symplectic Linear Groups with GAP +""" + +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.symplectic import SymplecticMatrixGroup_generic + + +class SymplecticMatrixGroup_gap(SymplecticMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): + r""" + Symplectic group in GAP. + + EXAMPLES:: + + sage: Sp(2,4) + Symplectic Group of degree 2 over Finite Field in a of size 2^2 + + sage: latex(Sp(4,5)) + \text{Sp}_{4}(\Bold{F}_{5}) + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: G = Sp(4,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + + @cached_method + def invariant_form(self): + """ + Return the quadratic form preserved by the symplectic group. + + OUTPUT: + + A matrix. + + EXAMPLES:: + + sage: Sp(4, GF(3)).invariant_form() + [0 0 0 1] + [0 0 1 0] + [0 2 0 0] + [2 0 0 0] + """ + m = self.gap().InvariantBilinearForm()['matrix'].matrix() + m.set_immutable() + return m diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index f4d8df525be..60985e22b7a 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -434,43 +434,3 @@ def _check_matrix(self, x, *args): raise TypeError('matrix must be unitary') else: raise TypeError('matrix must be unitary with respect to the hermitian form\n{}'.format(H)) - -class UnitaryMatrixGroup_gap(UnitaryMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): - r""" - The general or special unitary group in GAP. - - TESTS: - - Check that :trac:`20867` is fixed:: - - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap - sage: G = GU(3,3) - sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) - True - """ - - @cached_method - def invariant_form(self): - """ - Return the hermitian form preserved by the unitary group. - - OUTPUT: - - A square matrix describing the bilinear form - - EXAMPLES:: - - sage: G32=GU(3,2) - sage: G32.invariant_form() - [0 0 1] - [0 1 0] - [1 0 0] - """ - d = self.degree() - R = self.base_ring() - # note that self.gap().InvariantSesquilinearForm()['matrix'].matrix().base_ring() != R for example for self = GU(3.2) - # therefore we have to coerce into the right matrix space - from sage.matrix.constructor import matrix - m = matrix(R, d, d, self.gap().InvariantSesquilinearForm()['matrix'].matrix()) - m.set_immutable() - return m diff --git a/src/sage/groups/matrix_gps/unitary_gap.py b/src/sage/groups/matrix_gps/unitary_gap.py new file mode 100644 index 00000000000..e2eece2779f --- /dev/null +++ b/src/sage/groups/matrix_gps/unitary_gap.py @@ -0,0 +1,48 @@ +r""" +Unitary Groups `GU(n,q)` and `SU(n,q)` with GAP +""" + +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap +from sage.groups.matrix_gps.unitary import UnitaryMatrixGroup_generic + + +class UnitaryMatrixGroup_gap(UnitaryMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): + r""" + The general or special unitary group in GAP. + + TESTS: + + Check that :trac:`20867` is fixed:: + + sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: G = GU(3,3) + sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) + True + """ + + @cached_method + def invariant_form(self): + """ + Return the hermitian form preserved by the unitary group. + + OUTPUT: + + A square matrix describing the bilinear form + + EXAMPLES:: + + sage: G32=GU(3,2) + sage: G32.invariant_form() + [0 0 1] + [0 1 0] + [1 0 0] + """ + d = self.degree() + R = self.base_ring() + # note that self.gap().InvariantSesquilinearForm()['matrix'].matrix().base_ring() != R for example for self = GU(3.2) + # therefore we have to coerce into the right matrix space + from sage.matrix.constructor import matrix + m = matrix(R, d, d, self.gap().InvariantSesquilinearForm()['matrix'].matrix()) + m.set_immutable() + return m From c95f132f14b19a01bda4d808621efe351e21f377 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 16:43:39 -0700 Subject: [PATCH 02/18] sage.groups.matrix_gps: Update imports of ..._gap classes --- src/sage/categories/primer.py | 4 ++-- src/sage/combinat/root_system/weyl_group.py | 4 ++-- src/sage/groups/matrix_gps/binary_dihedral.py | 2 +- src/sage/groups/matrix_gps/finitely_generated_gap.py | 2 +- src/sage/groups/matrix_gps/heisenberg.py | 2 +- src/sage/groups/matrix_gps/isometries.py | 2 +- src/sage/groups/matrix_gps/linear.py | 4 ++++ src/sage/groups/matrix_gps/linear_gap.py | 2 +- src/sage/groups/matrix_gps/matrix_group_gap.py | 4 ++-- src/sage/groups/matrix_gps/named_group_gap.py | 2 +- src/sage/groups/matrix_gps/orthogonal.py | 2 ++ src/sage/groups/matrix_gps/orthogonal_gap.py | 2 +- src/sage/groups/matrix_gps/pickling_overrides.py | 2 +- src/sage/groups/matrix_gps/symplectic.py | 2 ++ src/sage/groups/matrix_gps/symplectic_gap.py | 2 +- src/sage/groups/matrix_gps/unitary.py | 5 +++-- src/sage/groups/matrix_gps/unitary_gap.py | 2 +- 17 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index 96dff8e2631..7ecc75e711a 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -524,12 +524,12 @@ class implements: sage: G = GL(2,ZZ) sage: type(G) - + Here is a piece of the hierarchy of classes above it:: sage: for cls in G.__class__.mro(): print(cls) - + ... diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index d64d2c1f366..bfbafcd522c 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -39,8 +39,8 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap -from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.group_element_gap import MatrixGroupElement_gap from sage.groups.perm_gps.permgroup import PermutationGroup_generic from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ diff --git a/src/sage/groups/matrix_gps/binary_dihedral.py b/src/sage/groups/matrix_gps/binary_dihedral.py index 0edae3511c2..c8813eeabd4 100644 --- a/src/sage/groups/matrix_gps/binary_dihedral.py +++ b/src/sage/groups/matrix_gps/binary_dihedral.py @@ -16,7 +16,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.structure.unique_representation import UniqueRepresentation from sage.rings.number_field.number_field import CyclotomicField from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py index 4d85c9f84a0..e76dbb770d4 100644 --- a/src/sage/groups/matrix_gps/finitely_generated_gap.py +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -19,7 +19,7 @@ class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap): [3 4], [10 0] ) sage: type(G) - + sage: TestSuite(G).run() """ diff --git a/src/sage/groups/matrix_gps/heisenberg.py b/src/sage/groups/matrix_gps/heisenberg.py index 68832525331..a3b74081750 100644 --- a/src/sage/groups/matrix_gps/heisenberg.py +++ b/src/sage/groups/matrix_gps/heisenberg.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.structure.unique_representation import UniqueRepresentation from sage.misc.latex import latex from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/groups/matrix_gps/isometries.py b/src/sage/groups/matrix_gps/isometries.py index cca45e71752..e7445166db6 100644 --- a/src/sage/groups/matrix_gps/isometries.py +++ b/src/sage/groups/matrix_gps/isometries.py @@ -39,7 +39,7 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.categories.action import Action diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index 15714ca81bf..bc7ea013a5e 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -163,6 +163,8 @@ def GL(n, R, var='a'): name = 'General Linear Group of degree {0} over {1}'.format(degree, ring) ltx = 'GL({0}, {1})'.format(degree, latex(ring)) try: + from .linear_gap import LinearMatrixGroup_gap + cmd = 'GL({0}, {1})'.format(degree, ring._gap_init_()) return LinearMatrixGroup_gap(degree, ring, False, name, ltx, cmd, category=cat) @@ -248,6 +250,8 @@ def SL(n, R, var='a'): name = 'Special Linear Group of degree {0} over {1}'.format(degree, ring) ltx = 'SL({0}, {1})'.format(degree, latex(ring)) try: + from .linear_gap import LinearMatrixGroup_gap + cmd = 'SL({0}, {1})'.format(degree, ring._gap_init_()) return LinearMatrixGroup_gap(degree, ring, True, name, ltx, cmd, category=cat) diff --git a/src/sage/groups/matrix_gps/linear_gap.py b/src/sage/groups/matrix_gps/linear_gap.py index 7f2be376d2f..37d33d5d2be 100644 --- a/src/sage/groups/matrix_gps/linear_gap.py +++ b/src/sage/groups/matrix_gps/linear_gap.py @@ -15,7 +15,7 @@ class LinearMatrixGroup_gap(NamedMatrixGroup_gap, LinearMatrixGroup_generic, Fin Check that :trac:`20867` is fixed:: - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap sage: G = GL(3,3) sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) True diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py index fe5a465d734..a78bf73e629 100644 --- a/src/sage/groups/matrix_gps/matrix_group_gap.py +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -32,7 +32,7 @@ def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None) :: - sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_gap + sage: from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap sage: MatrixGroup_gap(2, ZZ, libgap.eval('GL(2, Integers)')) Matrix group over Integer Ring with 3 generators ( [0 1] [-1 0] [1 1] @@ -283,7 +283,7 @@ def _subgroup_constructor(self, libgap_subgroup): cat = Groups() if self in Groups().Finite(): cat = cat.Finite() - from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(), libgap_subgroup, ambient=self, category=cat) diff --git a/src/sage/groups/matrix_gps/named_group_gap.py b/src/sage/groups/matrix_gps/named_group_gap.py index ff2b3c66eae..ecc24d0bd1a 100644 --- a/src/sage/groups/matrix_gps/named_group_gap.py +++ b/src/sage/groups/matrix_gps/named_group_gap.py @@ -30,7 +30,7 @@ def __init__(self, degree, base_ring, special, sage_name, latex_string, EXAMPLES:: sage: G = GL(2, GF(3)) - sage: from sage.groups.matrix_gps.named_group import NamedMatrixGroup_gap + sage: from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap sage: isinstance(G, NamedMatrixGroup_gap) True """ diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 8db16de0e90..1e64a80d850 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -203,6 +203,8 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): '+' if e == 1 else '-') if is_FiniteField(ring): + from .orthogonal_gap import OrthogonalMatrixGroup_gap + cmd = '{0}O({1}, {2}, {3})'.format(ltx_prefix, e, degree, ring.order()) return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd) else: diff --git a/src/sage/groups/matrix_gps/orthogonal_gap.py b/src/sage/groups/matrix_gps/orthogonal_gap.py index e1ad894eedf..182e4609925 100644 --- a/src/sage/groups/matrix_gps/orthogonal_gap.py +++ b/src/sage/groups/matrix_gps/orthogonal_gap.py @@ -15,7 +15,7 @@ class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_ Check that :trac:`20867` is fixed:: - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap sage: G = GO(3,3) sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) True diff --git a/src/sage/groups/matrix_gps/pickling_overrides.py b/src/sage/groups/matrix_gps/pickling_overrides.py index d8d68ffd22f..2c4176f5982 100644 --- a/src/sage/groups/matrix_gps/pickling_overrides.py +++ b/src/sage/groups/matrix_gps/pickling_overrides.py @@ -4,7 +4,7 @@ from sage.structure.sage_object import register_unpickle_override -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap +from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap from sage.groups.matrix_gps.linear import GL, LinearMatrixGroup_generic diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index a1814e7cd79..87775331967 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -160,6 +160,8 @@ def Sp(n, R, var='a', invariant_form=None): ltx = r'\text{{Sp}}_{{{0}}}({1})'.format(degree, latex(ring)) try: + from .symplectic_gap import SymplecticMatrixGroup_gap + cmd = 'Sp({0}, {1})'.format(degree, ring._gap_init_()) return SymplecticMatrixGroup_gap(degree, ring, True, name, ltx, cmd) except ValueError: diff --git a/src/sage/groups/matrix_gps/symplectic_gap.py b/src/sage/groups/matrix_gps/symplectic_gap.py index d05f87323a3..2e6e48f41d8 100644 --- a/src/sage/groups/matrix_gps/symplectic_gap.py +++ b/src/sage/groups/matrix_gps/symplectic_gap.py @@ -23,7 +23,7 @@ class SymplecticMatrixGroup_gap(SymplecticMatrixGroup_generic, NamedMatrixGroup_ Check that :trac:`20867` is fixed:: - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap sage: G = Sp(4,3) sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) True diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index 60985e22b7a..d78f63ab33b 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -55,8 +55,7 @@ from sage.misc.cachefunc import cached_method from sage.groups.matrix_gps.named_group import ( normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic, NamedMatrixGroup_gap ) -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + NamedMatrixGroup_generic) def finite_field_sqrt(ring): @@ -135,6 +134,8 @@ def _UG(n, R, special, var='a', invariant_form=None): ltx = r'\text{{{0}U}}_{{{1}}}({2})'.format(latex_prefix, degree, latex(ring)) if is_FiniteField(ring): + from .unitary import UnitaryMatrixGroup_gap + cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q) return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd) else: diff --git a/src/sage/groups/matrix_gps/unitary_gap.py b/src/sage/groups/matrix_gps/unitary_gap.py index e2eece2779f..28dc94b8b48 100644 --- a/src/sage/groups/matrix_gps/unitary_gap.py +++ b/src/sage/groups/matrix_gps/unitary_gap.py @@ -15,7 +15,7 @@ class UnitaryMatrixGroup_gap(UnitaryMatrixGroup_generic, NamedMatrixGroup_gap, F Check that :trac:`20867` is fixed:: - sage: from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap + sage: from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap sage: G = GU(3,3) sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) True From d6d5747a3ec7168e6eb28b874611a63434b15267 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 17:25:18 -0700 Subject: [PATCH 03/18] sage.groups.matrix_gps: Move MatrixGroupElement_gap class to a separate ..._gap module --- src/sage/groups/matrix_gps/group_element.pxd | 6 - src/sage/groups/matrix_gps/group_element.pyx | 414 +----------------- .../groups/matrix_gps/group_element_gap.pxd | 5 + .../groups/matrix_gps/group_element_gap.pyx | 404 +++++++++++++++++ .../groups/matrix_gps/pickling_overrides.py | 3 +- 5 files changed, 419 insertions(+), 413 deletions(-) create mode 100644 src/sage/groups/matrix_gps/group_element_gap.pxd create mode 100644 src/sage/groups/matrix_gps/group_element_gap.pyx diff --git a/src/sage/groups/matrix_gps/group_element.pxd b/src/sage/groups/matrix_gps/group_element.pxd index df5f99aeca9..36a5a9fc4ce 100644 --- a/src/sage/groups/matrix_gps/group_element.pxd +++ b/src/sage/groups/matrix_gps/group_element.pxd @@ -1,5 +1,4 @@ from sage.structure.element cimport MultiplicativeGroupElement, Element, MonoidElement, Matrix -from sage.groups.libgap_wrapper cimport ElementLibGAP cpdef is_MatrixGroupElement(x) @@ -9,8 +8,3 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): cpdef _act_on_(self, x, bint self_on_left) cpdef _mul_(self, other) cpdef list list(self) - -cdef class MatrixGroupElement_gap(ElementLibGAP): - cpdef _act_on_(self, x, bint self_on_left) - cpdef list list(self) - diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 4d0312efdf9..e543e3e43ae 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -75,16 +75,18 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.element cimport MultiplicativeGroupElement, Element, MonoidElement, Matrix +from sage.misc.cachefunc import cached_method +from sage.rings.integer_ring import ZZ +from sage.structure.element cimport MultiplicativeGroupElement, Matrix +from sage.structure.element import is_Matrix from sage.structure.parent cimport Parent from sage.structure.richcmp cimport richcmp -from sage.libs.gap.element cimport GapElement, GapElement_List -from sage.groups.libgap_wrapper cimport ElementLibGAP -from sage.structure.element import is_Matrix -from sage.structure.factorization import Factorization -from sage.misc.cachefunc import cached_method -from sage.rings.integer_ring import ZZ + +try: + from .group_element_gap import MatrixGroupElement_gap +except ImportError: + MatrixGroupElement_gap = () cpdef is_MatrixGroupElement(x): @@ -409,404 +411,6 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): inverse = __invert__ -################################################################### -# -# Matrix group elements implemented in GAP -# -################################################################### - -cdef class MatrixGroupElement_gap(ElementLibGAP): - """ - Element of a matrix group over a generic ring. - - The group elements are implemented as wrappers around libGAP matrices. - - INPUT: - - - ``M`` -- a matrix - - - ``parent`` -- the parent - - - ``check`` -- bool (default: ``True``); if ``True`` does some - type checking - - - ``convert`` -- bool (default: ``True``); if ``True`` convert - ``M`` to the right matrix space - """ - def __init__(self, parent, M, check=True, convert=True): - r""" - Initialize ``self``. - - TESTS:: - - sage: MS = MatrixSpace(GF(3),2,2) - sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) - sage: G.gen(0) - [1 0] - [0 1] - sage: g = G.random_element() - sage: TestSuite(g).run() - """ - if isinstance(M, GapElement): - ElementLibGAP.__init__(self, parent, M) - return - if convert: - M = parent.matrix_space()(M) - from sage.libs.gap.libgap import libgap - M_gap = libgap(M) - if check: - if not is_Matrix(M): - raise TypeError('M must be a matrix') - if M.parent() is not parent.matrix_space(): - raise TypeError('M must be a in the matrix space of the group') - parent._check_matrix(M, M_gap) - ElementLibGAP.__init__(self, parent, M_gap) - - def __reduce__(self): - """ - Implement pickling. - - TESTS:: - - sage: MS = MatrixSpace(GF(3), 2, 2) - sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) - sage: loads(G.gen(0).dumps()) - [1 0] - [0 1] - """ - return (self.parent(), (self.matrix(),)) - - def __hash__(self): - r""" - TESTS:: - - sage: MS = MatrixSpace(GF(3), 2) - sage: G = MatrixGroup([MS([1,1,0,1]), MS([1,0,1,1])]) - sage: g = G.an_element() - sage: hash(g) - -5306160029685893860 # 64-bit - -181258980 # 32-bit - """ - return hash(self.matrix()) - - def _repr_(self): - r""" - Return string representation of this matrix. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: g = G([[1, 1], [0, 1]]) - sage: g # indirect doctest - [1 1] - [0 1] - sage: g._repr_() - '[1 1]\n[0 1]' - """ - return str(self.matrix()) - - def _latex_(self): - r""" - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: g = G([[1, 1], [0, 1]]) - sage: print(g._latex_()) - \left(\begin{array}{rr} - 1 & 1 \\ - 0 & 1 - \end{array}\right) - - Type ``view(g._latex_())`` to see the object in an - xdvi window (assuming you have latex and xdvi installed). - """ - return self.matrix()._latex_() - - cpdef _act_on_(self, x, bint self_on_left): - """ - EXAMPLES:: - - sage: G = GL(4,7) - sage: G.0 * vector([1,2,3,4]) - (3, 2, 3, 4) - sage: v = vector(GF(7), [3,2,1,-1]) - sage: g = G.1 - sage: v * g == v * g.matrix() # indirect doctest - True - """ - if not is_MatrixGroupElement(x) and x not in self.parent().base_ring(): - try: - if self_on_left: - return self.matrix() * x - else: - return x * self.matrix() - except TypeError: - return None - - cpdef _richcmp_(self, other, int op): - """ - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2) - sage: gens = [MS([1,0, 0,1]), MS([1,1, 0,1])] - sage: G = MatrixGroup(gens) - sage: g = G([1,1, 0,1]) - sage: h = G([1,1, 0,1]) - sage: g == h - True - sage: g == G.one() - False - """ - return richcmp(self.matrix(), other.matrix(), op) - - @cached_method - def matrix(self): - """ - Obtain the usual matrix (as an element of a matrix space) - associated to this matrix group element. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: m = G.gen(0).matrix(); m - [1 0] - [0 1] - sage: m.parent() - Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 - - sage: k = GF(7); G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]) - sage: g = G.0 - sage: g.matrix() - [1 1] - [0 1] - sage: parent(g.matrix()) - Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 - - Matrices have extra functionality that matrix group elements - do not have:: - - sage: g.matrix().charpoly('t') - t^2 + 5*t + 1 - """ - # We do a slightly specialized version of sage.libs.gap.element.GapElement.matrix() - # in order to use our current matrix space directly and avoid - # some overhead safety checks. - entries = self.gap().Flat() - MS = self.parent().matrix_space() - ring = MS.base_ring() - m = MS([x.sage(ring=ring) for x in entries]) - m.set_immutable() - return m - - def _matrix_(self, base=None): - """ - Method used by the :func:`matrix` constructor. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: G = MatrixGroup([MS([1,1,0,1])]) - sage: g = G.gen(0) - sage: M = matrix(GF(9), g); M; parent(M) - [1 1] - [0 1] - Full MatrixSpace of 2 by 2 dense matrices over Finite Field in z2 of size 3^2 - """ - return self.matrix() - - cpdef list list(self): - """ - Return list representation of this matrix. - - EXAMPLES:: - - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: g = G.0 - sage: g - [1 0] - [0 1] - sage: g.list() - [[1, 0], [0, 1]] - """ - return [r.list() for r in self.matrix().rows()] - - @cached_method - def multiplicative_order(self): - """ - Return the order of this group element, which is the smallest - positive integer `n` such that `g^n = 1`, or - +Infinity if no such integer exists. - - EXAMPLES:: - - sage: k = GF(7) - sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G - Matrix group over Finite Field of size 7 with 2 generators ( - [1 1] [1 0] - [0 1], [0 2] - ) - sage: G.order() - 21 - sage: G.gen(0).multiplicative_order(), G.gen(1).multiplicative_order() - (7, 3) - - ``order`` is just an alias for ``multiplicative_order``:: - - sage: G.gen(0).order(), G.gen(1).order() - (7, 3) - - sage: k = QQ - sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G - Matrix group over Rational Field with 2 generators ( - [1 1] [1 0] - [0 1], [0 2] - ) - sage: G.order() - +Infinity - sage: G.gen(0).order(), G.gen(1).order() - (+Infinity, +Infinity) - - sage: gl = GL(2, ZZ); gl - General Linear Group of degree 2 over Integer Ring - sage: g = gl.gen(2); g - [1 1] - [0 1] - sage: g.order() - +Infinity - """ - order = self.gap().Order() - if order.IsInt(): - return order.sage() - else: - assert order.IsInfinity() - from sage.rings.infinity import Infinity - return Infinity - - def word_problem(self, gens=None): - r""" - Solve the word problem. - - This method writes the group element as a product of the - elements of the list ``gens``, or the standard generators of - the parent of self if ``gens`` is None. - - INPUT: - - - ``gens`` -- a list/tuple/iterable of elements (or objects - that can be converted to group elements), or ``None`` - (default). By default, the generators of the parent group - are used. - - OUTPUT: - - A factorization object that contains information about the - order of factors and the exponents. A ``ValueError`` is raised - if the group element cannot be written as a word in ``gens``. - - ALGORITHM: - - Use GAP, which has optimized algorithms for solving the word - problem (the GAP functions ``EpimorphismFromFreeGroup`` and - ``PreImagesRepresentative``). - - EXAMPLES:: - - sage: G = GL(2,5); G - General Linear Group of degree 2 over Finite Field of size 5 - sage: G.gens() - ( - [2 0] [4 1] - [0 1], [4 0] - ) - sage: G(1).word_problem([G.gen(0)]) - 1 - sage: type(_) - - - sage: g = G([0,4,1,4]) - sage: g.word_problem() - ([4 1] - [4 0])^-1 - - Next we construct a more complicated element of the group from the - generators:: - - sage: s,t = G.0, G.1 - sage: a = (s * t * s); b = a.word_problem(); b - ([2 0] - [0 1]) * - ([4 1] - [4 0]) * - ([2 0] - [0 1]) - sage: flatten(b) - [ - [2 0] [4 1] [2 0] - [0 1], 1, [4 0], 1, [0 1], 1 - ] - sage: b.prod() == a - True - - We solve the word problem using some different generators:: - - sage: s = G([2,0,0,1]); t = G([1,1,0,1]); u = G([0,-1,1,0]) - sage: a.word_problem([s,t,u]) - ([2 0] - [0 1])^-1 * - ([1 1] - [0 1])^-1 * - ([0 4] - [1 0]) * - ([2 0] - [0 1])^-1 - - We try some elements that don't actually generate the group:: - - sage: a.word_problem([t,u]) - Traceback (most recent call last): - ... - ValueError: word problem has no solution - - AUTHORS: - - - David Joyner and William Stein - - David Loeffler (2010): fixed some bugs - - Volker Braun (2013): LibGAP - """ - from sage.libs.gap.libgap import libgap - G = self.parent() - if gens: - gen = lambda i:gens[i] - H = libgap.Group([G(x).gap() for x in gens]) - else: - gen = G.gen - H = G.gap() - hom = H.EpimorphismFromFreeGroup() - preimg = hom.PreImagesRepresentative(self.gap()) - - if preimg.is_bool(): - assert preimg == libgap.eval('fail') - raise ValueError('word problem has no solution') - - result = [] - n = preimg.NumberSyllables().sage() - exponent_syllable = libgap.eval('ExponentSyllable') - generator_syllable = libgap.eval('GeneratorSyllable') - for i in range(n): - exponent = exponent_syllable(preimg, i+1).sage() - generator = gen(generator_syllable(preimg, i+1).sage() - 1) - result.append( (generator, exponent) ) - result = Factorization(result) - result._set_cr(True) - return result def _unpickle_generic_element(G, mat): """ diff --git a/src/sage/groups/matrix_gps/group_element_gap.pxd b/src/sage/groups/matrix_gps/group_element_gap.pxd new file mode 100644 index 00000000000..e0ecbefea5c --- /dev/null +++ b/src/sage/groups/matrix_gps/group_element_gap.pxd @@ -0,0 +1,5 @@ +from sage.groups.libgap_wrapper cimport ElementLibGAP + +cdef class MatrixGroupElement_gap(ElementLibGAP): + cpdef _act_on_(self, x, bint self_on_left) + cpdef list list(self) diff --git a/src/sage/groups/matrix_gps/group_element_gap.pyx b/src/sage/groups/matrix_gps/group_element_gap.pyx new file mode 100644 index 00000000000..2e6116e7871 --- /dev/null +++ b/src/sage/groups/matrix_gps/group_element_gap.pyx @@ -0,0 +1,404 @@ +r""" +Matrix group elements implemented in GAP +""" + +from sage.groups.matrix_gps.group_element cimport is_MatrixGroupElement +from sage.libs.gap.element cimport GapElement, GapElement_List +from sage.misc.cachefunc import cached_method +from sage.structure.element import is_Matrix +from sage.structure.factorization import Factorization +from sage.structure.richcmp cimport richcmp + + +cdef class MatrixGroupElement_gap(ElementLibGAP): + """ + Element of a matrix group over a generic ring. + + The group elements are implemented as wrappers around libGAP matrices. + + INPUT: + + - ``M`` -- a matrix + + - ``parent`` -- the parent + + - ``check`` -- bool (default: ``True``); if ``True`` does some + type checking + + - ``convert`` -- bool (default: ``True``); if ``True`` convert + ``M`` to the right matrix space + """ + def __init__(self, parent, M, check=True, convert=True): + r""" + Initialize ``self``. + + TESTS:: + + sage: MS = MatrixSpace(GF(3),2,2) + sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) + sage: G.gen(0) + [1 0] + [0 1] + sage: g = G.random_element() + sage: TestSuite(g).run() + """ + if isinstance(M, GapElement): + ElementLibGAP.__init__(self, parent, M) + return + if convert: + M = parent.matrix_space()(M) + from sage.libs.gap.libgap import libgap + M_gap = libgap(M) + if check: + if not is_Matrix(M): + raise TypeError('M must be a matrix') + if M.parent() is not parent.matrix_space(): + raise TypeError('M must be a in the matrix space of the group') + parent._check_matrix(M, M_gap) + ElementLibGAP.__init__(self, parent, M_gap) + + def __reduce__(self): + """ + Implement pickling. + + TESTS:: + + sage: MS = MatrixSpace(GF(3), 2, 2) + sage: G = MatrixGroup(MS([[1,0],[0,1]]), MS([[1,1],[0,1]])) + sage: loads(G.gen(0).dumps()) + [1 0] + [0 1] + """ + return (self.parent(), (self.matrix(),)) + + def __hash__(self): + r""" + TESTS:: + + sage: MS = MatrixSpace(GF(3), 2) + sage: G = MatrixGroup([MS([1,1,0,1]), MS([1,0,1,1])]) + sage: g = G.an_element() + sage: hash(g) + -5306160029685893860 # 64-bit + -181258980 # 32-bit + """ + return hash(self.matrix()) + + def _repr_(self): + r""" + Return string representation of this matrix. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: g = G([[1, 1], [0, 1]]) + sage: g # indirect doctest + [1 1] + [0 1] + sage: g._repr_() + '[1 1]\n[0 1]' + """ + return str(self.matrix()) + + def _latex_(self): + r""" + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: g = G([[1, 1], [0, 1]]) + sage: print(g._latex_()) + \left(\begin{array}{rr} + 1 & 1 \\ + 0 & 1 + \end{array}\right) + + Type ``view(g._latex_())`` to see the object in an + xdvi window (assuming you have latex and xdvi installed). + """ + return self.matrix()._latex_() + + cpdef _act_on_(self, x, bint self_on_left): + """ + EXAMPLES:: + + sage: G = GL(4,7) + sage: G.0 * vector([1,2,3,4]) + (3, 2, 3, 4) + sage: v = vector(GF(7), [3,2,1,-1]) + sage: g = G.1 + sage: v * g == v * g.matrix() # indirect doctest + True + """ + if not is_MatrixGroupElement(x) and x not in self.parent().base_ring(): + try: + if self_on_left: + return self.matrix() * x + else: + return x * self.matrix() + except TypeError: + return None + + cpdef _richcmp_(self, other, int op): + """ + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2) + sage: gens = [MS([1,0, 0,1]), MS([1,1, 0,1])] + sage: G = MatrixGroup(gens) + sage: g = G([1,1, 0,1]) + sage: h = G([1,1, 0,1]) + sage: g == h + True + sage: g == G.one() + False + """ + return richcmp(self.matrix(), other.matrix(), op) + + @cached_method + def matrix(self): + """ + Obtain the usual matrix (as an element of a matrix space) + associated to this matrix group element. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: m = G.gen(0).matrix(); m + [1 0] + [0 1] + sage: m.parent() + Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 3 + + sage: k = GF(7); G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]) + sage: g = G.0 + sage: g.matrix() + [1 1] + [0 1] + sage: parent(g.matrix()) + Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 + + Matrices have extra functionality that matrix group elements + do not have:: + + sage: g.matrix().charpoly('t') + t^2 + 5*t + 1 + """ + # We do a slightly specialized version of sage.libs.gap.element.GapElement.matrix() + # in order to use our current matrix space directly and avoid + # some overhead safety checks. + entries = self.gap().Flat() + MS = self.parent().matrix_space() + ring = MS.base_ring() + m = MS([x.sage(ring=ring) for x in entries]) + m.set_immutable() + return m + + def _matrix_(self, base=None): + """ + Method used by the :func:`matrix` constructor. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: G = MatrixGroup([MS([1,1,0,1])]) + sage: g = G.gen(0) + sage: M = matrix(GF(9), g); M; parent(M) + [1 1] + [0 1] + Full MatrixSpace of 2 by 2 dense matrices over Finite Field in z2 of size 3^2 + """ + return self.matrix() + + cpdef list list(self): + """ + Return list representation of this matrix. + + EXAMPLES:: + + sage: F = GF(3); MS = MatrixSpace(F,2,2) + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: G = MatrixGroup(gens) + sage: g = G.0 + sage: g + [1 0] + [0 1] + sage: g.list() + [[1, 0], [0, 1]] + """ + return [r.list() for r in self.matrix().rows()] + + @cached_method + def multiplicative_order(self): + """ + Return the order of this group element, which is the smallest + positive integer `n` such that `g^n = 1`, or + +Infinity if no such integer exists. + + EXAMPLES:: + + sage: k = GF(7) + sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G + Matrix group over Finite Field of size 7 with 2 generators ( + [1 1] [1 0] + [0 1], [0 2] + ) + sage: G.order() + 21 + sage: G.gen(0).multiplicative_order(), G.gen(1).multiplicative_order() + (7, 3) + + ``order`` is just an alias for ``multiplicative_order``:: + + sage: G.gen(0).order(), G.gen(1).order() + (7, 3) + + sage: k = QQ + sage: G = MatrixGroup([matrix(k,2,[1,1,0,1]), matrix(k,2,[1,0,0,2])]); G + Matrix group over Rational Field with 2 generators ( + [1 1] [1 0] + [0 1], [0 2] + ) + sage: G.order() + +Infinity + sage: G.gen(0).order(), G.gen(1).order() + (+Infinity, +Infinity) + + sage: gl = GL(2, ZZ); gl + General Linear Group of degree 2 over Integer Ring + sage: g = gl.gen(2); g + [1 1] + [0 1] + sage: g.order() + +Infinity + """ + order = self.gap().Order() + if order.IsInt(): + return order.sage() + else: + assert order.IsInfinity() + from sage.rings.infinity import Infinity + return Infinity + + def word_problem(self, gens=None): + r""" + Solve the word problem. + + This method writes the group element as a product of the + elements of the list ``gens``, or the standard generators of + the parent of self if ``gens`` is None. + + INPUT: + + - ``gens`` -- a list/tuple/iterable of elements (or objects + that can be converted to group elements), or ``None`` + (default). By default, the generators of the parent group + are used. + + OUTPUT: + + A factorization object that contains information about the + order of factors and the exponents. A ``ValueError`` is raised + if the group element cannot be written as a word in ``gens``. + + ALGORITHM: + + Use GAP, which has optimized algorithms for solving the word + problem (the GAP functions ``EpimorphismFromFreeGroup`` and + ``PreImagesRepresentative``). + + EXAMPLES:: + + sage: G = GL(2,5); G + General Linear Group of degree 2 over Finite Field of size 5 + sage: G.gens() + ( + [2 0] [4 1] + [0 1], [4 0] + ) + sage: G(1).word_problem([G.gen(0)]) + 1 + sage: type(_) + + + sage: g = G([0,4,1,4]) + sage: g.word_problem() + ([4 1] + [4 0])^-1 + + Next we construct a more complicated element of the group from the + generators:: + + sage: s,t = G.0, G.1 + sage: a = (s * t * s); b = a.word_problem(); b + ([2 0] + [0 1]) * + ([4 1] + [4 0]) * + ([2 0] + [0 1]) + sage: flatten(b) + [ + [2 0] [4 1] [2 0] + [0 1], 1, [4 0], 1, [0 1], 1 + ] + sage: b.prod() == a + True + + We solve the word problem using some different generators:: + + sage: s = G([2,0,0,1]); t = G([1,1,0,1]); u = G([0,-1,1,0]) + sage: a.word_problem([s,t,u]) + ([2 0] + [0 1])^-1 * + ([1 1] + [0 1])^-1 * + ([0 4] + [1 0]) * + ([2 0] + [0 1])^-1 + + We try some elements that don't actually generate the group:: + + sage: a.word_problem([t,u]) + Traceback (most recent call last): + ... + ValueError: word problem has no solution + + AUTHORS: + + - David Joyner and William Stein + - David Loeffler (2010): fixed some bugs + - Volker Braun (2013): LibGAP + """ + from sage.libs.gap.libgap import libgap + G = self.parent() + if gens: + gen = lambda i:gens[i] + H = libgap.Group([G(x).gap() for x in gens]) + else: + gen = G.gen + H = G.gap() + hom = H.EpimorphismFromFreeGroup() + preimg = hom.PreImagesRepresentative(self.gap()) + + if preimg.is_bool(): + assert preimg == libgap.eval('fail') + raise ValueError('word problem has no solution') + + result = [] + n = preimg.NumberSyllables().sage() + exponent_syllable = libgap.eval('ExponentSyllable') + generator_syllable = libgap.eval('GeneratorSyllable') + for i in range(n): + exponent = exponent_syllable(preimg, i+1).sage() + generator = gen(generator_syllable(preimg, i+1).sage() - 1) + result.append( (generator, exponent) ) + result = Factorization(result) + result._set_cr(True) + return result diff --git a/src/sage/groups/matrix_gps/pickling_overrides.py b/src/sage/groups/matrix_gps/pickling_overrides.py index 2c4176f5982..9a62d03e6c4 100644 --- a/src/sage/groups/matrix_gps/pickling_overrides.py +++ b/src/sage/groups/matrix_gps/pickling_overrides.py @@ -5,11 +5,10 @@ from sage.structure.sage_object import register_unpickle_override from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap -from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap +from sage.groups.matrix_gps.group_element_gap import MatrixGroupElement_gap from sage.groups.matrix_gps.linear import GL, LinearMatrixGroup_generic - class LegacyMatrixGroup(FinitelyGeneratedMatrixGroup_gap): def __setstate__(self, state): From b17ab882bee69fbaf4e48b2789545237ce507819 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 17:30:46 -0700 Subject: [PATCH 04/18] sage.groups.matrix_gps: Make a namespace package, replace imports from .all --- src/sage/groups/matrix_gps/__init__.py | 0 src/sage/modular/arithgroup/congroup_generic.py | 7 ++++++- src/sage/modular/local_comp/type_space.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) delete mode 100644 src/sage/groups/matrix_gps/__init__.py diff --git a/src/sage/groups/matrix_gps/__init__.py b/src/sage/groups/matrix_gps/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index 99dbc5036fb..e71426f9922 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -22,7 +22,6 @@ ################################################################################ from sage.arith.misc import gcd -from sage.groups.matrix_gps.all import MatrixGroup from sage.matrix.matrix_space import MatrixSpace from sage.misc.misc_c import prod from sage.rings.finite_rings.integer_mod_ring import Zmod @@ -88,7 +87,9 @@ def CongruenceSubgroup_constructor(*args): ... TypeError: Ring of definition must be Z / NZ for some N """ + from sage.groups.matrix_gps.finitely_generated import MatrixGroup from sage.groups.matrix_gps.matrix_group import is_MatrixGroup + if is_MatrixGroup(args[0]): G = args[0] @@ -377,6 +378,8 @@ def to_even_subgroup(self): if self.is_even(): return self else: + from sage.groups.matrix_gps.finitely_generated import MatrixGroup + G = self.image_mod_n() H = MatrixGroup([ g.matrix() for g in G.gens()] + [G.matrix_space()(-1)]) return CongruenceSubgroup_constructor(H) @@ -590,7 +593,9 @@ def _minimize_level(G): sage: sage.modular.arithgroup.congroup_generic._minimize_level(G) 3 """ + from sage.groups.matrix_gps.finitely_generated import MatrixGroup from .congroup_gamma import Gamma_constructor as Gamma + Glist = list(G) N = G.base_ring().characteristic() i = Gamma(N).index() diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 2549e5519b0..3b57a2652ae 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -497,7 +497,7 @@ def _rho_unramified(self, g): True """ f = self.prime() ** self.u() - from sage.groups.matrix_gps.all import SL + from sage.groups.matrix_gps.linear import SL G = SL(2, Zmod(f)) gg = G(g) s = G([1,1,0,1]) From a074b13b81abb40c119bdd9ffaf1372c020f49a8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 17:45:51 -0700 Subject: [PATCH 05/18] sage.groups.matrix_gps: Fix up imports --- .../groups/matrix_gps/finitely_generated.py | 23 +++++++------------ .../matrix_gps/finitely_generated_gap.py | 12 ++++++++++ .../groups/matrix_gps/matrix_group_gap.py | 3 +++ src/sage/groups/matrix_gps/named_group.py | 2 +- src/sage/groups/matrix_gps/orthogonal_gap.py | 1 + src/sage/groups/matrix_gps/symplectic_gap.py | 1 + src/sage/groups/matrix_gps/unitary.py | 2 +- src/sage/groups/matrix_gps/unitary_gap.py | 1 + 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index a7749ad88e6..e6770f9da4d 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -62,24 +62,15 @@ # https://www.gnu.org/licenses/ ############################################################################## +from sage.groups.matrix_gps.group_element import is_MatrixGroupElement +from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic +from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import is_MatrixSpace +from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ -from sage.rings.qqbar import QQbar from sage.structure.element import is_Matrix -from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace -from sage.matrix.constructor import matrix from sage.structure.sequence import Sequence -from sage.misc.cachefunc import cached_method -from sage.modules.free_module_element import vector -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.power_series_ring import PowerSeriesRing -from sage.rings.fraction_field import FractionField -from sage.misc.functional import cyclotomic_polynomial -from sage.rings.number_field.number_field import CyclotomicField -from sage.combinat.integer_vector import IntegerVectors - -from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic -from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap -from sage.groups.matrix_gps.group_element import is_MatrixGroupElement def normalize_square_matrices(matrices): @@ -296,6 +287,8 @@ def MatrixGroup(*gens, **kwds): from sage.libs.gap.libgap import libgap category = kwds.get('category', None) try: + from .finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + gap_gens = [libgap(matrix_gen) for matrix_gen in gens] gap_group = libgap.Group(gap_gens) return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group, diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py index e76dbb770d4..5f570967f85 100644 --- a/src/sage/groups/matrix_gps/finitely_generated_gap.py +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -2,7 +2,19 @@ Finitely Generated Matrix Groups with GAP """ +from sage.combinat.integer_vector import IntegerVectors +from sage.groups.matrix_gps.finitely_generated import MatrixGroup from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.cachefunc import cached_method +from sage.misc.functional import cyclotomic_polynomial +from sage.modules.free_module_element import vector +from sage.rings.fraction_field import FractionField +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import CyclotomicField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.qqbar import QQbar class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap): diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py index a78bf73e629..9b327ff9250 100644 --- a/src/sage/groups/matrix_gps/matrix_group_gap.py +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -2,7 +2,10 @@ Matrix group over a ring that GAP understands """ +from sage.categories.groups import Groups +from sage.groups.group import Group from sage.groups.libgap_mixin import GroupMixinLibGAP +from sage.groups.libgap_wrapper import ParentLibGAP from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index f2770a3ec9f..ef3e7f4bf3b 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -41,7 +41,7 @@ ############################################################################## from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic -form sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap +from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap from sage.structure.unique_representation import CachedRepresentation diff --git a/src/sage/groups/matrix_gps/orthogonal_gap.py b/src/sage/groups/matrix_gps/orthogonal_gap.py index 182e4609925..f75958276ce 100644 --- a/src/sage/groups/matrix_gps/orthogonal_gap.py +++ b/src/sage/groups/matrix_gps/orthogonal_gap.py @@ -5,6 +5,7 @@ from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap from sage.groups.matrix_gps.orthogonal import OrthogonalMatrixGroup_generic +from sage.misc.cachefunc import cached_method class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): diff --git a/src/sage/groups/matrix_gps/symplectic_gap.py b/src/sage/groups/matrix_gps/symplectic_gap.py index 2e6e48f41d8..891c5bac832 100644 --- a/src/sage/groups/matrix_gps/symplectic_gap.py +++ b/src/sage/groups/matrix_gps/symplectic_gap.py @@ -5,6 +5,7 @@ from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap from sage.groups.matrix_gps.symplectic import SymplecticMatrixGroup_generic +from sage.misc.cachefunc import cached_method class SymplecticMatrixGroup_gap(SymplecticMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index d78f63ab33b..43c766bb7e0 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -134,7 +134,7 @@ def _UG(n, R, special, var='a', invariant_form=None): ltx = r'\text{{{0}U}}_{{{1}}}({2})'.format(latex_prefix, degree, latex(ring)) if is_FiniteField(ring): - from .unitary import UnitaryMatrixGroup_gap + from .unitary_gap import UnitaryMatrixGroup_gap cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q) return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd) diff --git a/src/sage/groups/matrix_gps/unitary_gap.py b/src/sage/groups/matrix_gps/unitary_gap.py index 28dc94b8b48..f760e880d40 100644 --- a/src/sage/groups/matrix_gps/unitary_gap.py +++ b/src/sage/groups/matrix_gps/unitary_gap.py @@ -5,6 +5,7 @@ from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap from sage.groups.matrix_gps.unitary import UnitaryMatrixGroup_generic +from sage.misc.cachefunc import cached_method class UnitaryMatrixGroup_gap(UnitaryMatrixGroup_generic, NamedMatrixGroup_gap, FinitelyGeneratedMatrixGroup_gap): From 3f1d6506b5d7ad5d95324664202c96e49cbef9d2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 17:53:17 -0700 Subject: [PATCH 06/18] src/doc/en/reference/groups/index.rst: Add the ..._gap modules --- src/doc/en/reference/groups/index.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index e3df953c29a..8f214fb0ae2 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -72,17 +72,23 @@ Matrix and Affine Groups sage/groups/matrix_gps/catalog sage/groups/matrix_gps/matrix_group + sage/groups/matrix_gps/matrix_group_gap sage/groups/matrix_gps/group_element + sage/groups/matrix_gps/group_element_gap sage/groups/matrix_gps/finitely_generated + sage/groups/matrix_gps/finitely_generated_gap sage/groups/matrix_gps/morphism sage/groups/matrix_gps/homset sage/groups/matrix_gps/binary_dihedral sage/groups/matrix_gps/coxeter_group sage/groups/matrix_gps/linear + sage/groups/matrix_gps/linear_gap sage/groups/matrix_gps/orthogonal + sage/groups/matrix_gps/orthogonal_gap sage/groups/matrix_gps/isometries - sage/groups/matrix_gps/symplectic + sage/groups/matrix_gps/symplectic_gap sage/groups/matrix_gps/unitary + sage/groups/matrix_gps/unitary_gap sage/groups/matrix_gps/heisenberg sage/groups/affine_gps/affine_group sage/groups/affine_gps/euclidean_group @@ -115,5 +121,6 @@ Internals :maxdepth: 1 sage/groups/matrix_gps/named_group + sage/groups/matrix_gps/named_group_gap .. include:: ../footer.txt From 009fb6c788fba236eda08cb873ec9a9ae7b756d4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 19:19:01 -0700 Subject: [PATCH 07/18] sage.groups.matrix_gps: Mark doctests # optional --- .../matrix_gps/all__sagemath_polyhedra.py | 13 +++ src/sage/groups/matrix_gps/orthogonal.py | 105 +++++++++--------- src/sage/groups/matrix_gps/symplectic.py | 16 +-- 3 files changed, 74 insertions(+), 60 deletions(-) create mode 100644 src/sage/groups/matrix_gps/all__sagemath_polyhedra.py diff --git a/src/sage/groups/matrix_gps/all__sagemath_polyhedra.py b/src/sage/groups/matrix_gps/all__sagemath_polyhedra.py new file mode 100644 index 00000000000..c6360cd6a03 --- /dev/null +++ b/src/sage/groups/matrix_gps/all__sagemath_polyhedra.py @@ -0,0 +1,13 @@ +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.groups.matrix_gps.linear', 'GL') +lazy_import('sage.groups.matrix_gps.linear', 'SL') +lazy_import('sage.groups.matrix_gps.symplectic', 'Sp') +lazy_import('sage.groups.matrix_gps.unitary', 'SU') +lazy_import('sage.groups.matrix_gps.unitary', 'GU') +lazy_import('sage.groups.matrix_gps.orthogonal', 'GO') +lazy_import('sage.groups.matrix_gps.orthogonal', 'SO') +lazy_import('sage.groups.matrix_gps.finitely_generated', 'MatrixGroup') +lazy_import('sage.groups.matrix_gps.finitely_generated', 'QuaternionMatrixGroupGF3') + +import sage.groups.matrix_gps.pickling_overrides diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 5dd76b2f9f9..209ab7f952f 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -36,9 +36,9 @@ sage: GO(3,7) General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: G = SO( 4, GF(7), 1); G + sage: G = SO(4, GF(7), 1); G # optional - sage.libs.pari Special Orthogonal Group of degree 4 and form parameter 1 over Finite Field of size 7 - sage: G.random_element() # random + sage: G.random_element() # random # optional - sage.libs.pari [4 3 5 2] [6 6 4 0] [0 4 6 0] @@ -46,14 +46,14 @@ TESTS:: - sage: G = GO(3, GF(5)) - sage: latex(G) + sage: G = GO(3, GF(5)) # optional - sage.libs.pari + sage: latex(G) # optional - sage.libs.pari \text{GO}_{3}(\Bold{F}_{5}) - sage: G = SO(3, GF(5)) - sage: latex(G) + sage: G = SO(3, GF(5)) # optional - sage.libs.pari + sage: latex(G) # optional - sage.libs.pari \text{SO}_{3}(\Bold{F}_{5}) - sage: G = SO(4, GF(5), 1) - sage: latex(G) + sage: G = SO(4, GF(5), 1) # optional - sage.libs.pari + sage: latex(G) # optional - sage.libs.pari \text{SO}_{4}(\Bold{F}_{5}, +) AUTHORS: @@ -116,13 +116,13 @@ def normalize_args_e(degree, ring, e): TESTS:: sage: from sage.groups.matrix_gps.orthogonal import normalize_args_e - sage: normalize_args_e(2, GF(3), +1) + sage: normalize_args_e(2, GF(3), +1) # optional - sage.libs.pari 1 - sage: normalize_args_e(3, GF(3), 0) + sage: normalize_args_e(3, GF(3), 0) # optional - sage.libs.pari 0 - sage: normalize_args_e(3, GF(3), +1) + sage: normalize_args_e(3, GF(3), +1) # optional - sage.libs.pari 0 - sage: normalize_args_e(2, GF(3), 0) + sage: normalize_args_e(2, GF(3), 0) # optional - sage.libs.pari Traceback (most recent call last): ... ValueError: must have e=-1 or e=1 for even degree @@ -149,14 +149,14 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): Check that :trac:`26028` is fixed:: - sage: GO(3,25).order() # indirect doctest + sage: GO(3,25).order() # indirect doctest # optional - sage.libs.pari 31200 Check that :trac:`28054` is fixed:: - sage: G = SO(2, GF(3), -1) - sage: m = G.invariant_form() - sage: G2 = SO(2, GF(3), 1, invariant_form=m) + sage: G = SO(2, GF(3), -1) # optional - sage.libs.pari + sage: m = G.invariant_form() # optional - sage.libs.pari + sage: G2 = SO(2, GF(3), 1, invariant_form=m) # optional - sage.libs.pari Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -261,11 +261,11 @@ def GO(n, R, e=0, var='a', invariant_form=None): EXAMPLES:: - sage: GO( 3, GF(7)) + sage: GO( 3, GF(7)) # optional - sage.libs.pari General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: GO( 3, GF(7)).order() + sage: GO( 3, GF(7)).order() # optional - sage.libs.pari 672 - sage: GO( 3, GF(7)).gens() + sage: GO( 3, GF(7)).gens() # optional - sage.libs.pari ( [3 0 0] [0 1 0] [0 5 0] [1 6 6] @@ -287,13 +287,13 @@ def GO(n, R, e=0, var='a', invariant_form=None): [0 1 0] [1 0 0] [0 0 3] - sage: pm = Permutation([2,3,1]).to_matrix() - sage: g = GO3(pm); g in GO3; g + sage: pm = Permutation([2,3,1]).to_matrix() # optional - sage.combinat + sage: g = GO3(pm); g in GO3; g # optional - sage.combinat True [0 0 1] [1 0 0] [0 1 0] - sage: GO3m(pm) + sage: GO3m(pm) # optional - sage.combinat Traceback (most recent call last): ... TypeError: matrix must be orthogonal with respect to the symmetric form @@ -309,7 +309,8 @@ def GO(n, R, e=0, var='a', invariant_form=None): 10 sage: R. = ZZ[] sage: GO(2, R, invariant_form=[[x,0],[0,1]]) - General Orthogonal Group of degree 2 over Univariate Polynomial Ring in x over Integer Ring with respect to symmetric form + General Orthogonal Group of degree 2 over + Univariate Polynomial Ring in x over Integer Ring with respect to symmetric form [x 0] [0 1] @@ -368,19 +369,19 @@ def SO(n, R, e=None, var='a', invariant_form=None): EXAMPLES:: - sage: G = SO(3,GF(5)) - sage: G + sage: G = SO(3,GF(5)) # optional - sage.libs.pari + sage: G # optional - sage.libs.pari Special Orthogonal Group of degree 3 over Finite Field of size 5 - sage: G = SO(3,GF(5)) - sage: G.gens() + sage: G = SO(3,GF(5)) # optional - sage.libs.pari + sage: G.gens() # optional - sage.libs.pari ( [2 0 0] [3 2 3] [1 4 4] [0 3 0] [0 2 0] [4 0 0] [0 0 1], [0 3 1], [2 0 4] ) - sage: G = SO(3,GF(5)) - sage: G.as_matrix_group() + sage: G = SO(3,GF(5)) # optional - sage.libs.pari + sage: G.as_matrix_group() # optional - sage.libs.pari Matrix group over Finite Field of size 5 with 3 generators ( [2 0 0] [3 2 3] [1 4 4] [0 3 0] [0 2 0] [4 0 0] @@ -389,27 +390,27 @@ def SO(n, R, e=None, var='a', invariant_form=None): Using the ``invariant_form`` option:: - sage: CF3 = CyclotomicField(3); e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) - sage: SO3 = SO(3, CF3) - sage: SO3m = SO(3, CF3, invariant_form=m) - sage: SO3 == SO3m + sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: SO3 = SO(3, CF3) # optional - sage.rings.number_field + sage: SO3m = SO(3, CF3, invariant_form=m) # optional - sage.rings.number_field + sage: SO3 == SO3m # optional - sage.rings.number_field False - sage: SO3.invariant_form() + sage: SO3.invariant_form() # optional - sage.rings.number_field [1 0 0] [0 1 0] [0 0 1] - sage: SO3m.invariant_form() + sage: SO3m.invariant_form() # optional - sage.rings.number_field [ 1 zeta3 0] [zeta3 2 0] [ 0 0 1] - sage: pm = Permutation([2,3,1]).to_matrix() - sage: g = SO3(pm); g in SO3; g + sage: pm = Permutation([2,3,1]).to_matrix() # optional - sage.combinat + sage: g = SO3(pm); g in SO3; g # optional - sage.combinat sage.rings.number_field True [0 0 1] [1 0 0] [0 1 0] - sage: SO3m(pm) + sage: SO3m(pm) # optional - sage.combinat sage.rings.number_field Traceback (most recent call last): ... TypeError: matrix must be orthogonal with respect to the symmetric form @@ -417,7 +418,7 @@ def SO(n, R, e=None, var='a', invariant_form=None): [zeta3 2 0] [ 0 0 1] - sage: SO(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) + sage: SO(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) # optional - sage.combinat sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -426,8 +427,8 @@ def SO(n, R, e=None, var='a', invariant_form=None): TESTS:: - sage: TestSuite(SO3m).run() - sage: groups.matrix.SO(2, 3, e=1) + sage: TestSuite(SO3m).run() # optional - sage.rings.number_field + sage: groups.matrix.SO(2, 3, e=1) # optional - sage.rings.number_field Special Orthogonal Group of degree 2 and form parameter 1 over Finite Field of size 3 """ return _OG(n, R, True, e=e, var=var, invariant_form=invariant_form) @@ -444,20 +445,20 @@ class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic): EXAMPLES:: - sage: G = GO(3, GF(7)); G + sage: G = GO(3, GF(7)); G # optional - sage.libs.pari General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: latex(G) + sage: latex(G) # optional - sage.libs.pari \text{GO}_{3}(\Bold{F}_{7}) - sage: G = SO(3, GF(5)); G + sage: G = SO(3, GF(5)); G # optional - sage.libs.pari Special Orthogonal Group of degree 3 over Finite Field of size 5 - sage: latex(G) + sage: latex(G) # optional - sage.libs.pari \text{SO}_{3}(\Bold{F}_{5}) - sage: CF3 = CyclotomicField(3); e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) - sage: G = SO(3, CF3, invariant_form=m) - sage: latex(G) + sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: G = SO(3, CF3, invariant_form=m) # optional - sage.rings.number_field + sage: latex(G) # optional - sage.rings.number_field \text{SO}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to non positive definite symmetric form }\left(\begin{array}{rrr} 1 & \zeta_{3} & 0 \\ \zeta_{3} & 2 & 0 \\ @@ -521,8 +522,8 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = GO(4, GF(5), +1) - sage: G._check_matrix(G.an_element().matrix()) + sage: G = GO(4, GF(5), +1) # optional - sage.libs.pari + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari """ if self._special and x.determinant() != 1: raise TypeError('matrix must have determinant one') diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index 3e5b0f194ae..e6c5a233057 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -80,13 +80,13 @@ def Sp(n, R, var='a', invariant_form=None): EXAMPLES:: - sage: Sp(4, 5) + sage: Sp(4, 5) # optional - sage.libs.pari Symplectic Group of degree 4 over Finite Field of size 5 sage: Sp(4, IntegerModRing(15)) Symplectic Group of degree 4 over Ring of integers modulo 15 - sage: Sp(3, GF(7)) + sage: Sp(3, GF(7)) # optional - sage.libs.pari Traceback (most recent call last): ... ValueError: the degree must be even @@ -133,10 +133,10 @@ def Sp(n, R, var='a', invariant_form=None): sage: TestSuite(Sp4).run() sage: TestSuite(Sp4m).run() - sage: groups.matrix.Sp(2, 3) + sage: groups.matrix.Sp(2, 3) # optional - sage.libs.pari Symplectic Group of degree 2 over Finite Field of size 3 - sage: G = Sp(4,5) + sage: G = Sp(4,5) # optional - sage.libs.pari sage: TestSuite(G).run() """ degree, ring = normalize_args_vectorspace(n, R, var=var) @@ -175,9 +175,9 @@ class SymplecticMatrixGroup_generic(NamedMatrixGroup_generic): EXAMPLES:: - sage: Sp43 = Sp(4,3); Sp43 + sage: Sp43 = Sp(4,3); Sp43 # optional - sage.libs.pari Symplectic Group of degree 4 over Finite Field of size 3 - sage: latex(Sp43) + sage: latex(Sp43) # optional - sage.libs.pari \text{Sp}_{4}(\Bold{F}_{3}) sage: Sp4m = Sp(4,QQ, invariant_form=(0, 0, 1, 0, 0, 0, 0, 2, -1, 0, 0, 0, 0, -2, 0, 0)); Sp4m @@ -233,8 +233,8 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = Sp(4,GF(5)) - sage: G._check_matrix(G.an_element().matrix()) + sage: G = Sp(4,GF(5)) # optional - sage.libs.pari + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari """ F = self.invariant_form() if x * F * x.transpose() != F: From 7f412894507309352a19d9578b7fa048357ee7d0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 21:08:00 -0700 Subject: [PATCH 08/18] sage.groups.{affine_gps,matrix_gps}: Mark doctests # optional --- src/sage/groups/affine_gps/affine_group.py | 76 ++++----- src/sage/groups/affine_gps/euclidean_group.py | 24 +-- src/sage/groups/affine_gps/group_element.py | 68 ++++---- src/sage/groups/group.pyx | 6 +- .../groups/matrix_gps/finitely_generated.py | 100 +++++------ src/sage/groups/matrix_gps/group_element.pyx | 156 +++++++++--------- src/sage/groups/matrix_gps/linear.py | 62 +++---- src/sage/groups/matrix_gps/matrix_group.py | 120 +++++++------- src/sage/groups/matrix_gps/named_group.py | 35 ++-- src/sage/groups/matrix_gps/orthogonal.py | 6 +- src/sage/groups/matrix_gps/symplectic.py | 20 +-- src/sage/groups/matrix_gps/unitary.py | 104 ++++++------ 12 files changed, 388 insertions(+), 389 deletions(-) diff --git a/src/sage/groups/affine_gps/affine_group.py b/src/sage/groups/affine_gps/affine_group.py index 44d6bf94900..7b0576e8649 100644 --- a/src/sage/groups/affine_gps/affine_group.py +++ b/src/sage/groups/affine_gps/affine_group.py @@ -129,11 +129,11 @@ class AffineGroup(UniqueRepresentation, Group): Some additional ways to create affine groups:: - sage: A = AffineSpace(2, GF(4,'a')); A + sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.libs.pari Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: G = AffineGroup(A); G + sage: G = AffineGroup(A); G # optional - sage.libs.pari Affine Group of degree 2 over Finite Field in a of size 2^2 - sage: G is AffineGroup(2,4) # shorthand + sage: G is AffineGroup(2,4) # shorthand # optional - sage.libs.pari True sage: V = ZZ^3; V @@ -152,10 +152,10 @@ def __classcall__(cls, *args, **kwds): EXAMPLES:: - sage: A = AffineSpace(2, GF(4,'a')) - sage: AffineGroup(A) is AffineGroup(2,4) + sage: A = AffineSpace(2, GF(4,'a')) # optional - sage.libs.pari + sage: AffineGroup(A) is AffineGroup(2,4) # optional - sage.libs.pari True - sage: AffineGroup(A) is AffineGroup(2, GF(4,'a')) + sage: AffineGroup(A) is AffineGroup(2, GF(4,'a')) # optional - sage.libs.pari True sage: A = AffineGroup(2, QQ) sage: V = QQ^2 @@ -202,10 +202,10 @@ def __init__(self, degree, ring): TESTS:: - sage: G = AffineGroup(2, GF(5)); G + sage: G = AffineGroup(2, GF(5)); G # optional - sage.libs.pari Affine Group of degree 2 over Finite Field of size 5 - sage: TestSuite(G).run() - sage: G.category() + sage: TestSuite(G).run() # optional - sage.libs.pari + sage: G.category() # optional - sage.libs.pari Category of finite groups sage: Aff6 = AffineGroup(6, QQ) @@ -264,8 +264,8 @@ def _latex_(self): EXAMPLES:: - sage: G = AffineGroup(6, GF(5)) - sage: latex(G) + sage: G = AffineGroup(6, GF(5)) # optional - sage.libs.pari + sage: latex(G) # optional - sage.libs.pari \mathrm{Aff}_{6}(\Bold{F}_{5}) """ return "\\mathrm{Aff}_{%s}(%s)" % (self.degree(), @@ -277,7 +277,7 @@ def _repr_(self): EXAMPLES:: - sage: AffineGroup(6, GF(5)) + sage: AffineGroup(6, GF(5)) # optional - sage.libs.pari Affine Group of degree 6 over Finite Field of size 5 """ return "Affine Group of degree %s over %s" % (self.degree(), @@ -289,7 +289,7 @@ def cardinality(self): EXAMPLES:: - sage: AffineGroup(6, GF(5)).cardinality() + sage: AffineGroup(6, GF(5)).cardinality() # optional - sage.libs.pari 172882428468750000000000000000 sage: AffineGroup(6, ZZ).cardinality() +Infinity @@ -307,11 +307,11 @@ def degree(self): EXAMPLES:: - sage: G = AffineGroup(6, GF(5)) - sage: g = G.an_element() - sage: G.degree() + sage: G = AffineGroup(6, GF(5)) # optional - sage.libs.pari + sage: g = G.an_element() # optional - sage.libs.pari + sage: G.degree() # optional - sage.libs.pari 6 - sage: G.degree() == g.A().nrows() == g.A().ncols() == g.b().degree() + sage: G.degree() == g.A().nrows() == g.A().ncols() == g.b().degree() # optional - sage.libs.pari True """ return self._degree @@ -329,8 +329,8 @@ def matrix_space(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) - sage: G.matrix_space() + sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari + sage: G.matrix_space() # optional - sage.libs.pari Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 5 """ d = self.degree() @@ -343,8 +343,8 @@ def vector_space(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) - sage: G.vector_space() + sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari + sage: G.vector_space() # optional - sage.libs.pari Vector space of dimension 3 over Finite Field of size 5 """ return FreeModule(self.base_ring(), self.degree()) @@ -373,8 +373,8 @@ def linear_space(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) - sage: G.linear_space() + sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari + sage: G.linear_space() # optional - sage.libs.pari Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 5 """ dp = self.degree() + 1 @@ -394,8 +394,8 @@ def linear(self, A): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) - sage: G.linear([1,2,3,4,5,6,7,8,0]) + sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari + sage: G.linear([1,2,3,4,5,6,7,8,0]) # optional - sage.libs.pari [1 2 3] [0] x |-> [4 0 1] x + [0] [2 3 0] [0] @@ -417,8 +417,8 @@ def translation(self, b): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) - sage: G.translation([1,4,8]) + sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari + sage: G.translation([1,4,8]) # optional - sage.libs.pari [1 0 0] [1] x |-> [0 1 0] x + [4] [0 0 1] [3] @@ -446,12 +446,12 @@ def reflection(self, v): EXAMPLES:: - sage: G = AffineGroup(3, QQ) - sage: G.reflection([1,0,0]) + sage: G = AffineGroup(3, QQ) # optional - sage.libs.pari + sage: G.reflection([1,0,0]) # optional - sage.libs.pari [-1 0 0] [0] x |-> [ 0 1 0] x + [0] [ 0 0 1] [0] - sage: G.reflection([3,4,-5]) + sage: G.reflection([3,4,-5]) # optional - sage.libs.pari [ 16/25 -12/25 3/5] [0] x |-> [-12/25 9/25 4/5] x + [0] [ 3/5 4/5 0] [0] @@ -470,13 +470,13 @@ def random_element(self): EXAMPLES:: - sage: G = AffineGroup(4, GF(3)) - sage: G.random_element() # random + sage: G = AffineGroup(4, GF(3)) # optional - sage.libs.pari + sage: G.random_element() # random # optional - sage.libs.pari [2 0 1 2] [1] [2 1 1 2] [2] x |-> [1 0 2 2] x + [2] [1 1 1 1] [2] - sage: G.random_element() in G + sage: G.random_element() in G # optional - sage.libs.pari True """ A = self._GL.random_element() @@ -490,8 +490,8 @@ def _an_element_(self): TESTS:: - sage: G = AffineGroup(4,5) - sage: G.an_element() in G + sage: G = AffineGroup(4,5) # optional - sage.libs.pari + sage: G.an_element() in G # optional - sage.libs.pari True """ A = self._GL.an_element() @@ -504,8 +504,8 @@ def some_elements(self): EXAMPLES:: - sage: G = AffineGroup(4,5) - sage: G.some_elements() + sage: G = AffineGroup(4,5) # optional - sage.libs.pari + sage: G.some_elements() # optional - sage.libs.pari [ [2 0 0 0] [1] [0 1 0 0] [0] x |-> [0 0 1 0] x + [0] @@ -518,7 +518,7 @@ def some_elements(self): [0 1 0 0] [...] x |-> [0 0 1 0] x + [...] [0 0 0 1] [...]] - sage: all(v.parent() is G for v in G.some_elements()) + sage: all(v.parent() is G for v in G.some_elements()) # optional - sage.libs.pari True sage: G = AffineGroup(2,QQ) diff --git a/src/sage/groups/affine_gps/euclidean_group.py b/src/sage/groups/affine_gps/euclidean_group.py index 969dbfe1f81..3278d10a1cb 100644 --- a/src/sage/groups/affine_gps/euclidean_group.py +++ b/src/sage/groups/affine_gps/euclidean_group.py @@ -121,11 +121,11 @@ class EuclideanGroup(AffineGroup): Some additional ways to create Euclidean groups:: - sage: A = AffineSpace(2, GF(4,'a')); A + sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.libs.pari Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: G = EuclideanGroup(A); G + sage: G = EuclideanGroup(A); G # optional - sage.libs.pari Euclidean Group of degree 2 over Finite Field in a of size 2^2 - sage: G is EuclideanGroup(2,4) # shorthand + sage: G is EuclideanGroup(2,4) # shorthand # optional - sage.libs.pari True sage: V = ZZ^3; V @@ -144,9 +144,9 @@ class EuclideanGroup(AffineGroup): sage: V = QQ^6 sage: E6 is EuclideanGroup(V) True - sage: G = EuclideanGroup(2, GF(5)); G + sage: G = EuclideanGroup(2, GF(5)); G # optional - sage.libs.pari Euclidean Group of degree 2 over Finite Field of size 5 - sage: TestSuite(G).run() + sage: TestSuite(G).run() # optional - sage.libs.pari REFERENCES: @@ -195,8 +195,8 @@ def _latex_(self): r""" EXAMPLES:: - sage: G = EuclideanGroup(6, GF(5)) - sage: latex(G) + sage: G = EuclideanGroup(6, GF(5)) # optional - sage.libs.pari + sage: latex(G) # optional - sage.libs.pari \mathrm{E}_{6}(\Bold{F}_{5}) """ return "\\mathrm{E}_{%s}(%s)"%(self.degree(), self.base_ring()._latex_()) @@ -207,7 +207,7 @@ def _repr_(self): EXAMPLES:: - sage: EuclideanGroup(6, GF(5)) + sage: EuclideanGroup(6, GF(5)) # optional - sage.libs.pari Euclidean Group of degree 6 over Finite Field of size 5 """ return "Euclidean Group of degree %s over %s"%(self.degree(), self.base_ring()) @@ -218,18 +218,18 @@ def random_element(self): EXAMPLES:: - sage: G = EuclideanGroup(4, GF(3)) - sage: G.random_element() # random + sage: G = EuclideanGroup(4, GF(3)) # optional - sage.libs.pari + sage: G.random_element() # random # optional - sage.libs.pari [2 1 2 1] [1] [1 2 2 1] [0] x |-> [2 2 2 2] x + [1] [1 1 2 2] [2] - sage: G.random_element() in G + sage: G.random_element() in G # optional - sage.libs.pari True TESTS:: - sage: G.random_element().A().is_unitary() + sage: G.random_element().A().is_unitary() # optional - sage.libs.pari True """ while True: diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index 127c1d33cb5..a04fee79262 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -80,13 +80,13 @@ class AffineGroupElement(MultiplicativeGroupElement): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) - sage: g = G.random_element() - sage: type(g) + sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari + sage: g = G.random_element() # optional - sage.libs.pari + sage: type(g) # optional - sage.libs.pari - sage: G(g.matrix()) == g + sage: G(g.matrix()) == g # optional - sage.libs.pari True - sage: G(2) + sage: G(2) # optional - sage.libs.pari [2 0] [0] x |-> [0 2] x + [0] @@ -110,9 +110,9 @@ def __init__(self, parent, A, b=0, convert=True, check=True): TESTS:: - sage: G = AffineGroup(4, GF(5)) - sage: g = G.random_element() - sage: TestSuite(g).run() + sage: G = AffineGroup(4, GF(5)) # optional - sage.libs.pari + sage: g = G.random_element() # optional - sage.libs.pari + sage: TestSuite(g).run() # optional - sage.libs.pari """ try: A = A.matrix() @@ -187,29 +187,29 @@ def matrix(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(7)) - sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) - sage: g + sage: G = AffineGroup(3, GF(7)) # optional - sage.libs.pari + sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) # optional - sage.libs.pari + sage: g # optional - sage.libs.pari [1 2 3] [3] x |-> [4 5 6] x + [4] [0 1 0] [5] - sage: g.matrix() + sage: g.matrix() # optional - sage.libs.pari [1 2 3|3] [4 5 6|4] [0 1 0|5] [-----+-] [0 0 0|1] - sage: parent(g.matrix()) + sage: parent(g.matrix()) # optional - sage.libs.pari Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 7 - sage: g.matrix() == matrix(g) + sage: g.matrix() == matrix(g) # optional - sage.libs.pari True Composition of affine group elements equals multiplication of the matrices:: - sage: g1 = G.random_element() - sage: g2 = G.random_element() - sage: g1.matrix() * g2.matrix() == (g1*g2).matrix() + sage: g1 = G.random_element() # optional - sage.libs.pari + sage: g2 = G.random_element() # optional - sage.libs.pari + sage: g1.matrix() * g2.matrix() == (g1*g2).matrix() # optional - sage.libs.pari True """ A = self._A @@ -338,13 +338,13 @@ def _mul_(self, other): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) - sage: g = G([1,1, 0,1], [0,1]) - sage: h = G([1,1, 0,1], [1,2]) - sage: g*h + sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari + sage: g = G([1,1, 0,1], [0,1]) # optional - sage.libs.pari + sage: h = G([1,1, 0,1], [1,2]) # optional - sage.libs.pari + sage: g*h # optional - sage.libs.pari [1 2] [0] x |-> [0 1] x + [0] - sage: g.matrix() * h.matrix() == (g*h).matrix() + sage: g.matrix() * h.matrix() == (g*h).matrix() # optional - sage.libs.pari True """ parent = self.parent() @@ -440,16 +440,16 @@ def _act_on_(self, x, self_on_left): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) - sage: g = G([1,2,3,4], [5,6]) - sage: g + sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari + sage: g = G([1,2,3,4], [5,6]) # optional - sage.libs.pari + sage: g # optional - sage.libs.pari [1 2] [2] x |-> [0 1] x + [0] - sage: v = vector(GF(3), [1,-1]); v + sage: v = vector(GF(3), [1,-1]); v # optional - sage.libs.pari (1, 2) - sage: g*v + sage: g*v # optional - sage.libs.pari (1, 2) - sage: g*v == g.A() * v + g.b() + sage: g*v == g.A() * v + g.b() # optional - sage.libs.pari True """ if self_on_left: @@ -465,18 +465,18 @@ def __invert__(self): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) - sage: g = G([1,2,3,4], [5,6]) - sage: g + sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari + sage: g = G([1,2,3,4], [5,6]) # optional - sage.libs.pari + sage: g # optional - sage.libs.pari [1 2] [2] x |-> [0 1] x + [0] - sage: ~g + sage: ~g # optional - sage.libs.pari [1 1] [1] x |-> [0 1] x + [0] - sage: g * g.inverse() # indirect doctest + sage: g * g.inverse() # indirect doctest # optional - sage.libs.pari [1 0] [0] x |-> [0 1] x + [0] - sage: g * g.inverse() == g.inverse() * g == G(1) + sage: g * g.inverse() == g.inverse() * g == G(1) # optional - sage.libs.pari True """ parent = self.parent() diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index b829bbf68bf..e31b39a88be 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -143,7 +143,7 @@ cdef class Group(Parent): EXAMPLES:: - sage: SL(2, 7).is_commutative() + sage: SL(2, 7).is_commutative() # optional - sage.libs.pari False """ return self.is_abelian() @@ -215,8 +215,8 @@ cdef class Group(Parent): EXAMPLES:: - sage: G = AbelianGroup([2,3,4,5]) - sage: G.an_element() + sage: G = AbelianGroup([2,3,4,5]) # optional - sage.groups + sage: G.an_element() # optional - sage.groups f0*f1*f2*f3 """ from sage.misc.misc_c import prod diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index e6770f9da4d..1a68f05cff6 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -6,10 +6,10 @@ EXAMPLES:: - sage: F = GF(3) - sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F,2, [1,1,0,1])] - sage: G = MatrixGroup(gens) - sage: G.conjugacy_classes_representatives() + sage: F = GF(3) # optional - sage.libs.pari + sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F,2, [1,1,0,1])] # optional - sage.libs.pari + sage: G = MatrixGroup(gens) # optional - sage.libs.pari + sage: G.conjugacy_classes_representatives() # optional - sage.libs.pari ( [1 0] [0 2] [0 1] [2 0] [0 2] [0 1] [0 2] [0 1], [1 1], [2 1], [0 2], [1 2], [2 2], [1 0] @@ -18,7 +18,7 @@ The finitely generated matrix groups can also be constructed as subgroups of matrix groups:: - sage: SL2Z = SL(2,ZZ) + sage: SL2Z = SL(2, ZZ) sage: S, T = SL2Z.gens() sage: SL2Z.subgroup([T^2]) Subgroup with 1 generators ( @@ -155,37 +155,37 @@ def QuaternionMatrixGroupGF3(): is the product of `I` and `J`. :: sage: from sage.groups.matrix_gps.finitely_generated import QuaternionMatrixGroupGF3 - sage: Q = QuaternionMatrixGroupGF3() - sage: Q.order() + sage: Q = QuaternionMatrixGroupGF3() # optional - sage.libs.pari + sage: Q.order() # optional - sage.libs.pari 8 - sage: aye = Q.gens()[0]; aye + sage: aye = Q.gens()[0]; aye # optional - sage.libs.pari [1 1] [1 2] - sage: jay = Q.gens()[1]; jay + sage: jay = Q.gens()[1]; jay # optional - sage.libs.pari [2 1] [1 1] - sage: kay = aye*jay; kay + sage: kay = aye*jay; kay # optional - sage.libs.pari [0 2] [1 0] TESTS:: - sage: groups.matrix.QuaternionGF3() + sage: groups.matrix.QuaternionGF3() # optional - sage.libs.pari Matrix group over Finite Field of size 3 with 2 generators ( [1 1] [2 1] [1 2], [1 1] ) - sage: Q = QuaternionMatrixGroupGF3() - sage: QP = Q.as_permutation_group() - sage: QP.is_isomorphic(QuaternionGroup()) + sage: Q = QuaternionMatrixGroupGF3() # optional - sage.libs.pari + sage: QP = Q.as_permutation_group() # optional - sage.libs.pari + sage: QP.is_isomorphic(QuaternionGroup()) # optional - sage.libs.pari True - sage: H = DihedralGroup(4) - sage: H.order() + sage: H = DihedralGroup(4) # optional - sage.groups sage.libs.pari + sage: H.order() # optional - sage.groups sage.libs.pari 8 - sage: QP.is_abelian(), H.is_abelian() + sage: QP.is_abelian(), H.is_abelian() # optional - sage.groups sage.libs.pari (False, False) - sage: QP.is_isomorphic(H) + sage: QP.is_isomorphic(H) # optional - sage.groups sage.libs.pari False """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -210,9 +210,9 @@ def MatrixGroup(*gens, **kwds): EXAMPLES:: - sage: F = GF(5) - sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])] - sage: G = MatrixGroup(gens); G + sage: F = GF(5) # optional - sage.libs.pari + sage: gens = [matrix(F,2, [1,2, -1, 1]), matrix(F,2, [1,1, 0,1])] # optional - sage.libs.pari + sage: G = MatrixGroup(gens); G # optional - sage.libs.pari Matrix group over Finite Field of size 5 with 2 generators ( [1 2] [1 1] [4 1], [0 1] @@ -224,8 +224,8 @@ def MatrixGroup(*gens, **kwds): matrices over the finite field, so creates that matrix group there:: - sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2] - sage: G = MatrixGroup(gens); G + sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2] # optional - sage.libs.pari + sage: G = MatrixGroup(gens); G # optional - sage.libs.pari Matrix group over Finite Field of size 7 with 3 generators ( [1 2] [1 1] [2 0] [6 1], [0 1], [0 2] @@ -233,17 +233,17 @@ def MatrixGroup(*gens, **kwds): Each generator must be invertible:: - sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])]) + sage: G = MatrixGroup([matrix(ZZ, 2, [1,2,3,4])]) Traceback (most recent call last): ... ValueError: each generator must be an invertible matrix - sage: F = GF(5); MS = MatrixSpace(F,2,2) - sage: MatrixGroup([MS.0]) + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari + sage: MatrixGroup([MS.0]) # optional - sage.libs.pari Traceback (most recent call last): ... ValueError: each generator must be an invertible matrix - sage: MatrixGroup([MS.0], check=False) # works formally but is mathematical nonsense + sage: MatrixGroup([MS.0], check=False) # works formally but is mathematical nonsense # optional - sage.libs.pari Matrix group over Finite Field of size 5 with 1 generators ( [1 0] [0 0] @@ -328,9 +328,9 @@ class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic): sage: MatrixGroup(m1, m2) == MatrixGroup(m2, m1) False - sage: G = GL(2, GF(3)) - sage: H = G.as_matrix_group() - sage: H == G, G == H + sage: G = GL(2, GF(3)) # optional - sage.libs.pari + sage: H = G.as_matrix_group() # optional - sage.libs.pari + sage: H == G, G == H # optional - sage.libs.pari (True, True) """ @@ -366,24 +366,24 @@ def gens(self): EXAMPLES:: - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]), MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens) - sage: gens[0] in G + sage: F = GF(3); MS = MatrixSpace(F,2,2) # optional - sage.libs.pari + sage: gens = [MS([[1,0],[0,1]]), MS([[1,1],[0,1]])] # optional - sage.libs.pari + sage: G = MatrixGroup(gens) # optional - sage.libs.pari + sage: gens[0] in G # optional - sage.libs.pari True - sage: gens = G.gens() - sage: gens[0] in G + sage: gens = G.gens() # optional - sage.libs.pari + sage: gens[0] in G # optional - sage.libs.pari True - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] + sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] # optional - sage.libs.pari - sage: F = GF(5); MS = MatrixSpace(F,2,2) - sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) - sage: G + sage: F = GF(5); MS = MatrixSpace(F,2,2) # optional - sage.libs.pari + sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) # optional - sage.libs.pari + sage: G # optional - sage.libs.pari Matrix group over Finite Field of size 5 with 2 generators ( [1 0] [1 2] [0 1], [3 4] ) - sage: G.gens() + sage: G.gens() # optional - sage.libs.pari ( [1 0] [1 2] [0 1], [3 4] @@ -402,13 +402,13 @@ def gen(self, i): EXAMPLES:: - sage: H = GL(2, GF(3)) - sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) - sage: G = H.subgroup([h1, h2]) - sage: G.gen(0) + sage: H = GL(2, GF(3)) # optional - sage.libs.pari + sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) # optional - sage.libs.pari + sage: G = H.subgroup([h1, h2]) # optional - sage.libs.pari + sage: G.gen(0) # optional - sage.libs.pari [1 0] [2 1] - sage: G.gen(0).matrix() == h1.matrix() + sage: G.gen(0).matrix() == h1.matrix() # optional - sage.libs.pari True """ return self.gens()[i] @@ -423,10 +423,10 @@ def ngens(self): EXAMPLES:: - sage: H = GL(2, GF(3)) - sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) - sage: G = H.subgroup([h1, h2]) - sage: G.ngens() + sage: H = GL(2, GF(3)) # optional - sage.libs.pari + sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) # optional - sage.libs.pari + sage: G = H.subgroup([h1, h2]) # optional - sage.libs.pari + sage: G.ngens() # optional - sage.libs.pari 2 """ return len(self._gens_matrix) diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index e543e3e43ae..1d3a1cdea24 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -3,16 +3,16 @@ Matrix Group Elements EXAMPLES:: - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] - sage: G = MatrixGroup(gens); G + sage: F = GF(3); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari + sage: gens = [MS([[1,0],[0,1]]), MS([[1,1],[0,1]])] # optional - sage.libs.pari + sage: G = MatrixGroup(gens); G # optional - sage.libs.pari Matrix group over Finite Field of size 3 with 2 generators ( [1 0] [1 1] [0 1], [0 1] ) - sage: g = G([[1,1],[0,1]]) - sage: h = G([[1,2],[0,1]]) - sage: g*h + sage: g = G([[1,1],[0,1]]) # optional - sage.libs.pari + sage: h = G([[1,2],[0,1]]) # optional - sage.libs.pari + sage: g*h # optional - sage.libs.pari [1 0] [0 1] @@ -20,7 +20,7 @@ You cannot add two matrices, since this is not a group operation. You can coerce matrices back to the matrix space and add them there:: - sage: g + h + sage: g + h # optional - sage.libs.pari Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for +: @@ -33,14 +33,14 @@ there:: [0 1], [0 1] )' - sage: g.matrix() + h.matrix() + sage: g.matrix() + h.matrix() # optional - sage.libs.pari [2 0] [0 2] Similarly, you cannot multiply group elements by scalars but you can do it with the underlying matrices:: - sage: 2*g + sage: 2*g # optional - sage.libs.pari Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Integer Ring' and 'Matrix group over Finite Field of size 3 with 2 generators ( @@ -107,8 +107,8 @@ cpdef is_MatrixGroupElement(x): sage: is_MatrixGroupElement('helloooo') False - sage: G = GL(2,3) - sage: is_MatrixGroupElement(G.an_element()) + sage: G = GL(2,3) # optional - sage.libs.pari + sage: is_MatrixGroupElement(G.an_element()) # optional - sage.libs.pari True """ return isinstance(x, (MatrixGroupElement_generic, MatrixGroupElement_gap)) @@ -139,9 +139,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: g + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: g # optional - sage.combinat [ 0 0 -1] [ 1 0 -1] [ 0 1 -1] @@ -152,9 +152,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): TESTS:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: TestSuite(g).run() + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: TestSuite(g).run() # optional - sage.combinat """ if convert: M = parent.matrix_space()(M) @@ -175,9 +175,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): r""" TESTS:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: hash(g) + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: hash(g) # optional - sage.combinat 660522311176098153 # 64-bit -606138007 # 32-bit """ @@ -189,9 +189,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): TESTS:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: loads(g.dumps()) == g + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: loads(g.dumps()) == g # optional - sage.combinat True """ return (_unpickle_generic_element, (self.parent(), self._matrix,)) @@ -202,8 +202,8 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: W.an_element() + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: W.an_element() # optional - sage.combinat [ 0 0 -1] [ 1 0 -1] [ 0 1 -1] @@ -214,9 +214,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): r""" EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: latex(g) + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: latex(g) # optional - sage.combinat \left(\begin{array}{rrr} 0 & 0 & -1 \\ 1 & 0 & -1 \\ @@ -229,13 +229,13 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): """ EXAMPLES:: - sage: W = CoxeterGroup(['A',4], base_ring=ZZ) - sage: g = W.gen(0) - sage: g * vector([1,1,1,1]) + sage: W = CoxeterGroup(['A',4], base_ring=ZZ) # optional - sage.combinat + sage: g = W.gen(0) # optional - sage.combinat + sage: g * vector([1,1,1,1]) # optional - sage.combinat (0, 1, 1, 1) - sage: v = vector([3,2,1,-1]) - sage: g = W.gen(1) - sage: v * g == v * g.matrix() # indirect doctest + sage: v = vector([3,2,1,-1]) # optional - sage.combinat + sage: g = W.gen(1) # optional - sage.combinat + sage: v * g == v * g.matrix() # indirect doctest # optional - sage.combinat True """ if not is_MatrixGroupElement(x) and x not in self.parent().base_ring(): @@ -251,16 +251,16 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): """ EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: TestSuite(g).run() - sage: h = W.gen(0) * W.gen(1) * W.gen(2) - sage: g == h + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: TestSuite(g).run() # optional - sage.combinat + sage: h = W.gen(0) * W.gen(1) * W.gen(2) # optional - sage.combinat + sage: g == h # optional - sage.combinat True - sage: a = W.gen(0) - sage: a == g + sage: a = W.gen(0) # optional - sage.combinat + sage: a == g # optional - sage.combinat False - sage: a != g + sage: a != g # optional - sage.combinat True """ cdef MatrixGroupElement_generic x = self @@ -273,13 +273,13 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.gen(0) - sage: g + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.gen(0) # optional - sage.combinat + sage: g # optional - sage.combinat [-1 1 0] [ 0 1 0] [ 0 0 1] - sage: g.list() + sage: g.list() # optional - sage.combinat [[-1, 1, 0], [0, 1, 0], [0, 0, 1]] """ return [r.list() for r in self._matrix.rows()] @@ -294,19 +294,19 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.gen(0) - sage: g.matrix() + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.gen(0) # optional - sage.combinat + sage: g.matrix() # optional - sage.combinat [-1 1 0] [ 0 1 0] [ 0 0 1] - sage: parent(g.matrix()) + sage: parent(g.matrix()) # optional - sage.combinat Full MatrixSpace of 3 by 3 dense matrices over Integer Ring Matrices have extra functionality that matrix group elements do not have:: - sage: g.matrix().charpoly('t') + sage: g.matrix().charpoly('t') # optional - sage.combinat t^3 - t^2 - t + 1 """ return self._matrix @@ -317,9 +317,9 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A', 3], base_ring=ZZ) - sage: g = W.gen(0) - sage: matrix(RDF, g) + sage: W = CoxeterGroup(['A', 3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.gen(0) # optional - sage.combinat + sage: matrix(RDF, g) # optional - sage.combinat [-1.0 1.0 0.0] [ 0.0 1.0 0.0] [ 0.0 0.0 1.0] @@ -333,10 +333,10 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.gen(0) - sage: h = W.an_element() - sage: g * h + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.gen(0) # optional - sage.combinat + sage: h = W.an_element() # optional - sage.combinat + sage: g * h # optional - sage.combinat [ 1 0 0] [ 1 0 -1] [ 0 1 -1] @@ -354,14 +354,14 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3]) - sage: g = W.gen(0) - sage: g.is_one() + sage: W = CoxeterGroup(['A',3]) # optional - sage.combinat + sage: g = W.gen(0) # optional - sage.combinat + sage: g.is_one() # optional - sage.combinat False - sage: W.an_element().is_one() + sage: W.an_element().is_one() # optional - sage.combinat False - sage: W.one().is_one() + sage: W.one().is_one() # optional - sage.combinat True """ return self._matrix.is_one() @@ -376,22 +376,22 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) - sage: g = W.an_element() - sage: ~g + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: ~g # optional - sage.combinat [-1 1 0] [-1 0 1] [-1 0 0] - sage: g * ~g == W.one() + sage: g * ~g == W.one() # optional - sage.combinat True - sage: ~g * g == W.one() + sage: ~g * g == W.one() # optional - sage.combinat True - sage: W = CoxeterGroup(['B',3]) - sage: W.base_ring() + sage: W = CoxeterGroup(['B',3]) # optional - sage.combinat sage.rings.number_field + sage: W.base_ring() # optional - sage.combinat sage.rings.number_field Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? - sage: g = W.an_element() - sage: ~g + sage: g = W.an_element() # optional - sage.combinat sage.rings.number_field + sage: ~g # optional - sage.combinat sage.rings.number_field [-1 1 0] [-1 0 a] [-a 0 1] @@ -418,12 +418,12 @@ def _unpickle_generic_element(G, mat): EXAMPLES:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) - sage: G = MatrixGroup(m1, m2) - sage: m = G.an_element() - sage: from sage.groups.matrix_gps.group_element import _unpickle_generic_element - sage: _unpickle_generic_element(G, m.matrix()) == m + sage: m1 = matrix(SR, [[1,2],[3,4]]) # optional - sage.symbolic + sage: m2 = matrix(SR, [[1,3],[-1,0]]) # optional - sage.symbolic + sage: G = MatrixGroup(m1, m2) # optional - sage.symbolic + sage: m = G.an_element() # optional - sage.symbolic + sage: from sage.groups.matrix_gps.group_element import _unpickle_generic_element # optional - sage.symbolic + sage: _unpickle_generic_element(G, m.matrix()) == m # optional - sage.symbolic True """ return G.element_class(G, mat, False, False) diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index bc7ea013a5e..c580596a1f6 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -93,14 +93,14 @@ def GL(n, R, var='a'): EXAMPLES:: - sage: G = GL(6,GF(5)) - sage: G.order() + sage: G = GL(6, GF(5)) # optional - sage.libs.pari + sage: G.order() # optional - sage.libs.pari 11064475422000000000000000 - sage: G.base_ring() + sage: G.base_ring() # optional - sage.libs.pari Finite Field of size 5 - sage: G.category() + sage: G.category() # optional - sage.libs.pari Category of finite groups - sage: TestSuite(G).run() + sage: TestSuite(G).run() # optional - sage.libs.pari sage: G = GL(6, QQ) sage: G.category() @@ -109,33 +109,33 @@ def GL(n, R, var='a'): Here is the Cayley graph of (relatively small) finite General Linear Group:: - sage: g = GL(2,3) - sage: d = g.cayley_graph(); d + sage: g = GL(2,3) # optional - sage.libs.pari + sage: d = g.cayley_graph(); d # optional - sage.graphs sage.libs.pari Digraph on 48 vertices - sage: d.plot(color_by_label=True, vertex_size=0.03, vertex_labels=False) # long time + sage: d.plot(color_by_label=True, vertex_size=0.03, vertex_labels=False) # long time # optional - sage.graphs sage.libs.pari sage.plot Graphics object consisting of 144 graphics primitives - sage: d.plot3d(color_by_label=True) # long time + sage: d.plot3d(color_by_label=True) # long time # optional - sage.graphs sage.libs.pari sage.plot Graphics3d Object :: - sage: F = GF(3); MS = MatrixSpace(F,2,2) - sage: gens = [MS([[2,0],[0,1]]), MS([[2,1],[2,0]])] - sage: G = MatrixGroup(gens) - sage: G.order() + sage: F = GF(3); MS = MatrixSpace(F,2,2) # optional - sage.libs.pari + sage: gens = [MS([[2,0],[0,1]]), MS([[2,1],[2,0]])] # optional - sage.libs.pari + sage: G = MatrixGroup(gens) # optional - sage.libs.pari + sage: G.order() # optional - sage.libs.pari 48 - sage: G.cardinality() + sage: G.cardinality() # optional - sage.libs.pari 48 - sage: H = GL(2,F) - sage: H.order() + sage: H = GL(2,F) # optional - sage.libs.pari + sage: H.order() # optional - sage.libs.pari 48 - sage: H == G + sage: H == G # optional - sage.libs.pari True - sage: H.gens() == G.gens() + sage: H.gens() == G.gens() # optional - sage.libs.pari True - sage: H.as_matrix_group() == H + sage: H.as_matrix_group() == H # optional - sage.libs.pari True - sage: H.gens() + sage: H.gens() # optional - sage.libs.pari ( [2 0] [2 1] [0 1], [2 0] @@ -143,11 +143,11 @@ def GL(n, R, var='a'): TESTS:: - sage: groups.matrix.GL(2, 3) + sage: groups.matrix.GL(2, 3) # optional - sage.groups sage.libs.pari General Linear Group of degree 2 over Finite Field of size 3 - sage: groups.matrix.GL(1, ZZ).category() + sage: groups.matrix.GL(1, ZZ).category() # optional - sage.groups Category of groups - sage: groups.matrix.GL(1, QQ).category() + sage: groups.matrix.GL(1, QQ).category() # optional - sage.groups Category of infinite groups """ degree, ring = normalize_args_vectorspace(n, R, var='a') @@ -202,15 +202,15 @@ def SL(n, R, var='a'): EXAMPLES:: - sage: SL(3, GF(2)) + sage: SL(3, GF(2)) # optional - sage.libs.pari Special Linear Group of degree 3 over Finite Field of size 2 - sage: G = SL(15, GF(7)); G + sage: G = SL(15, GF(7)); G # optional - sage.libs.pari Special Linear Group of degree 15 over Finite Field of size 7 - sage: G.category() + sage: G.category() # optional - sage.libs.pari Category of finite groups - sage: G.order() + sage: G.order() # optional - sage.libs.pari 1956712595698146962015219062429586341124018007182049478916067369638713066737882363393519966343657677430907011270206265834819092046250232049187967718149558134226774650845658791865745408000000 - sage: len(G.gens()) + sage: len(G.gens()) # optional - sage.libs.pari 2 sage: G = SL(2, ZZ); G Special Linear Group of degree 2 over Integer Ring @@ -224,7 +224,7 @@ def SL(n, R, var='a'): Next we compute generators for `\mathrm{SL}_3(\ZZ)` :: - sage: G = SL(3,ZZ); G + sage: G = SL(3, ZZ); G Special Linear Group of degree 3 over Integer Ring sage: G.gens() ( @@ -276,8 +276,8 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = SL(2,GF(5)) - sage: G._check_matrix(G.an_element().matrix()) + sage: G = SL(2, GF(5)) # optional - sage.libs.pari + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari """ if self._special: if x.determinant() != 1: diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 3c3a4e321fd..703c61209e1 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -3,14 +3,14 @@ Loading, saving, ... works:: - sage: G = GL(2,5); G + sage: G = GL(2,5); G # optional - sage.libs.pari General Linear Group of degree 2 over Finite Field of size 5 - sage: TestSuite(G).run() + sage: TestSuite(G).run() # optional - sage.libs.pari - sage: g = G.1; g + sage: g = G.1; g # optional - sage.libs.pari [4 1] [4 0] - sage: TestSuite(g).run() + sage: TestSuite(g).run() # optional - sage.libs.pari We test that :trac:`9437` is fixed:: @@ -99,9 +99,9 @@ class MatrixGroup_base(Group): TESTS:: - sage: G = SO(3, GF(11)); G + sage: G = SO(3, GF(11)); G # optional - sage.libs.pari Special Orthogonal Group of degree 3 over Finite Field of size 11 - sage: G.category() + sage: G.category() # optional - sage.libs.pari Category of finite groups """ _ambient = None # internal attribute to register the ambient group in case this instance is a subgroup @@ -129,9 +129,9 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = SU(2,GF(5)); F = G.base_ring() # this is GF(5^2,'a') - sage: G._check_matrix(identity_matrix(F,2)) - sage: G._check_matrix(matrix(F,[[1,1],[0,1]])) + sage: G = SU(2,GF(5)); F = G.base_ring() # this is GF(5^2,'a') # optional - sage.libs.pari + sage: G._check_matrix(identity_matrix(F,2)) # optional - sage.libs.pari + sage: G._check_matrix(matrix(F,[[1,1],[0,1]])) # optional - sage.libs.pari Traceback (most recent call last): ... TypeError: matrix must be unitary with respect to the hermitian form @@ -150,8 +150,8 @@ def as_matrix_group(self): EXAMPLES:: - sage: G = SU(4,GF(5)) - sage: G.as_matrix_group() + sage: G = SU(4,GF(5)) # optional - sage.libs.pari + sage: G.as_matrix_group() # optional - sage.libs.pari Matrix group over Finite Field in a of size 5^2 with 2 generators ( [ a 0 0 0] [ 1 0 4*a + 3 0] [ 0 2*a + 3 0 0] [ 1 0 0 0] @@ -159,8 +159,8 @@ def as_matrix_group(self): [ 0 0 0 3*a], [ 0 3*a + 1 0 0] ) - sage: G = GO(3,GF(5)) - sage: G.as_matrix_group() + sage: G = GO(3,GF(5)) # optional - sage.libs.pari + sage: G.as_matrix_group() # optional - sage.libs.pari Matrix group over Finite Field of size 5 with 2 generators ( [2 0 0] [0 1 0] [0 3 0] [1 4 4] @@ -183,22 +183,22 @@ def subgroup(self, generators, check=True): EXAMPLES:: - sage: UCF = UniversalCyclotomicField() - sage: G = GL(3, UCF) - sage: e3 = UCF.gen(3); e5 = UCF.gen(5) - sage: m = matrix(UCF, 3,3, [[e3, 1, 0], [0, e5, 7],[4, 3, 2]]) - sage: S = G.subgroup([m]); S + sage: UCF = UniversalCyclotomicField() # optional - sage.rings.number_field + sage: G = GL(3, UCF) # optional - sage.rings.number_field + sage: e3 = UCF.gen(3); e5 = UCF.gen(5) # optional - sage.rings.number_field + sage: m = matrix(UCF, 3,3, [[e3, 1, 0], [0, e5, 7],[4, 3, 2]]) # optional - sage.rings.number_field + sage: S = G.subgroup([m]); S # optional - sage.rings.number_field Subgroup with 1 generators ( [E(3) 1 0] [ 0 E(5) 7] [ 4 3 2] ) of General Linear Group of degree 3 over Universal Cyclotomic Field - sage: CF3 = CyclotomicField(3) - sage: G = GL(3, CF3) - sage: e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[e3, 1, 0], [0, ~e3, 7],[4, 3, 2]]) - sage: S = G.subgroup([m]); S + sage: CF3 = CyclotomicField(3) # optional - sage.rings.number_field + sage: G = GL(3, CF3) # optional - sage.rings.number_field + sage: e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 3,3, [[e3, 1, 0], [0, ~e3, 7],[4, 3, 2]]) # optional - sage.rings.number_field + sage: S = G.subgroup([m]); S # optional - sage.rings.number_field Subgroup with 1 generators ( [ zeta3 1 0] [ 0 -zeta3 - 1 7] @@ -207,8 +207,8 @@ def subgroup(self, generators, check=True): TESTS:: - sage: TestSuite(G).run() - sage: TestSuite(S).run() + sage: TestSuite(G).run() # optional - sage.rings.number_field + sage: TestSuite(S).run() # optional - sage.rings.number_field """ try: test = self.is_finite() @@ -257,10 +257,10 @@ def _repr_(self): EXAMPLES:: - 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 + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari + sage: gens = [MS([[1,2],[-1,1]]), MS([[1,1],[0,1]])] # optional - sage.libs.pari + sage: G = MatrixGroup(gens) # optional - sage.libs.pari + sage: G # optional - sage.libs.pari Matrix group over Finite Field of size 5 with 2 generators ( [1 2] [1 1] [4 1], [0 1] @@ -268,11 +268,11 @@ def _repr_(self): case of being a subgroup:: - sage: CF3 = CyclotomicField(3) - sage: G = GL(2, CF3) - sage: e3 = CF3.gen() - sage: m = matrix(CF3, 2,2, [[e3, 1], [0, ~e3]]) - sage: S = G.subgroup([m]); S + sage: CF3 = CyclotomicField(3) # optional - sage.rings.number_field + sage: G = GL(2, CF3) # optional - sage.rings.number_field + sage: e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 2,2, [[e3, 1], [0, ~e3]]) # optional - sage.rings.number_field + sage: S = G.subgroup([m]); S # optional - sage.rings.number_field Subgroup with 1 generators ( [ zeta3 1] [ 0 -zeta3 - 1] @@ -305,8 +305,8 @@ def _repr_option(self, key): EXAMPLES:: - sage: SO3 = groups.matrix.SO(3, QQ) - sage: SO3._repr_option('element_ascii_art') + sage: SO3 = groups.matrix.SO(3, QQ) # optional - sage.groups + sage: SO3._repr_option('element_ascii_art') # optional - sage.groups True """ if key == 'element_ascii_art': @@ -317,9 +317,9 @@ def _latex_(self): r""" EXAMPLES:: - sage: MS = MatrixSpace(GF(5), 2, 2) - sage: G = MatrixGroup(MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])) - sage: latex(G) + sage: MS = MatrixSpace(GF(5), 2, 2) # optional - sage.libs.pari + sage: G = MatrixGroup(MS([[1,2],[-1,1]]), MS([[1,1],[0,1]])) # optional - sage.libs.pari + sage: latex(G) # optional - sage.libs.pari \left\langle \left(\begin{array}{rr} 1 & 2 \\ 4 & 1 @@ -345,19 +345,19 @@ def sign_representation(self, base_ring=None, side="twosided"): EXAMPLES:: sage: G = GL(2, QQ) - sage: V = G.sign_representation() - sage: e = G.an_element() - sage: e + sage: V = G.sign_representation() # optional - sage.combinat + sage: e = G.an_element() # optional - sage.combinat + sage: e # optional - sage.combinat [1 0] [0 1] - sage: V._default_sign(e) + sage: V._default_sign(e) # optional - sage.combinat 1 - sage: m2 = V.an_element() - sage: m2 + sage: m2 = V.an_element() # optional - sage.combinat + sage: m2 # optional - sage.combinat 2*B['v'] - sage: m2*e + sage: m2*e # optional - sage.combinat 2*B['v'] - sage: m2*e*e + sage: m2*e*e # optional - sage.combinat 2*B['v'] """ if base_ring is None: @@ -422,7 +422,7 @@ def degree(self): EXAMPLES:: - sage: SU(5,5).degree() + sage: SU(5,5).degree() # optional - sage.libs.pari 5 """ return self._deg @@ -437,11 +437,11 @@ def matrix_space(self): EXAMPLES:: - sage: F = GF(5); MS = MatrixSpace(F,2,2) - sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) - sage: G.matrix_space() + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari + sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) # optional - sage.libs.pari + sage: G.matrix_space() # optional - sage.libs.pari Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5 - sage: G.matrix_space() is MS + sage: G.matrix_space() is MS # optional - sage.libs.pari True """ return MatrixSpace(self.base_ring(), self.degree()) @@ -466,11 +466,11 @@ def __richcmp__(self, other, op): EXAMPLES:: - sage: G = GL(2,3) - sage: H = MatrixGroup(G.gens()) - sage: H == G + sage: G = GL(2,3) # optional - sage.libs.pari + sage: H = MatrixGroup(G.gens()) # optional - sage.libs.pari + sage: H == G # optional - sage.libs.pari True - sage: G == H + sage: G == H # optional - sage.libs.pari True sage: MS = MatrixSpace(QQ, 2, 2) @@ -482,11 +482,11 @@ def __richcmp__(self, other, op): TESTS:: - sage: G = groups.matrix.GL(4,2) - sage: H = MatrixGroup(G.gens()) - sage: G == H + sage: G = groups.matrix.GL(4,2) # optional - sage.groups sage.libs.pari + sage: H = MatrixGroup(G.gens()) # optional - sage.groups sage.libs.pari + sage: G == H # optional - sage.groups sage.libs.pari True - sage: G != H + sage: G != H # optional - sage.groups sage.libs.pari False """ if not is_MatrixGroup(other): diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index ef3e7f4bf3b..9944b4254df 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -8,17 +8,17 @@ sage: SL(2, ZZ) Special Linear Group of degree 2 over Integer Ring - sage: G = SL(2,GF(3)); G + sage: G = SL(2, GF(3)); G # optional - sage.libs.pari Special Linear Group of degree 2 over Finite Field of size 3 - sage: G.is_finite() + sage: G.is_finite() # optional - sage.libs.pari True - sage: G.conjugacy_classes_representatives() + sage: G.conjugacy_classes_representatives() # optional - sage.libs.pari ( [1 0] [0 2] [0 1] [2 0] [0 2] [0 1] [0 2] [0 1], [1 1], [2 1], [0 2], [1 2], [2 2], [1 0] ) - sage: G = SL(6,GF(5)) - sage: G.gens() + sage: G = SL(6, GF(5)) # optional - sage.libs.pari + sage: G.gens() # optional - sage.libs.pari ( [2 0 0 0 0 0] [4 0 0 0 0 1] [0 3 0 0 0 0] [4 0 0 0 0 0] @@ -41,7 +41,6 @@ ############################################################################## from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic -from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap from sage.structure.unique_representation import CachedRepresentation @@ -81,12 +80,12 @@ def normalize_args_vectorspace(*args, **kwds): TESTS:: sage: from sage.groups.matrix_gps.named_group import normalize_args_vectorspace - sage: A = AffineSpace(2, GF(4,'a')); A + sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.libs.pari Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: normalize_args_vectorspace(A) + sage: normalize_args_vectorspace(A) # optional - sage.libs.pari (2, Finite Field in a of size 2^2) - sage: normalize_args_vectorspace(2,4) # shorthand + sage: normalize_args_vectorspace(2,4) # shorthand # optional - sage.libs.pari (2, Finite Field in a of size 2^2) sage: V = ZZ^3; V @@ -148,12 +147,12 @@ def normalize_args_invariant_form(R, d, invariant_form): TESTS:: sage: from sage.groups.matrix_gps.named_group import normalize_args_invariant_form - sage: CF3 = CyclotomicField(3) - sage: m = normalize_args_invariant_form(CF3, 3, (1,2,3,0,2,0,0,2,1)); m + sage: CF3 = CyclotomicField(3) # optional - sage.rings.number_field + sage: m = normalize_args_invariant_form(CF3, 3, (1,2,3,0,2,0,0,2,1)); m # optional - sage.rings.number_field [1 2 3] [0 2 0] [0 2 1] - sage: m.base_ring() == CF3 + sage: m.base_ring() == CF3 # optional - sage.rings.number_field True sage: normalize_args_invariant_form(ZZ, 3, (1,2,3,0,2,0,0,2)) @@ -286,15 +285,15 @@ def __richcmp__(self, other, op): EXAMPLES:: - sage: G = GL(2,3) - sage: G == MatrixGroup(G.gens()) + sage: G = GL(2,3) # optional - sage.libs.pari + sage: G == MatrixGroup(G.gens()) # optional - sage.libs.pari True - sage: G = groups.matrix.GL(4,2) - sage: H = MatrixGroup(G.gens()) - sage: G == H + sage: G = groups.matrix.GL(4,2) # optional - sage.libs.pari + sage: H = MatrixGroup(G.gens()) # optional - sage.libs.pari + sage: G == H # optional - sage.libs.pari True - sage: G != H + sage: G != H # optional - sage.libs.pari False """ return MatrixGroup_generic.__richcmp__(self, other, op) diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 209ab7f952f..8ab908095b0 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -33,7 +33,7 @@ EXAMPLES:: - sage: GO(3,7) + sage: GO(3,7) # optional - sage.libs.pari General Orthogonal Group of degree 3 over Finite Field of size 7 sage: G = SO(4, GF(7), 1); G # optional - sage.libs.pari @@ -477,10 +477,10 @@ def invariant_bilinear_form(self): EXAMPLES:: - sage: GO(2,3,+1).invariant_bilinear_form() + sage: GO(2,3,+1).invariant_bilinear_form() # optional - sage.libs.pari [0 1] [1 0] - sage: GO(2,3,-1).invariant_bilinear_form() + sage: GO(2,3,-1).invariant_bilinear_form() # optional - sage.libs.pari [2 1] [1 1] sage: G = GO(4, QQ) diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index e6c5a233057..2babbcd0c6f 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -3,17 +3,17 @@ EXAMPLES:: - sage: G = Sp(4,GF(7)); G + sage: G = Sp(4, GF(7)); G # optional - sage.libs.pari Symplectic Group of degree 4 over Finite Field of size 7 - sage: g = prod(G.gens()); g + sage: g = prod(G.gens()); g # optional - sage.libs.pari [3 0 3 0] [1 0 0 0] [0 1 0 1] [0 2 0 0] - sage: m = g.matrix() - sage: m * G.invariant_form() * m.transpose() == G.invariant_form() + sage: m = g.matrix() # optional - sage.libs.pari + sage: m * G.invariant_form() * m.transpose() == G.invariant_form() # optional - sage.libs.pari True - sage: G.order() + sage: G.order() # optional - sage.libs.pari 276595200 AUTHORS: @@ -108,14 +108,14 @@ def Sp(n, R, var='a', invariant_form=None): [ 0 0 0 2] [-1 0 0 0] [ 0 -2 0 0] - sage: pm = Permutation([2,1,4,3]).to_matrix() - sage: g = Sp4(pm); g in Sp4; g + sage: pm = Permutation([2,1,4,3]).to_matrix() # optional - sage.combinat + sage: g = Sp4(pm); g in Sp4; g # optional - sage.combinat True [0 1 0 0] [1 0 0 0] [0 0 0 1] [0 0 1 0] - sage: Sp4m(pm) + sage: Sp4m(pm) # optional - sage.combinat Traceback (most recent call last): ... TypeError: matrix must be symplectic with respect to the alternating form @@ -124,7 +124,7 @@ def Sp(n, R, var='a', invariant_form=None): [-1 0 0 0] [ 0 -2 0 0] - sage: Sp(4,3, invariant_form=[[0,0,0,1],[0,0,1,0],[0,2,0,0], [2,0,0,0]]) + sage: Sp(4,3, invariant_form=[[0,0,0,1],[0,0,1,0],[0,2,0,0], [2,0,0,0]]) # optional - sage.libs.pari Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -137,7 +137,7 @@ def Sp(n, R, var='a', invariant_form=None): Symplectic Group of degree 2 over Finite Field of size 3 sage: G = Sp(4,5) # optional - sage.libs.pari - sage: TestSuite(G).run() + sage: TestSuite(G).run() # optional - sage.libs.pari """ degree, ring = normalize_args_vectorspace(n, R, var=var) if degree % 2: diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index a163b067e5c..db54b803064 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -6,18 +6,18 @@ EXAMPLES:: - sage: G = SU(3,5) - sage: G.order() + sage: G = SU(3,5) # optional - sage.libs.pari + sage: G.order() # optional - sage.libs.pari 378000 - sage: G + sage: G # optional - sage.libs.pari Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: G.gens() + sage: G.gens() # optional - sage.libs.pari ( [ a 0 0] [4*a 4 1] [ 0 2*a + 2 0] [ 4 4 0] [ 0 0 3*a], [ 1 0 0] ) - sage: G.base_ring() + sage: G.base_ring() # optional - sage.libs.pari Finite Field in a of size 5^2 AUTHORS: @@ -73,7 +73,7 @@ def finite_field_sqrt(ring): EXAMPLES:: sage: from sage.groups.matrix_gps.unitary import finite_field_sqrt - sage: finite_field_sqrt(GF(4, 'a')) + sage: finite_field_sqrt(GF(4, 'a')) # optional - sage.libs.pari 2 """ if not isinstance(ring, FiniteField): @@ -96,7 +96,7 @@ def _UG(n, R, special, var='a', invariant_form=None): TESTS:: - sage: GU(3,25).order() # indirect doctest + sage: GU(3,25).order() # indirect doctest # optional - sage.libs.pari 3961191000000 """ prefix = 'General' @@ -188,9 +188,9 @@ def GU(n, R, var='a', invariant_form=None): EXAMPLES:: - sage: G = GU(3, 7); G + sage: G = GU(3, 7); G # optional - sage.libs.pari General Unitary Group of degree 3 over Finite Field in a of size 7^2 - sage: G.gens() + sage: G.gens() # optional - sage.libs.pari ( [ a 0 0] [6*a 6 1] [ 0 1 0] [ 6 6 0] @@ -199,10 +199,10 @@ def GU(n, R, var='a', invariant_form=None): sage: GU(2,QQ) General Unitary Group of degree 2 over Rational Field - sage: G = GU(3, 5, var='beta') - sage: G.base_ring() + sage: G = GU(3, 5, var='beta') # optional - sage.libs.pari + sage: G.base_ring() # optional - sage.libs.pari Finite Field in beta of size 5^2 - sage: G.gens() + sage: G.gens() # optional - sage.libs.pari ( [ beta 0 0] [4*beta 4 1] [ 0 1 0] [ 4 4 0] @@ -211,27 +211,27 @@ def GU(n, R, var='a', invariant_form=None): Using the ``invariant_form`` option:: - sage: UCF = UniversalCyclotomicField(); e5=UCF.gen(5) - sage: m = matrix(UCF, 3,3, [[1,e5,0],[e5.conjugate(),2,0],[0,0,1]]) - sage: G = GU(3, UCF) - sage: Gm = GU(3, UCF, invariant_form=m) - sage: G == Gm + sage: UCF = UniversalCyclotomicField(); e5=UCF.gen(5) # optional - sage.rings.number_field + sage: m = matrix(UCF, 3,3, [[1,e5,0],[e5.conjugate(),2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: G = GU(3, UCF) # optional - sage.rings.number_field + sage: Gm = GU(3, UCF, invariant_form=m) # optional - sage.rings.number_field + sage: G == Gm # optional - sage.rings.number_field False - sage: G.invariant_form() + sage: G.invariant_form() # optional - sage.rings.number_field [1 0 0] [0 1 0] [0 0 1] - sage: Gm.invariant_form() + sage: Gm.invariant_form() # optional - sage.rings.number_field [ 1 E(5) 0] [E(5)^4 2 0] [ 0 0 1] - sage: pm = Permutation((1,2,3)).to_matrix() - sage: g = G(pm); g in G; g + sage: pm = Permutation((1,2,3)).to_matrix() # optional - sage.combinat sage.rings.number_field + sage: g = G(pm); g in G; g # optional - sage.combinat sage.rings.number_field True [0 0 1] [1 0 0] [0 1 0] - sage: Gm(pm) + sage: Gm(pm) # optional - sage.combinat sage.rings.number_field Traceback (most recent call last): ... TypeError: matrix must be unitary with respect to the hermitian form @@ -239,7 +239,7 @@ def GU(n, R, var='a', invariant_form=None): [E(5)^4 2 0] [ 0 0 1] - sage: GU(3,3, invariant_form=[[1,0,0],[0,2,0],[0,0,1]]) + sage: GU(3,3, invariant_form=[[1,0,0],[0,2,0],[0,0,1]]) # optional - sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -251,8 +251,8 @@ def GU(n, R, var='a', invariant_form=None): TESTS:: - sage: TestSuite(G).run() - sage: groups.matrix.GU(2, 3) + sage: TestSuite(G).run() # optional - sage.rings.number_field + sage: groups.matrix.GU(2, 3) # optional - sage.groups sage.libs.pari General Unitary Group of degree 2 over Finite Field in a of size 3^2 """ return _UG(n, R, False, var=var, invariant_form=invariant_form) @@ -302,35 +302,35 @@ def SU(n, R, var='a', invariant_form=None): EXAMPLES:: - sage: SU(3,5) + sage: SU(3,5) # optional - sage.libs.pari Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: SU(3, GF(5)) + sage: SU(3, GF(5)) # optional - sage.libs.pari Special Unitary Group of degree 3 over Finite Field in a of size 5^2 sage: SU(3,QQ) Special Unitary Group of degree 3 over Rational Field Using the ``invariant_form`` option:: - sage: CF3 = CyclotomicField(3); e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) - sage: G = SU(3, CF3) - sage: Gm = SU(3, CF3, invariant_form=m) - sage: G == Gm + sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: G = SU(3, CF3) # optional - sage.rings.number_field + sage: Gm = SU(3, CF3, invariant_form=m) # optional - sage.rings.number_field + sage: G == Gm # optional - sage.rings.number_field False - sage: G.invariant_form() + sage: G.invariant_form() # optional - sage.rings.number_field [1 0 0] [0 1 0] [0 0 1] - sage: Gm.invariant_form() + sage: Gm.invariant_form() # optional - sage.rings.number_field [ 1 zeta3 0] [-zeta3 - 1 2 0] [ 0 0 1] - sage: pm = Permutation((1,2,3)).to_matrix() - sage: G(pm) + sage: pm = Permutation((1,2,3)).to_matrix() # optional - sage.combinat sage.rings.number_field + sage: G(pm) # optional - sage.combinat sage.rings.number_field [0 0 1] [1 0 0] [0 1 0] - sage: Gm(pm) + sage: Gm(pm) # optional - sage.combinat sage.rings.number_field Traceback (most recent call last): ... TypeError: matrix must be unitary with respect to the hermitian form @@ -338,15 +338,15 @@ def SU(n, R, var='a', invariant_form=None): [-zeta3 - 1 2 0] [ 0 0 1] - sage: SU(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) + sage: SU(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) # optional - sage.libs.pari Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP TESTS:: - sage: TestSuite(Gm).run() - sage: groups.matrix.SU(2, 3) + sage: TestSuite(Gm).run() # optional - sage.rings.number_field + sage: groups.matrix.SU(2, 3) # optional - sage.libs.pari Special Unitary Group of degree 2 over Finite Field in a of size 3^2 """ return _UG(n, R, True, var=var, invariant_form=invariant_form) @@ -363,20 +363,20 @@ class UnitaryMatrixGroup_generic(NamedMatrixGroup_generic): EXAMPLES:: - sage: G = GU(3, GF(7)); G + sage: G = GU(3, GF(7)); G # optional - sage.libs.pari General Unitary Group of degree 3 over Finite Field in a of size 7^2 - sage: latex(G) + sage: latex(G) # optional - sage.libs.pari \text{GU}_{3}(\Bold{F}_{7^{2}}) - sage: G = SU(3, GF(5)); G + sage: G = SU(3, GF(5)); G # optional - sage.libs.pari Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: latex(G) + sage: latex(G) # optional - sage.libs.pari \text{SU}_{3}(\Bold{F}_{5^{2}}) - sage: CF3 = CyclotomicField(3); e3 = CF3.gen() - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) - sage: G = SU(3, CF3, invariant_form=m) - sage: latex(G) + sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: G = SU(3, CF3, invariant_form=m) # optional - sage.rings.number_field + sage: latex(G) # optional - sage.rings.number_field \text{SU}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to positive definite hermitian form }\left(\begin{array}{rrr} 1 & \zeta_{3} & 0 \\ -\zeta_{3} - 1 & 2 & 0 \\ @@ -421,10 +421,10 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = GU(2, GF(5)) - sage: G._check_matrix(G.an_element().matrix()) - sage: G = SU(2, GF(5)) - sage: G._check_matrix(G.an_element().matrix()) + sage: G = GU(2, GF(5)) # optional - sage.libs.pari + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari + sage: G = SU(2, GF(5)) # optional - sage.libs.pari + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari """ if self._special and x.determinant() != 1: raise TypeError('matrix must have determinant one') From 12ad68ae66bd6e579e774cbff8f4b5df0881e381 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 21:09:15 -0700 Subject: [PATCH 09/18] src/sage/matrix/matrix_space.py: Use try...except for import/isinstance of is_MatrixGroup, is_ArithmeticSubgroup --- src/sage/matrix/matrix_space.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 3a48b7bccbe..007816400af 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -1230,12 +1230,24 @@ def _coerce_map_from_(self, S): pass else: MS = meth_matrix_space() - from sage.groups.matrix_gps.matrix_group import is_MatrixGroup - from sage.modular.arithgroup.arithgroup_generic import is_ArithmeticSubgroup - if is_MatrixGroup(S) or is_ArithmeticSubgroup(S): - return self.has_coerce_map_from(MS) + + try: + from sage.groups.matrix_gps.matrix_group import is_MatrixGroup + except ImportError: + pass else: - return False + if is_MatrixGroup(S): + return self.has_coerce_map_from(MS) + + try: + from sage.modular.arithgroup.arithgroup_generic import is_ArithmeticSubgroup + except ImportError: + pass + else: + if is_ArithmeticSubgroup(S): + return self.has_coerce_map_from(MS) + + return False # The parent is not matrix-like: coerce via base ring return (self.nrows() == self.ncols()) and self._coerce_map_via([B], S) From fb55f02ac912413bf022a38ec0b7f8dee8d5ecf9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Mar 2023 21:10:21 -0700 Subject: [PATCH 10/18] sage.groups.matrix_gps: When ..._gap classes cannot be imported, fall back to _generic --- .../groups/matrix_gps/finitely_generated.py | 20 ++++++++----- src/sage/groups/matrix_gps/linear.py | 30 ++++++++++++------- src/sage/groups/matrix_gps/orthogonal.py | 13 ++++---- src/sage/groups/matrix_gps/symplectic.py | 13 +++++--- src/sage/groups/matrix_gps/unitary.py | 16 ++++++---- 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index 1a68f05cff6..8685927a2dd 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -64,7 +64,6 @@ from sage.groups.matrix_gps.group_element import is_MatrixGroupElement from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic -from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap from sage.matrix.constructor import matrix from sage.matrix.matrix_space import is_MatrixSpace from sage.misc.cachefunc import cached_method @@ -284,18 +283,23 @@ def MatrixGroup(*gens, **kwds): MS = gens.universe() base_ring = MS.base_ring() degree = ZZ(MS.ncols()) # == MS.nrows() - from sage.libs.gap.libgap import libgap category = kwds.get('category', None) try: + from sage.libs.gap.libgap import libgap from .finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap + except ImportError: + pass + else: + try: + gap_gens = [libgap(matrix_gen) for matrix_gen in gens] + gap_group = libgap.Group(gap_gens) + return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group, + category=category) + except (TypeError, ValueError): + pass - gap_gens = [libgap(matrix_gen) for matrix_gen in gens] - gap_group = libgap.Group(gap_gens) - return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group, + return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens, category=category) - except (TypeError, ValueError): - return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens, - category=category) ################################################################### # diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index c580596a1f6..6d8df540e85 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -164,13 +164,18 @@ def GL(n, R, var='a'): ltx = 'GL({0}, {1})'.format(degree, latex(ring)) try: from .linear_gap import LinearMatrixGroup_gap + except ImportError: + pass + else: + try: + cmd = 'GL({0}, {1})'.format(degree, ring._gap_init_()) + return LinearMatrixGroup_gap(degree, ring, False, name, ltx, cmd, + category=cat) + except ValueError: + pass - cmd = 'GL({0}, {1})'.format(degree, ring._gap_init_()) - return LinearMatrixGroup_gap(degree, ring, False, name, ltx, cmd, + return LinearMatrixGroup_generic(degree, ring, False, name, ltx, category=cat) - except ValueError: - return LinearMatrixGroup_generic(degree, ring, False, name, ltx, - category=cat) @@ -251,13 +256,18 @@ def SL(n, R, var='a'): ltx = 'SL({0}, {1})'.format(degree, latex(ring)) try: from .linear_gap import LinearMatrixGroup_gap + except ImportError: + pass + else: + try: + cmd = 'SL({0}, {1})'.format(degree, ring._gap_init_()) + return LinearMatrixGroup_gap(degree, ring, True, name, ltx, cmd, + category=cat) + except ValueError: + pass - cmd = 'SL({0}, {1})'.format(degree, ring._gap_init_()) - return LinearMatrixGroup_gap(degree, ring, True, name, ltx, cmd, + return LinearMatrixGroup_generic(degree, ring, True, name, ltx, category=cat) - except ValueError: - return LinearMatrixGroup_generic(degree, ring, True, name, ltx, - category=cat) diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 8ab908095b0..52586ef12d6 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -203,12 +203,15 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): '+' if e == 1 else '-') if isinstance(ring, FiniteField): - from .orthogonal_gap import OrthogonalMatrixGroup_gap + try: + from .orthogonal_gap import OrthogonalMatrixGroup_gap + except ImportError: + pass + else: + cmd = '{0}O({1}, {2}, {3})'.format(ltx_prefix, e, degree, ring.order()) + return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd) - cmd = '{0}O({1}, {2}, {3})'.format(ltx_prefix, e, degree, ring.order()) - return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd) - else: - return OrthogonalMatrixGroup_generic(degree, ring, False, name, ltx, invariant_form=invariant_form) + return OrthogonalMatrixGroup_generic(degree, ring, False, name, ltx, invariant_form=invariant_form) diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index 2babbcd0c6f..464905ad1e4 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -161,11 +161,16 @@ def Sp(n, R, var='a', invariant_form=None): try: from .symplectic_gap import SymplecticMatrixGroup_gap + except ImportError: + pass + else: + try: + cmd = 'Sp({0}, {1})'.format(degree, ring._gap_init_()) + return SymplecticMatrixGroup_gap(degree, ring, True, name, ltx, cmd) + except ValueError: + pass - cmd = 'Sp({0}, {1})'.format(degree, ring._gap_init_()) - return SymplecticMatrixGroup_gap(degree, ring, True, name, ltx, cmd) - except ValueError: - return SymplecticMatrixGroup_generic(degree, ring, True, name, ltx, invariant_form=invariant_form) + return SymplecticMatrixGroup_generic(degree, ring, True, name, ltx, invariant_form=invariant_form) diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index db54b803064..690ab96e023 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -134,12 +134,16 @@ def _UG(n, R, special, var='a', invariant_form=None): ltx = r'\text{{{0}U}}_{{{1}}}({2})'.format(latex_prefix, degree, latex(ring)) if isinstance(ring, FiniteField): - from .unitary_gap import UnitaryMatrixGroup_gap - - cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q) - return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd) - else: - return UnitaryMatrixGroup_generic(degree, ring, special, name, ltx, invariant_form=invariant_form) + try: + from .unitary_gap import UnitaryMatrixGroup_gap + except ImportError: + pass + else: + cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q) + return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd) + + return UnitaryMatrixGroup_generic(degree, ring, special, name, ltx, + invariant_form=invariant_form) From 97b54805e12ea13bc8d05cbe091ea3a4b9cf5f56 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 19 Mar 2023 11:16:39 -0700 Subject: [PATCH 11/18] src/doc/en/reference/groups/index.rst: Fix up --- src/doc/en/reference/groups/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/groups/index.rst b/src/doc/en/reference/groups/index.rst index 8f214fb0ae2..46764ef45e1 100644 --- a/src/doc/en/reference/groups/index.rst +++ b/src/doc/en/reference/groups/index.rst @@ -86,6 +86,7 @@ Matrix and Affine Groups sage/groups/matrix_gps/orthogonal sage/groups/matrix_gps/orthogonal_gap sage/groups/matrix_gps/isometries + sage/groups/matrix_gps/symplectic sage/groups/matrix_gps/symplectic_gap sage/groups/matrix_gps/unitary sage/groups/matrix_gps/unitary_gap From c362fb7c293b7e5e2230e0571408a28323bc67f7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 19 Mar 2023 15:06:49 -0700 Subject: [PATCH 12/18] src/sage/groups/matrix_gps/finitely_generated_gap.py: Mark a doctest random --- src/sage/groups/matrix_gps/finitely_generated_gap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py index 726d099fd96..53609adebbc 100644 --- a/src/sage/groups/matrix_gps/finitely_generated_gap.py +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -106,7 +106,7 @@ def as_permutation_group(self, algorithm=None, seed=None): 144 sage: Psmaller.cardinality() 21499084800 - sage: Psmaller.degree() + sage: Psmaller.degree() # random 80 .. NOTE:: From 5dccde47117f0ece5d934c54874db7fcd4dd6d38 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 1 Apr 2023 11:27:18 -0700 Subject: [PATCH 13/18] sage.groups.{affine_gps,matrix_gps}: Use '# optional - sage.rings.finite_rings' when GF is involved, add '# optional - sage.symbolic' --- src/sage/groups/affine_gps/affine_group.py | 76 ++++----- src/sage/groups/affine_gps/euclidean_group.py | 24 +-- src/sage/groups/affine_gps/group_element.py | 68 ++++---- src/sage/groups/group.pyx | 2 +- .../groups/matrix_gps/finitely_generated.py | 148 +++++++++--------- src/sage/groups/matrix_gps/group_element.pyx | 35 ++--- src/sage/groups/matrix_gps/linear.py | 79 +++++----- src/sage/groups/matrix_gps/matrix_group.py | 80 +++++----- src/sage/groups/matrix_gps/named_group.py | 28 ++-- src/sage/groups/matrix_gps/orthogonal.py | 121 +++++++------- src/sage/groups/matrix_gps/symplectic.py | 42 ++--- src/sage/groups/matrix_gps/unitary.py | 66 ++++---- 12 files changed, 386 insertions(+), 383 deletions(-) diff --git a/src/sage/groups/affine_gps/affine_group.py b/src/sage/groups/affine_gps/affine_group.py index 7b0576e8649..4d3cfd46cf7 100644 --- a/src/sage/groups/affine_gps/affine_group.py +++ b/src/sage/groups/affine_gps/affine_group.py @@ -129,11 +129,11 @@ class AffineGroup(UniqueRepresentation, Group): Some additional ways to create affine groups:: - sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.libs.pari + sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.rings.finite_rings Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: G = AffineGroup(A); G # optional - sage.libs.pari + sage: G = AffineGroup(A); G # optional - sage.rings.finite_rings Affine Group of degree 2 over Finite Field in a of size 2^2 - sage: G is AffineGroup(2,4) # shorthand # optional - sage.libs.pari + sage: G is AffineGroup(2,4) # shorthand # optional - sage.rings.finite_rings True sage: V = ZZ^3; V @@ -152,10 +152,10 @@ def __classcall__(cls, *args, **kwds): EXAMPLES:: - sage: A = AffineSpace(2, GF(4,'a')) # optional - sage.libs.pari - sage: AffineGroup(A) is AffineGroup(2,4) # optional - sage.libs.pari + sage: A = AffineSpace(2, GF(4,'a')) # optional - sage.rings.finite_rings + sage: AffineGroup(A) is AffineGroup(2,4) # optional - sage.rings.finite_rings True - sage: AffineGroup(A) is AffineGroup(2, GF(4,'a')) # optional - sage.libs.pari + sage: AffineGroup(A) is AffineGroup(2, GF(4,'a')) # optional - sage.rings.finite_rings True sage: A = AffineGroup(2, QQ) sage: V = QQ^2 @@ -202,10 +202,10 @@ def __init__(self, degree, ring): TESTS:: - sage: G = AffineGroup(2, GF(5)); G # optional - sage.libs.pari + sage: G = AffineGroup(2, GF(5)); G # optional - sage.rings.finite_rings Affine Group of degree 2 over Finite Field of size 5 - sage: TestSuite(G).run() # optional - sage.libs.pari - sage: G.category() # optional - sage.libs.pari + sage: TestSuite(G).run() # optional - sage.rings.finite_rings + sage: G.category() # optional - sage.rings.finite_rings Category of finite groups sage: Aff6 = AffineGroup(6, QQ) @@ -264,8 +264,8 @@ def _latex_(self): EXAMPLES:: - sage: G = AffineGroup(6, GF(5)) # optional - sage.libs.pari - sage: latex(G) # optional - sage.libs.pari + sage: G = AffineGroup(6, GF(5)) # optional - sage.rings.finite_rings + sage: latex(G) # optional - sage.rings.finite_rings \mathrm{Aff}_{6}(\Bold{F}_{5}) """ return "\\mathrm{Aff}_{%s}(%s)" % (self.degree(), @@ -277,7 +277,7 @@ def _repr_(self): EXAMPLES:: - sage: AffineGroup(6, GF(5)) # optional - sage.libs.pari + sage: AffineGroup(6, GF(5)) # optional - sage.rings.finite_rings Affine Group of degree 6 over Finite Field of size 5 """ return "Affine Group of degree %s over %s" % (self.degree(), @@ -289,7 +289,7 @@ def cardinality(self): EXAMPLES:: - sage: AffineGroup(6, GF(5)).cardinality() # optional - sage.libs.pari + sage: AffineGroup(6, GF(5)).cardinality() # optional - sage.rings.finite_rings 172882428468750000000000000000 sage: AffineGroup(6, ZZ).cardinality() +Infinity @@ -307,11 +307,11 @@ def degree(self): EXAMPLES:: - sage: G = AffineGroup(6, GF(5)) # optional - sage.libs.pari - sage: g = G.an_element() # optional - sage.libs.pari - sage: G.degree() # optional - sage.libs.pari + sage: G = AffineGroup(6, GF(5)) # optional - sage.rings.finite_rings + sage: g = G.an_element() # optional - sage.rings.finite_rings + sage: G.degree() # optional - sage.rings.finite_rings 6 - sage: G.degree() == g.A().nrows() == g.A().ncols() == g.b().degree() # optional - sage.libs.pari + sage: G.degree() == g.A().nrows() == g.A().ncols() == g.b().degree() # optional - sage.rings.finite_rings True """ return self._degree @@ -329,8 +329,8 @@ def matrix_space(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari - sage: G.matrix_space() # optional - sage.libs.pari + sage: G = AffineGroup(3, GF(5)) # optional - sage.rings.finite_rings + sage: G.matrix_space() # optional - sage.rings.finite_rings Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 5 """ d = self.degree() @@ -343,8 +343,8 @@ def vector_space(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari - sage: G.vector_space() # optional - sage.libs.pari + sage: G = AffineGroup(3, GF(5)) # optional - sage.rings.finite_rings + sage: G.vector_space() # optional - sage.rings.finite_rings Vector space of dimension 3 over Finite Field of size 5 """ return FreeModule(self.base_ring(), self.degree()) @@ -373,8 +373,8 @@ def linear_space(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari - sage: G.linear_space() # optional - sage.libs.pari + sage: G = AffineGroup(3, GF(5)) # optional - sage.rings.finite_rings + sage: G.linear_space() # optional - sage.rings.finite_rings Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 5 """ dp = self.degree() + 1 @@ -394,8 +394,8 @@ def linear(self, A): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari - sage: G.linear([1,2,3,4,5,6,7,8,0]) # optional - sage.libs.pari + sage: G = AffineGroup(3, GF(5)) # optional - sage.rings.finite_rings + sage: G.linear([1,2,3,4,5,6,7,8,0]) # optional - sage.rings.finite_rings [1 2 3] [0] x |-> [4 0 1] x + [0] [2 3 0] [0] @@ -417,8 +417,8 @@ def translation(self, b): EXAMPLES:: - sage: G = AffineGroup(3, GF(5)) # optional - sage.libs.pari - sage: G.translation([1,4,8]) # optional - sage.libs.pari + sage: G = AffineGroup(3, GF(5)) # optional - sage.rings.finite_rings + sage: G.translation([1,4,8]) # optional - sage.rings.finite_rings [1 0 0] [1] x |-> [0 1 0] x + [4] [0 0 1] [3] @@ -446,12 +446,12 @@ def reflection(self, v): EXAMPLES:: - sage: G = AffineGroup(3, QQ) # optional - sage.libs.pari - sage: G.reflection([1,0,0]) # optional - sage.libs.pari + sage: G = AffineGroup(3, QQ) # optional - sage.rings.finite_rings + sage: G.reflection([1,0,0]) # optional - sage.rings.finite_rings [-1 0 0] [0] x |-> [ 0 1 0] x + [0] [ 0 0 1] [0] - sage: G.reflection([3,4,-5]) # optional - sage.libs.pari + sage: G.reflection([3,4,-5]) # optional - sage.rings.finite_rings [ 16/25 -12/25 3/5] [0] x |-> [-12/25 9/25 4/5] x + [0] [ 3/5 4/5 0] [0] @@ -470,13 +470,13 @@ def random_element(self): EXAMPLES:: - sage: G = AffineGroup(4, GF(3)) # optional - sage.libs.pari - sage: G.random_element() # random # optional - sage.libs.pari + sage: G = AffineGroup(4, GF(3)) # optional - sage.rings.finite_rings + sage: G.random_element() # random # optional - sage.rings.finite_rings [2 0 1 2] [1] [2 1 1 2] [2] x |-> [1 0 2 2] x + [2] [1 1 1 1] [2] - sage: G.random_element() in G # optional - sage.libs.pari + sage: G.random_element() in G # optional - sage.rings.finite_rings True """ A = self._GL.random_element() @@ -490,8 +490,8 @@ def _an_element_(self): TESTS:: - sage: G = AffineGroup(4,5) # optional - sage.libs.pari - sage: G.an_element() in G # optional - sage.libs.pari + sage: G = AffineGroup(4,5) # optional - sage.rings.finite_rings + sage: G.an_element() in G # optional - sage.rings.finite_rings True """ A = self._GL.an_element() @@ -504,8 +504,8 @@ def some_elements(self): EXAMPLES:: - sage: G = AffineGroup(4,5) # optional - sage.libs.pari - sage: G.some_elements() # optional - sage.libs.pari + sage: G = AffineGroup(4,5) # optional - sage.rings.finite_rings + sage: G.some_elements() # optional - sage.rings.finite_rings [ [2 0 0 0] [1] [0 1 0 0] [0] x |-> [0 0 1 0] x + [0] @@ -518,7 +518,7 @@ def some_elements(self): [0 1 0 0] [...] x |-> [0 0 1 0] x + [...] [0 0 0 1] [...]] - sage: all(v.parent() is G for v in G.some_elements()) # optional - sage.libs.pari + sage: all(v.parent() is G for v in G.some_elements()) # optional - sage.rings.finite_rings True sage: G = AffineGroup(2,QQ) diff --git a/src/sage/groups/affine_gps/euclidean_group.py b/src/sage/groups/affine_gps/euclidean_group.py index 3278d10a1cb..4dee50f329b 100644 --- a/src/sage/groups/affine_gps/euclidean_group.py +++ b/src/sage/groups/affine_gps/euclidean_group.py @@ -121,11 +121,11 @@ class EuclideanGroup(AffineGroup): Some additional ways to create Euclidean groups:: - sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.libs.pari + sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.rings.finite_rings Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: G = EuclideanGroup(A); G # optional - sage.libs.pari + sage: G = EuclideanGroup(A); G # optional - sage.rings.finite_rings Euclidean Group of degree 2 over Finite Field in a of size 2^2 - sage: G is EuclideanGroup(2,4) # shorthand # optional - sage.libs.pari + sage: G is EuclideanGroup(2,4) # shorthand # optional - sage.rings.finite_rings True sage: V = ZZ^3; V @@ -144,9 +144,9 @@ class EuclideanGroup(AffineGroup): sage: V = QQ^6 sage: E6 is EuclideanGroup(V) True - sage: G = EuclideanGroup(2, GF(5)); G # optional - sage.libs.pari + sage: G = EuclideanGroup(2, GF(5)); G # optional - sage.rings.finite_rings Euclidean Group of degree 2 over Finite Field of size 5 - sage: TestSuite(G).run() # optional - sage.libs.pari + sage: TestSuite(G).run() # optional - sage.rings.finite_rings REFERENCES: @@ -195,8 +195,8 @@ def _latex_(self): r""" EXAMPLES:: - sage: G = EuclideanGroup(6, GF(5)) # optional - sage.libs.pari - sage: latex(G) # optional - sage.libs.pari + sage: G = EuclideanGroup(6, GF(5)) # optional - sage.rings.finite_rings + sage: latex(G) # optional - sage.rings.finite_rings \mathrm{E}_{6}(\Bold{F}_{5}) """ return "\\mathrm{E}_{%s}(%s)"%(self.degree(), self.base_ring()._latex_()) @@ -207,7 +207,7 @@ def _repr_(self): EXAMPLES:: - sage: EuclideanGroup(6, GF(5)) # optional - sage.libs.pari + sage: EuclideanGroup(6, GF(5)) # optional - sage.rings.finite_rings Euclidean Group of degree 6 over Finite Field of size 5 """ return "Euclidean Group of degree %s over %s"%(self.degree(), self.base_ring()) @@ -218,18 +218,18 @@ def random_element(self): EXAMPLES:: - sage: G = EuclideanGroup(4, GF(3)) # optional - sage.libs.pari - sage: G.random_element() # random # optional - sage.libs.pari + sage: G = EuclideanGroup(4, GF(3)) # optional - sage.rings.finite_rings + sage: G.random_element() # random # optional - sage.rings.finite_rings [2 1 2 1] [1] [1 2 2 1] [0] x |-> [2 2 2 2] x + [1] [1 1 2 2] [2] - sage: G.random_element() in G # optional - sage.libs.pari + sage: G.random_element() in G # optional - sage.rings.finite_rings True TESTS:: - sage: G.random_element().A().is_unitary() # optional - sage.libs.pari + sage: G.random_element().A().is_unitary() # optional - sage.rings.finite_rings True """ while True: diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index a04fee79262..590d4bf400d 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -80,13 +80,13 @@ class AffineGroupElement(MultiplicativeGroupElement): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari - sage: g = G.random_element() # optional - sage.libs.pari - sage: type(g) # optional - sage.libs.pari + sage: G = AffineGroup(2, GF(3)) # optional - sage.rings.finite_rings + sage: g = G.random_element() # optional - sage.rings.finite_rings + sage: type(g) # optional - sage.rings.finite_rings - sage: G(g.matrix()) == g # optional - sage.libs.pari + sage: G(g.matrix()) == g # optional - sage.rings.finite_rings True - sage: G(2) # optional - sage.libs.pari + sage: G(2) # optional - sage.rings.finite_rings [2 0] [0] x |-> [0 2] x + [0] @@ -110,9 +110,9 @@ def __init__(self, parent, A, b=0, convert=True, check=True): TESTS:: - sage: G = AffineGroup(4, GF(5)) # optional - sage.libs.pari - sage: g = G.random_element() # optional - sage.libs.pari - sage: TestSuite(g).run() # optional - sage.libs.pari + sage: G = AffineGroup(4, GF(5)) # optional - sage.rings.finite_rings + sage: g = G.random_element() # optional - sage.rings.finite_rings + sage: TestSuite(g).run() # optional - sage.rings.finite_rings """ try: A = A.matrix() @@ -187,29 +187,29 @@ def matrix(self): EXAMPLES:: - sage: G = AffineGroup(3, GF(7)) # optional - sage.libs.pari - sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) # optional - sage.libs.pari - sage: g # optional - sage.libs.pari + sage: G = AffineGroup(3, GF(7)) # optional - sage.rings.finite_rings + sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) # optional - sage.rings.finite_rings + sage: g # optional - sage.rings.finite_rings [1 2 3] [3] x |-> [4 5 6] x + [4] [0 1 0] [5] - sage: g.matrix() # optional - sage.libs.pari + sage: g.matrix() # optional - sage.rings.finite_rings [1 2 3|3] [4 5 6|4] [0 1 0|5] [-----+-] [0 0 0|1] - sage: parent(g.matrix()) # optional - sage.libs.pari + sage: parent(g.matrix()) # optional - sage.rings.finite_rings Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 7 - sage: g.matrix() == matrix(g) # optional - sage.libs.pari + sage: g.matrix() == matrix(g) # optional - sage.rings.finite_rings True Composition of affine group elements equals multiplication of the matrices:: - sage: g1 = G.random_element() # optional - sage.libs.pari - sage: g2 = G.random_element() # optional - sage.libs.pari - sage: g1.matrix() * g2.matrix() == (g1*g2).matrix() # optional - sage.libs.pari + sage: g1 = G.random_element() # optional - sage.rings.finite_rings + sage: g2 = G.random_element() # optional - sage.rings.finite_rings + sage: g1.matrix() * g2.matrix() == (g1*g2).matrix() # optional - sage.rings.finite_rings True """ A = self._A @@ -338,13 +338,13 @@ def _mul_(self, other): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari - sage: g = G([1,1, 0,1], [0,1]) # optional - sage.libs.pari - sage: h = G([1,1, 0,1], [1,2]) # optional - sage.libs.pari - sage: g*h # optional - sage.libs.pari + sage: G = AffineGroup(2, GF(3)) # optional - sage.rings.finite_rings + sage: g = G([1,1, 0,1], [0,1]) # optional - sage.rings.finite_rings + sage: h = G([1,1, 0,1], [1,2]) # optional - sage.rings.finite_rings + sage: g*h # optional - sage.rings.finite_rings [1 2] [0] x |-> [0 1] x + [0] - sage: g.matrix() * h.matrix() == (g*h).matrix() # optional - sage.libs.pari + sage: g.matrix() * h.matrix() == (g*h).matrix() # optional - sage.rings.finite_rings True """ parent = self.parent() @@ -440,16 +440,16 @@ def _act_on_(self, x, self_on_left): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari - sage: g = G([1,2,3,4], [5,6]) # optional - sage.libs.pari - sage: g # optional - sage.libs.pari + sage: G = AffineGroup(2, GF(3)) # optional - sage.rings.finite_rings + sage: g = G([1,2,3,4], [5,6]) # optional - sage.rings.finite_rings + sage: g # optional - sage.rings.finite_rings [1 2] [2] x |-> [0 1] x + [0] - sage: v = vector(GF(3), [1,-1]); v # optional - sage.libs.pari + sage: v = vector(GF(3), [1,-1]); v # optional - sage.rings.finite_rings (1, 2) - sage: g*v # optional - sage.libs.pari + sage: g*v # optional - sage.rings.finite_rings (1, 2) - sage: g*v == g.A() * v + g.b() # optional - sage.libs.pari + sage: g*v == g.A() * v + g.b() # optional - sage.rings.finite_rings True """ if self_on_left: @@ -465,18 +465,18 @@ def __invert__(self): EXAMPLES:: - sage: G = AffineGroup(2, GF(3)) # optional - sage.libs.pari - sage: g = G([1,2,3,4], [5,6]) # optional - sage.libs.pari - sage: g # optional - sage.libs.pari + sage: G = AffineGroup(2, GF(3)) # optional - sage.rings.finite_rings + sage: g = G([1,2,3,4], [5,6]) # optional - sage.rings.finite_rings + sage: g # optional - sage.rings.finite_rings [1 2] [2] x |-> [0 1] x + [0] - sage: ~g # optional - sage.libs.pari + sage: ~g # optional - sage.rings.finite_rings [1 1] [1] x |-> [0 1] x + [0] - sage: g * g.inverse() # indirect doctest # optional - sage.libs.pari + sage: g * g.inverse() # indirect doctest # optional - sage.rings.finite_rings [1 0] [0] x |-> [0 1] x + [0] - sage: g * g.inverse() == g.inverse() * g == G(1) # optional - sage.libs.pari + sage: g * g.inverse() == g.inverse() * g == G(1) # optional - sage.rings.finite_rings True """ parent = self.parent() diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index e31b39a88be..7947f0f876d 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -143,7 +143,7 @@ cdef class Group(Parent): EXAMPLES:: - sage: SL(2, 7).is_commutative() # optional - sage.libs.pari + sage: SL(2, 7).is_commutative() # optional - sage.rings.finite_rings False """ return self.is_abelian() diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index 8685927a2dd..54568c333f4 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -6,10 +6,10 @@ EXAMPLES:: - sage: F = GF(3) # optional - sage.libs.pari - sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F,2, [1,1,0,1])] # optional - sage.libs.pari - sage: G = MatrixGroup(gens) # optional - sage.libs.pari - sage: G.conjugacy_classes_representatives() # optional - sage.libs.pari + sage: F = GF(3) # optional - sage.rings.finite_rings + sage: gens = [matrix(F, 2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])] # optional - sage.rings.finite_rings + sage: G = MatrixGroup(gens) # optional - sage.rings.finite_rings + sage: G.conjugacy_classes_representatives() # optional - sage.rings.finite_rings ( [1 0] [0 2] [0 1] [2 0] [0 2] [0 1] [0 2] [0 1], [1 1], [2 1], [0 2], [1 2], [2 2], [1 0] @@ -83,9 +83,9 @@ def normalize_square_matrices(matrices): EXAMPLES:: sage: from sage.groups.matrix_gps.finitely_generated import normalize_square_matrices - sage: m1 = [[1,2],[3,4]] + sage: m1 = [[1,2], [3,4]] sage: m2 = [2, 3, 4, 5] - sage: m3 = matrix(QQ, [[1/2,1/3],[1/4,1/5]]) + sage: m3 = matrix(QQ, [[1/2,1/3], [1/4,1/5]]) sage: m4 = MatrixGroup(m3).gen(0) sage: normalize_square_matrices([m1, m2, m3, m4]) [ @@ -154,37 +154,37 @@ def QuaternionMatrixGroupGF3(): is the product of `I` and `J`. :: sage: from sage.groups.matrix_gps.finitely_generated import QuaternionMatrixGroupGF3 - sage: Q = QuaternionMatrixGroupGF3() # optional - sage.libs.pari - sage: Q.order() # optional - sage.libs.pari + sage: Q = QuaternionMatrixGroupGF3() # optional - sage.rings.finite_rings + sage: Q.order() # optional - sage.rings.finite_rings 8 - sage: aye = Q.gens()[0]; aye # optional - sage.libs.pari + sage: aye = Q.gens()[0]; aye # optional - sage.rings.finite_rings [1 1] [1 2] - sage: jay = Q.gens()[1]; jay # optional - sage.libs.pari + sage: jay = Q.gens()[1]; jay # optional - sage.rings.finite_rings [2 1] [1 1] - sage: kay = aye*jay; kay # optional - sage.libs.pari + sage: kay = aye*jay; kay # optional - sage.rings.finite_rings [0 2] [1 0] TESTS:: - sage: groups.matrix.QuaternionGF3() # optional - sage.libs.pari + sage: groups.matrix.QuaternionGF3() # optional - sage.rings.finite_rings Matrix group over Finite Field of size 3 with 2 generators ( [1 1] [2 1] [1 2], [1 1] ) - sage: Q = QuaternionMatrixGroupGF3() # optional - sage.libs.pari - sage: QP = Q.as_permutation_group() # optional - sage.libs.pari - sage: QP.is_isomorphic(QuaternionGroup()) # optional - sage.libs.pari + sage: Q = QuaternionMatrixGroupGF3() # optional - sage.rings.finite_rings + sage: QP = Q.as_permutation_group() # optional - sage.rings.finite_rings + sage: QP.is_isomorphic(QuaternionGroup()) # optional - sage.rings.finite_rings True - sage: H = DihedralGroup(4) # optional - sage.groups sage.libs.pari - sage: H.order() # optional - sage.groups sage.libs.pari + sage: H = DihedralGroup(4) # optional - sage.groups sage.rings.finite_rings + sage: H.order() # optional - sage.groups sage.rings.finite_rings 8 - sage: QP.is_abelian(), H.is_abelian() # optional - sage.groups sage.libs.pari + sage: QP.is_abelian(), H.is_abelian() # optional - sage.groups sage.rings.finite_rings (False, False) - sage: QP.is_isomorphic(H) # optional - sage.groups sage.libs.pari + sage: QP.is_isomorphic(H) # optional - sage.groups sage.rings.finite_rings False """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -209,9 +209,9 @@ def MatrixGroup(*gens, **kwds): EXAMPLES:: - sage: F = GF(5) # optional - sage.libs.pari - sage: gens = [matrix(F,2, [1,2, -1, 1]), matrix(F,2, [1,1, 0,1])] # optional - sage.libs.pari - sage: G = MatrixGroup(gens); G # optional - sage.libs.pari + sage: F = GF(5) # optional - sage.rings.finite_rings + sage: gens = [matrix(F, 2, [1,2, -1,1]), matrix(F,2, [1,1, 0,1])] # optional - sage.rings.finite_rings + sage: G = MatrixGroup(gens); G # optional - sage.rings.finite_rings Matrix group over Finite Field of size 5 with 2 generators ( [1 2] [1 1] [4 1], [0 1] @@ -223,8 +223,8 @@ def MatrixGroup(*gens, **kwds): matrices over the finite field, so creates that matrix group there:: - sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2] # optional - sage.libs.pari - sage: G = MatrixGroup(gens); G # optional - sage.libs.pari + sage: gens = [matrix(2, [1,2, -1,1]), matrix(GF(7), 2, [1,1, 0,1]), 2] # optional - sage.rings.finite_rings + sage: G = MatrixGroup(gens); G # optional - sage.rings.finite_rings Matrix group over Finite Field of size 7 with 3 generators ( [1 2] [1 1] [2 0] [6 1], [0 1], [0 2] @@ -237,12 +237,12 @@ def MatrixGroup(*gens, **kwds): ... ValueError: each generator must be an invertible matrix - sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari - sage: MatrixGroup([MS.0]) # optional - sage.libs.pari + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.rings.finite_rings + sage: MatrixGroup([MS.0]) # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: each generator must be an invertible matrix - sage: MatrixGroup([MS.0], check=False) # works formally but is mathematical nonsense # optional - sage.libs.pari + sage: MatrixGroup([MS.0], check=False) # works formally but is mathematical nonsense # optional - sage.rings.finite_rings Matrix group over Finite Field of size 5 with 1 generators ( [1 0] [0 0] @@ -312,19 +312,19 @@ class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic): """ TESTS:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) - sage: MatrixGroup(m1) == MatrixGroup(m1) + sage: m1 = matrix(SR, [[1,2], [3,4]]) # optional - sage.symbolic + sage: m2 = matrix(SR, [[1,3], [-1,0]]) # optional - sage.symbolic + sage: MatrixGroup(m1) == MatrixGroup(m1) # optional - sage.symbolic True - sage: MatrixGroup(m1) == MatrixGroup(m1.change_ring(QQ)) + sage: MatrixGroup(m1) == MatrixGroup(m1.change_ring(QQ)) # optional - sage.symbolic False - sage: MatrixGroup(m1) == MatrixGroup(m2) + sage: MatrixGroup(m1) == MatrixGroup(m2) # optional - sage.symbolic False - sage: MatrixGroup(m1, m2) == MatrixGroup(m2, m1) + sage: MatrixGroup(m1, m2) == MatrixGroup(m2, m1) # optional - sage.symbolic False - sage: m1 = matrix(QQ, [[1,2],[3,4]]) - sage: m2 = matrix(QQ, [[1,3],[-1,0]]) + sage: m1 = matrix(QQ, [[1,2], [3,4]]) + sage: m2 = matrix(QQ, [[1,3], [-1,0]]) sage: MatrixGroup(m1) == MatrixGroup(m1) True sage: MatrixGroup(m1) == MatrixGroup(m2) @@ -332,9 +332,9 @@ class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic): sage: MatrixGroup(m1, m2) == MatrixGroup(m2, m1) False - sage: G = GL(2, GF(3)) # optional - sage.libs.pari - sage: H = G.as_matrix_group() # optional - sage.libs.pari - sage: H == G, G == H # optional - sage.libs.pari + sage: G = GL(2, GF(3)) # optional - sage.rings.finite_rings + sage: H = G.as_matrix_group() # optional - sage.rings.finite_rings + sage: H == G, G == H # optional - sage.rings.finite_rings (True, True) """ @@ -344,16 +344,16 @@ def __init__(self, degree, base_ring, generator_matrices, category=None): EXAMPLES:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) - sage: G = MatrixGroup(m1, m2) - sage: TestSuite(G).run() - sage: type(G) + sage: m1 = matrix(SR, [[1,2], [3,4]]) # optional - sage.symbolic + sage: m2 = matrix(SR, [[1,3], [-1,0]]) # optional - sage.symbolic + sage: G = MatrixGroup(m1, m2) # optional - sage.symbolic + sage: TestSuite(G).run() # optional - sage.symbolic + sage: type(G) # optional - sage.symbolic sage: from sage.groups.matrix_gps.finitely_generated import \ ....: FinitelyGeneratedMatrixGroup_generic - sage: G = FinitelyGeneratedMatrixGroup_generic(2, QQ, [matrix(QQ,[[1,2],[3,4]])]) + sage: G = FinitelyGeneratedMatrixGroup_generic(2, QQ, [matrix(QQ, [[1,2], [3,4]])]) sage: G.gens() ( [1 2] @@ -370,24 +370,24 @@ def gens(self): EXAMPLES:: - sage: F = GF(3); MS = MatrixSpace(F,2,2) # optional - sage.libs.pari - sage: gens = [MS([[1,0],[0,1]]), MS([[1,1],[0,1]])] # optional - sage.libs.pari - sage: G = MatrixGroup(gens) # optional - sage.libs.pari - sage: gens[0] in G # optional - sage.libs.pari + sage: F = GF(3); MS = MatrixSpace(F, 2, 2) # optional - sage.rings.finite_rings + sage: gens = [MS([[1,0], [0,1]]), MS([[1,1], [0,1]])] # optional - sage.rings.finite_rings + sage: G = MatrixGroup(gens) # optional - sage.rings.finite_rings + sage: gens[0] in G # optional - sage.rings.finite_rings True - sage: gens = G.gens() # optional - sage.libs.pari - sage: gens[0] in G # optional - sage.libs.pari + sage: gens = G.gens() # optional - sage.rings.finite_rings + sage: gens[0] in G # optional - sage.rings.finite_rings True - sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])] # optional - sage.libs.pari + sage: gens = [MS([[1,0], [0,1]]), MS([[1,1], [0,1]])] # optional - sage.rings.finite_rings - sage: F = GF(5); MS = MatrixSpace(F,2,2) # optional - sage.libs.pari - sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) # optional - sage.libs.pari - sage: G # optional - sage.libs.pari + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.rings.finite_rings + sage: G = MatrixGroup([MS(1), MS([1,2, 3,4])]) # optional - sage.rings.finite_rings + sage: G # optional - sage.rings.finite_rings Matrix group over Finite Field of size 5 with 2 generators ( [1 0] [1 2] [0 1], [3 4] ) - sage: G.gens() # optional - sage.libs.pari + sage: G.gens() # optional - sage.rings.finite_rings ( [1 0] [1 2] [0 1], [3 4] @@ -406,13 +406,13 @@ def gen(self, i): EXAMPLES:: - sage: H = GL(2, GF(3)) # optional - sage.libs.pari - sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) # optional - sage.libs.pari - sage: G = H.subgroup([h1, h2]) # optional - sage.libs.pari - sage: G.gen(0) # optional - sage.libs.pari + sage: H = GL(2, GF(3)) # optional - sage.rings.finite_rings + sage: h1, h2 = H([[1,0], [2,1]]), H([[1,1], [0,1]]) # optional - sage.rings.finite_rings + sage: G = H.subgroup([h1, h2]) # optional - sage.rings.finite_rings + sage: G.gen(0) # optional - sage.rings.finite_rings [1 0] [2 1] - sage: G.gen(0).matrix() == h1.matrix() # optional - sage.libs.pari + sage: G.gen(0).matrix() == h1.matrix() # optional - sage.rings.finite_rings True """ return self.gens()[i] @@ -427,10 +427,10 @@ def ngens(self): EXAMPLES:: - sage: H = GL(2, GF(3)) # optional - sage.libs.pari - sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]]) # optional - sage.libs.pari - sage: G = H.subgroup([h1, h2]) # optional - sage.libs.pari - sage: G.ngens() # optional - sage.libs.pari + sage: H = GL(2, GF(3)) # optional - sage.rings.finite_rings + sage: h1, h2 = H([[1,0], [2,1]]), H([[1,1], [0,1]]) # optional - sage.rings.finite_rings + sage: G = H.subgroup([h1, h2]) # optional - sage.rings.finite_rings + sage: G.ngens() # optional - sage.rings.finite_rings 2 """ return len(self._gens_matrix) @@ -441,17 +441,17 @@ def __reduce__(self): TESTS:: - sage: G = MatrixGroup([matrix(CC, [[1,2],[3,4]]), - ....: matrix(CC, [[1,3],[-1,0]])]) + sage: G = MatrixGroup([matrix(CC, [[1,2], [3,4]]), + ....: matrix(CC, [[1,3], [-1,0]])]) sage: loads(dumps(G)) == G True Check that :trac:`22128` is fixed:: - sage: R = MatrixSpace(SR, 2) - sage: G = MatrixGroup([R([[1, 1], [0, 1]])]) - sage: G.register_embedding(R) - sage: loads(dumps(G)) + sage: R = MatrixSpace(SR, 2) # optional - sage.symbolic + sage: G = MatrixGroup([R([[1, 1], [0, 1]])]) # optional - sage.symbolic + sage: G.register_embedding(R) # optional - sage.symbolic + sage: loads(dumps(G)) # optional - sage.symbolic Matrix group over Symbolic Ring with 1 generators ( [1 1] [0 1] @@ -463,10 +463,10 @@ def _test_matrix_generators(self, **options): """ EXAMPLES:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) - sage: m2 = matrix(SR, [[1,3],[-1,0]]) - sage: G = MatrixGroup(m1, m2) - sage: G._test_matrix_generators() + sage: m1 = matrix(SR, [[1,2], [3,4]]) # optional - sage.symbolic + sage: m2 = matrix(SR, [[1,3], [-1,0]]) # optional - sage.symbolic + sage: G = MatrixGroup(m1, m2) # optional - sage.symbolic + sage: G._test_matrix_generators() # optional - sage.symbolic """ tester = self._tester(**options) for g,h in zip(self.gens(), MatrixGroup(self.gens()).gens()): diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 1d3a1cdea24..67fda25d0cf 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -3,16 +3,15 @@ Matrix Group Elements EXAMPLES:: - sage: F = GF(3); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari - sage: gens = [MS([[1,0],[0,1]]), MS([[1,1],[0,1]])] # optional - sage.libs.pari - sage: G = MatrixGroup(gens); G # optional - sage.libs.pari + sage: F = GF(3); MS = MatrixSpace(F, 2, 2) # optional - sage.rings.finite_rings + sage: gens = [MS([[1,0], [0,1]]), MS([[1,1], [0,1]])] # optional - sage.rings.finite_rings + sage: G = MatrixGroup(gens); G # optional - sage.rings.finite_rings Matrix group over Finite Field of size 3 with 2 generators ( [1 0] [1 1] - [0 1], [0 1] - ) - sage: g = G([[1,1],[0,1]]) # optional - sage.libs.pari - sage: h = G([[1,2],[0,1]]) # optional - sage.libs.pari - sage: g*h # optional - sage.libs.pari + [0 1], [0 1] ) + sage: g = G([[1,1], [0,1]]) # optional - sage.rings.finite_rings + sage: h = G([[1,2], [0,1]]) # optional - sage.rings.finite_rings + sage: g*h # optional - sage.rings.finite_rings [1 0] [0 1] @@ -20,7 +19,7 @@ You cannot add two matrices, since this is not a group operation. You can coerce matrices back to the matrix space and add them there:: - sage: g + h # optional - sage.libs.pari + sage: g + h # optional - sage.rings.finite_rings Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for +: @@ -33,20 +32,20 @@ there:: [0 1], [0 1] )' - sage: g.matrix() + h.matrix() # optional - sage.libs.pari + sage: g.matrix() + h.matrix() # optional - sage.rings.finite_rings [2 0] [0 2] Similarly, you cannot multiply group elements by scalars but you can do it with the underlying matrices:: - sage: 2*g # optional - sage.libs.pari + sage: 2*g # optional - sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for *: 'Integer Ring' and 'Matrix group over Finite Field of size 3 with 2 generators ( + TypeError: unsupported operand parent(s) for *: 'Integer Ring' + and 'Matrix group over Finite Field of size 3 with 2 generators ( [1 0] [1 1] - [0 1], [0 1] - )' + [0 1], [0 1] )' AUTHORS: @@ -107,8 +106,8 @@ cpdef is_MatrixGroupElement(x): sage: is_MatrixGroupElement('helloooo') False - sage: G = GL(2,3) # optional - sage.libs.pari - sage: is_MatrixGroupElement(G.an_element()) # optional - sage.libs.pari + sage: G = GL(2,3) # optional - sage.rings.finite_rings + sage: is_MatrixGroupElement(G.an_element()) # optional - sage.rings.finite_rings True """ return isinstance(x, (MatrixGroupElement_generic, MatrixGroupElement_gap)) @@ -418,8 +417,8 @@ def _unpickle_generic_element(G, mat): EXAMPLES:: - sage: m1 = matrix(SR, [[1,2],[3,4]]) # optional - sage.symbolic - sage: m2 = matrix(SR, [[1,3],[-1,0]]) # optional - sage.symbolic + sage: m1 = matrix(SR, [[1,2], [3,4]]) # optional - sage.symbolic + sage: m2 = matrix(SR, [[1,3], [-1,0]]) # optional - sage.symbolic sage: G = MatrixGroup(m1, m2) # optional - sage.symbolic sage: m = G.an_element() # optional - sage.symbolic sage: from sage.groups.matrix_gps.group_element import _unpickle_generic_element # optional - sage.symbolic diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index 2ac702fc637..f56edc3cea0 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -3,28 +3,28 @@ EXAMPLES:: - sage: GL(4,QQ) + sage: GL(4, QQ) General Linear Group of degree 4 over Rational Field - sage: GL(1,ZZ) + sage: GL(1, ZZ) General Linear Group of degree 1 over Integer Ring - sage: GL(100,RR) + sage: GL(100, RR) General Linear Group of degree 100 over Real Field with 53 bits of precision - sage: GL(3,GF(49,'a')) + sage: GL(3, GF(49,'a')) # optional - sage.rings.finite_rings General Linear Group of degree 3 over Finite Field in a of size 7^2 sage: SL(2, ZZ) Special Linear Group of degree 2 over Integer Ring - sage: G = SL(2,GF(3)); G + sage: G = SL(2, GF(3)); G # optional - sage.rings.finite_rings Special Linear Group of degree 2 over Finite Field of size 3 - sage: G.is_finite() + sage: G.is_finite() # optional - sage.rings.finite_rings True - sage: G.conjugacy_classes_representatives() + sage: G.conjugacy_classes_representatives() # optional - sage.rings.finite_rings ( [1 0] [0 2] [0 1] [2 0] [0 2] [0 1] [0 2] [0 1], [1 1], [2 1], [0 2], [1 2], [2 2], [1 0] ) - sage: G = SL(6,GF(5)) - sage: G.gens() + sage: G = SL(6, GF(5)) # optional - sage.rings.finite_rings + sage: G.gens() # optional - sage.rings.finite_rings ( [2 0 0 0 0 0] [4 0 0 0 0 1] [0 3 0 0 0 0] [4 0 0 0 0 0] @@ -93,14 +93,14 @@ def GL(n, R, var='a'): EXAMPLES:: - sage: G = GL(6, GF(5)) # optional - sage.libs.pari - sage: G.order() # optional - sage.libs.pari + sage: G = GL(6, GF(5)) # optional - sage.rings.finite_rings + sage: G.order() # optional - sage.rings.finite_rings 11064475422000000000000000 - sage: G.base_ring() # optional - sage.libs.pari + sage: G.base_ring() # optional - sage.rings.finite_rings Finite Field of size 5 - sage: G.category() # optional - sage.libs.pari + sage: G.category() # optional - sage.rings.finite_rings Category of finite groups - sage: TestSuite(G).run() # optional - sage.libs.pari + sage: TestSuite(G).run() # optional - sage.rings.finite_rings sage: G = GL(6, QQ) sage: G.category() @@ -109,33 +109,34 @@ def GL(n, R, var='a'): Here is the Cayley graph of (relatively small) finite General Linear Group:: - sage: g = GL(2,3) # optional - sage.libs.pari - sage: d = g.cayley_graph(); d # optional - sage.graphs sage.libs.pari + sage: g = GL(2,3) # optional - sage.rings.finite_rings + sage: d = g.cayley_graph(); d # optional - sage.graphs sage.rings.finite_rings Digraph on 48 vertices - sage: d.plot(color_by_label=True, vertex_size=0.03, vertex_labels=False) # long time # optional - sage.graphs sage.libs.pari sage.plot + sage: d.plot(color_by_label=True, vertex_size=0.03, # long time # optional - sage.graphs sage.rings.finite_rings sage.plot + ....: vertex_labels=False) Graphics object consisting of 144 graphics primitives - sage: d.plot3d(color_by_label=True) # long time # optional - sage.graphs sage.libs.pari sage.plot + sage: d.plot3d(color_by_label=True) # long time # optional - sage.graphs sage.rings.finite_rings sage.plot Graphics3d Object :: - sage: F = GF(3); MS = MatrixSpace(F,2,2) # optional - sage.libs.pari - sage: gens = [MS([[2,0],[0,1]]), MS([[2,1],[2,0]])] # optional - sage.libs.pari - sage: G = MatrixGroup(gens) # optional - sage.libs.pari - sage: G.order() # optional - sage.libs.pari + sage: F = GF(3); MS = MatrixSpace(F, 2, 2) # optional - sage.rings.finite_rings + sage: gens = [MS([[2,0], [0,1]]), MS([[2,1], [2,0]])] # optional - sage.rings.finite_rings + sage: G = MatrixGroup(gens) # optional - sage.rings.finite_rings + sage: G.order() # optional - sage.rings.finite_rings 48 - sage: G.cardinality() # optional - sage.libs.pari + sage: G.cardinality() # optional - sage.rings.finite_rings 48 - sage: H = GL(2,F) # optional - sage.libs.pari - sage: H.order() # optional - sage.libs.pari + sage: H = GL(2,F) # optional - sage.rings.finite_rings + sage: H.order() # optional - sage.rings.finite_rings 48 - sage: H == G # optional - sage.libs.pari + sage: H == G # optional - sage.rings.finite_rings True - sage: H.gens() == G.gens() # optional - sage.libs.pari + sage: H.gens() == G.gens() # optional - sage.rings.finite_rings True - sage: H.as_matrix_group() == H # optional - sage.libs.pari + sage: H.as_matrix_group() == H # optional - sage.rings.finite_rings True - sage: H.gens() # optional - sage.libs.pari + sage: H.gens() # optional - sage.rings.finite_rings ( [2 0] [2 1] [0 1], [2 0] @@ -143,11 +144,11 @@ def GL(n, R, var='a'): TESTS:: - sage: groups.matrix.GL(2, 3) # optional - sage.groups sage.libs.pari + sage: groups.matrix.GL(2, 3) # optional - sage.groups sage.rings.finite_rings General Linear Group of degree 2 over Finite Field of size 3 - sage: groups.matrix.GL(1, ZZ).category() # optional - sage.groups + sage: groups.matrix.GL(1, ZZ).category() # optional - sage.groups Category of groups - sage: groups.matrix.GL(1, QQ).category() # optional - sage.groups + sage: groups.matrix.GL(1, QQ).category() # optional - sage.groups Category of infinite groups """ degree, ring = normalize_args_vectorspace(n, R, var='a') @@ -206,15 +207,15 @@ def SL(n, R, var='a'): EXAMPLES:: - sage: SL(3, GF(2)) # optional - sage.libs.pari + sage: SL(3, GF(2)) # optional - sage.rings.finite_rings Special Linear Group of degree 3 over Finite Field of size 2 - sage: G = SL(15, GF(7)); G # optional - sage.libs.pari + sage: G = SL(15, GF(7)); G # optional - sage.rings.finite_rings Special Linear Group of degree 15 over Finite Field of size 7 - sage: G.category() # optional - sage.libs.pari + sage: G.category() # optional - sage.rings.finite_rings Category of finite groups - sage: G.order() # optional - sage.libs.pari + sage: G.order() # optional - sage.rings.finite_rings 1956712595698146962015219062429586341124018007182049478916067369638713066737882363393519966343657677430907011270206265834819092046250232049187967718149558134226774650845658791865745408000000 - sage: len(G.gens()) # optional - sage.libs.pari + sage: len(G.gens()) # optional - sage.rings.finite_rings 2 sage: G = SL(2, ZZ); G Special Linear Group of degree 2 over Integer Ring @@ -284,8 +285,8 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = SL(2, GF(5)) # optional - sage.libs.pari - sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari + sage: G = SL(2, GF(5)) # optional - sage.rings.finite_rings + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.rings.finite_rings """ if self._special: if x.determinant() != 1: diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 703c61209e1..f3728709cf8 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -3,14 +3,14 @@ Loading, saving, ... works:: - sage: G = GL(2,5); G # optional - sage.libs.pari + sage: G = GL(2,5); G # optional - sage.rings.finite_rings General Linear Group of degree 2 over Finite Field of size 5 - sage: TestSuite(G).run() # optional - sage.libs.pari + sage: TestSuite(G).run() # optional - sage.rings.finite_rings - sage: g = G.1; g # optional - sage.libs.pari + sage: g = G.1; g # optional - sage.rings.finite_rings [4 1] [4 0] - sage: TestSuite(g).run() # optional - sage.libs.pari + sage: TestSuite(g).run() # optional - sage.rings.finite_rings We test that :trac:`9437` is fixed:: @@ -69,13 +69,13 @@ def is_MatrixGroup(x): EXAMPLES:: sage: from sage.groups.matrix_gps.matrix_group import is_MatrixGroup - sage: is_MatrixGroup(MatrixSpace(QQ,3)) + sage: is_MatrixGroup(MatrixSpace(QQ, 3)) False - sage: is_MatrixGroup(Mat(QQ,3)) + sage: is_MatrixGroup(Mat(QQ, 3)) False - sage: is_MatrixGroup(GL(2,ZZ)) + sage: is_MatrixGroup(GL(2, ZZ)) True - sage: is_MatrixGroup(MatrixGroup([matrix(2,[1,1,0,1])])) + sage: is_MatrixGroup(MatrixGroup([matrix(2, [1,1,0,1])])) True """ return isinstance(x, MatrixGroup_base) @@ -99,9 +99,9 @@ class MatrixGroup_base(Group): TESTS:: - sage: G = SO(3, GF(11)); G # optional - sage.libs.pari + sage: G = SO(3, GF(11)); G # optional - sage.rings.finite_rings Special Orthogonal Group of degree 3 over Finite Field of size 11 - sage: G.category() # optional - sage.libs.pari + sage: G.category() # optional - sage.rings.finite_rings Category of finite groups """ _ambient = None # internal attribute to register the ambient group in case this instance is a subgroup @@ -129,9 +129,9 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = SU(2,GF(5)); F = G.base_ring() # this is GF(5^2,'a') # optional - sage.libs.pari - sage: G._check_matrix(identity_matrix(F,2)) # optional - sage.libs.pari - sage: G._check_matrix(matrix(F,[[1,1],[0,1]])) # optional - sage.libs.pari + sage: G = SU(2, GF(5)); F = G.base_ring() # this is GF(5^2,'a') # optional - sage.rings.finite_rings + sage: G._check_matrix(identity_matrix(F, 2)) # optional - sage.rings.finite_rings + sage: G._check_matrix(matrix(F, [[1,1], [0,1]])) # optional - sage.rings.finite_rings Traceback (most recent call last): ... TypeError: matrix must be unitary with respect to the hermitian form @@ -150,8 +150,8 @@ def as_matrix_group(self): EXAMPLES:: - sage: G = SU(4,GF(5)) # optional - sage.libs.pari - sage: G.as_matrix_group() # optional - sage.libs.pari + sage: G = SU(4, GF(5)) # optional - sage.rings.finite_rings + sage: G.as_matrix_group() # optional - sage.rings.finite_rings Matrix group over Finite Field in a of size 5^2 with 2 generators ( [ a 0 0 0] [ 1 0 4*a + 3 0] [ 0 2*a + 3 0 0] [ 1 0 0 0] @@ -159,8 +159,8 @@ def as_matrix_group(self): [ 0 0 0 3*a], [ 0 3*a + 1 0 0] ) - sage: G = GO(3,GF(5)) # optional - sage.libs.pari - sage: G.as_matrix_group() # optional - sage.libs.pari + sage: G = GO(3,GF(5)) # optional - sage.rings.finite_rings + sage: G.as_matrix_group() # optional - sage.rings.finite_rings Matrix group over Finite Field of size 5 with 2 generators ( [2 0 0] [0 1 0] [0 3 0] [1 4 4] @@ -236,8 +236,8 @@ def ambient(self): EXAMPLES:: - sage: G = GL(2,QQ) - sage: m = matrix(QQ, 2,2, [[3, 0],[~5,1]]) + sage: G = GL(2, QQ) + sage: m = matrix(QQ, 2, 2, [[3, 0], [~5,1]]) sage: S = G.subgroup([m]) sage: S.ambient() is G True @@ -257,10 +257,10 @@ def _repr_(self): EXAMPLES:: - sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari - sage: gens = [MS([[1,2],[-1,1]]), MS([[1,1],[0,1]])] # optional - sage.libs.pari - sage: G = MatrixGroup(gens) # optional - sage.libs.pari - sage: G # optional - sage.libs.pari + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.rings.finite_rings + sage: gens = [MS([[1,2], [-1,1]]), MS([[1,1], [0,1]])] # optional - sage.rings.finite_rings + sage: G = MatrixGroup(gens) # optional - sage.rings.finite_rings + sage: G # optional - sage.rings.finite_rings Matrix group over Finite Field of size 5 with 2 generators ( [1 2] [1 1] [4 1], [0 1] @@ -271,7 +271,7 @@ def _repr_(self): sage: CF3 = CyclotomicField(3) # optional - sage.rings.number_field sage: G = GL(2, CF3) # optional - sage.rings.number_field sage: e3 = CF3.gen() # optional - sage.rings.number_field - sage: m = matrix(CF3, 2,2, [[e3, 1], [0, ~e3]]) # optional - sage.rings.number_field + sage: m = matrix(CF3, 2, 2, [[e3, 1], [0, ~e3]]) # optional - sage.rings.number_field sage: S = G.subgroup([m]); S # optional - sage.rings.number_field Subgroup with 1 generators ( [ zeta3 1] @@ -317,9 +317,9 @@ def _latex_(self): r""" EXAMPLES:: - sage: MS = MatrixSpace(GF(5), 2, 2) # optional - sage.libs.pari - sage: G = MatrixGroup(MS([[1,2],[-1,1]]), MS([[1,1],[0,1]])) # optional - sage.libs.pari - sage: latex(G) # optional - sage.libs.pari + sage: MS = MatrixSpace(GF(5), 2, 2) # optional - sage.rings.finite_rings + sage: G = MatrixGroup(MS([[1,2], [-1,1]]), MS([[1,1], [0,1]])) # optional - sage.rings.finite_rings + sage: latex(G) # optional - sage.rings.finite_rings \left\langle \left(\begin{array}{rr} 1 & 2 \\ 4 & 1 @@ -422,7 +422,7 @@ def degree(self): EXAMPLES:: - sage: SU(5,5).degree() # optional - sage.libs.pari + sage: SU(5,5).degree() # optional - sage.rings.finite_rings 5 """ return self._deg @@ -437,11 +437,11 @@ def matrix_space(self): EXAMPLES:: - sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.libs.pari - sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) # optional - sage.libs.pari - sage: G.matrix_space() # optional - sage.libs.pari + sage: F = GF(5); MS = MatrixSpace(F, 2, 2) # optional - sage.rings.finite_rings + sage: G = MatrixGroup([MS(1), MS([1,2,3,4])]) # optional - sage.rings.finite_rings + sage: G.matrix_space() # optional - sage.rings.finite_rings Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5 - sage: G.matrix_space() is MS # optional - sage.libs.pari + sage: G.matrix_space() is MS # optional - sage.rings.finite_rings True """ return MatrixSpace(self.base_ring(), self.degree()) @@ -466,11 +466,11 @@ def __richcmp__(self, other, op): EXAMPLES:: - sage: G = GL(2,3) # optional - sage.libs.pari - sage: H = MatrixGroup(G.gens()) # optional - sage.libs.pari - sage: H == G # optional - sage.libs.pari + sage: G = GL(2,3) # optional - sage.rings.finite_rings + sage: H = MatrixGroup(G.gens()) # optional - sage.rings.finite_rings + sage: H == G # optional - sage.rings.finite_rings True - sage: G == H # optional - sage.libs.pari + sage: G == H # optional - sage.rings.finite_rings True sage: MS = MatrixSpace(QQ, 2, 2) @@ -482,11 +482,11 @@ def __richcmp__(self, other, op): TESTS:: - sage: G = groups.matrix.GL(4,2) # optional - sage.groups sage.libs.pari - sage: H = MatrixGroup(G.gens()) # optional - sage.groups sage.libs.pari - sage: G == H # optional - sage.groups sage.libs.pari + sage: G = groups.matrix.GL(4,2) # optional - sage.groups sage.rings.finite_rings + sage: H = MatrixGroup(G.gens()) # optional - sage.groups sage.rings.finite_rings + sage: G == H # optional - sage.groups sage.rings.finite_rings True - sage: G != H # optional - sage.groups sage.libs.pari + sage: G != H # optional - sage.groups sage.rings.finite_rings False """ if not is_MatrixGroup(other): diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index 9944b4254df..dce2e17e9d0 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -8,17 +8,17 @@ sage: SL(2, ZZ) Special Linear Group of degree 2 over Integer Ring - sage: G = SL(2, GF(3)); G # optional - sage.libs.pari + sage: G = SL(2, GF(3)); G # optional - sage.rings.finite_rings Special Linear Group of degree 2 over Finite Field of size 3 - sage: G.is_finite() # optional - sage.libs.pari + sage: G.is_finite() # optional - sage.rings.finite_rings True - sage: G.conjugacy_classes_representatives() # optional - sage.libs.pari + sage: G.conjugacy_classes_representatives() # optional - sage.rings.finite_rings ( [1 0] [0 2] [0 1] [2 0] [0 2] [0 1] [0 2] [0 1], [1 1], [2 1], [0 2], [1 2], [2 2], [1 0] ) - sage: G = SL(6, GF(5)) # optional - sage.libs.pari - sage: G.gens() # optional - sage.libs.pari + sage: G = SL(6, GF(5)) # optional - sage.rings.finite_rings + sage: G.gens() # optional - sage.rings.finite_rings ( [2 0 0 0 0 0] [4 0 0 0 0 1] [0 3 0 0 0 0] [4 0 0 0 0 0] @@ -80,12 +80,12 @@ def normalize_args_vectorspace(*args, **kwds): TESTS:: sage: from sage.groups.matrix_gps.named_group import normalize_args_vectorspace - sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.libs.pari + sage: A = AffineSpace(2, GF(4,'a')); A # optional - sage.rings.finite_rings Affine Space of dimension 2 over Finite Field in a of size 2^2 - sage: normalize_args_vectorspace(A) # optional - sage.libs.pari + sage: normalize_args_vectorspace(A) # optional - sage.rings.finite_rings (2, Finite Field in a of size 2^2) - sage: normalize_args_vectorspace(2,4) # shorthand # optional - sage.libs.pari + sage: normalize_args_vectorspace(2,4) # shorthand # optional - sage.rings.finite_rings (2, Finite Field in a of size 2^2) sage: V = ZZ^3; V @@ -285,15 +285,15 @@ def __richcmp__(self, other, op): EXAMPLES:: - sage: G = GL(2,3) # optional - sage.libs.pari - sage: G == MatrixGroup(G.gens()) # optional - sage.libs.pari + sage: G = GL(2,3) # optional - sage.rings.finite_rings + sage: G == MatrixGroup(G.gens()) # optional - sage.rings.finite_rings True - sage: G = groups.matrix.GL(4,2) # optional - sage.libs.pari - sage: H = MatrixGroup(G.gens()) # optional - sage.libs.pari - sage: G == H # optional - sage.libs.pari + sage: G = groups.matrix.GL(4,2) # optional - sage.rings.finite_rings + sage: H = MatrixGroup(G.gens()) # optional - sage.rings.finite_rings + sage: G == H # optional - sage.rings.finite_rings True - sage: G != H # optional - sage.libs.pari + sage: G != H # optional - sage.rings.finite_rings False """ return MatrixGroup_generic.__richcmp__(self, other, op) diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 741146d24da..1de6593eb7c 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -33,12 +33,13 @@ EXAMPLES:: - sage: GO(3,7) # optional - sage.libs.pari + sage: GO(3,7) # optional - sage.rings.finite_rings General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: G = SO(4, GF(7), 1); G # optional - sage.libs.pari - Special Orthogonal Group of degree 4 and form parameter 1 over Finite Field of size 7 - sage: G.random_element() # random # optional - sage.libs.pari + sage: G = SO(4, GF(7), 1); G # optional - sage.rings.finite_rings + Special Orthogonal Group of degree 4 and form parameter 1 + over Finite Field of size 7 + sage: G.random_element() # random # optional - sage.rings.finite_rings [4 3 5 2] [6 6 4 0] [0 4 6 0] @@ -46,14 +47,14 @@ TESTS:: - sage: G = GO(3, GF(5)) # optional - sage.libs.pari - sage: latex(G) # optional - sage.libs.pari + sage: G = GO(3, GF(5)) # optional - sage.rings.finite_rings + sage: latex(G) # optional - sage.rings.finite_rings \text{GO}_{3}(\Bold{F}_{5}) - sage: G = SO(3, GF(5)) # optional - sage.libs.pari - sage: latex(G) # optional - sage.libs.pari + sage: G = SO(3, GF(5)) # optional - sage.rings.finite_rings + sage: latex(G) # optional - sage.rings.finite_rings \text{SO}_{3}(\Bold{F}_{5}) - sage: G = SO(4, GF(5), 1) # optional - sage.libs.pari - sage: latex(G) # optional - sage.libs.pari + sage: G = SO(4, GF(5), 1) # optional - sage.rings.finite_rings + sage: latex(G) # optional - sage.rings.finite_rings \text{SO}_{4}(\Bold{F}_{5}, +) AUTHORS: @@ -116,13 +117,13 @@ def normalize_args_e(degree, ring, e): TESTS:: sage: from sage.groups.matrix_gps.orthogonal import normalize_args_e - sage: normalize_args_e(2, GF(3), +1) # optional - sage.libs.pari + sage: normalize_args_e(2, GF(3), +1) # optional - sage.rings.finite_rings 1 - sage: normalize_args_e(3, GF(3), 0) # optional - sage.libs.pari + sage: normalize_args_e(3, GF(3), 0) # optional - sage.rings.finite_rings 0 - sage: normalize_args_e(3, GF(3), +1) # optional - sage.libs.pari + sage: normalize_args_e(3, GF(3), +1) # optional - sage.rings.finite_rings 0 - sage: normalize_args_e(2, GF(3), 0) # optional - sage.libs.pari + sage: normalize_args_e(2, GF(3), 0) # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: must have e=-1 or e=1 for even degree @@ -149,14 +150,14 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): Check that :trac:`26028` is fixed:: - sage: GO(3,25).order() # indirect doctest # optional - sage.libs.pari + sage: GO(3,25).order() # indirect doctest # optional - sage.rings.finite_rings 31200 Check that :trac:`28054` is fixed:: - sage: G = SO(2, GF(3), -1) # optional - sage.libs.pari - sage: m = G.invariant_form() # optional - sage.libs.pari - sage: G2 = SO(2, GF(3), 1, invariant_form=m) # optional - sage.libs.pari + sage: G = SO(2, GF(3), -1) # optional - sage.rings.finite_rings + sage: m = G.invariant_form() # optional - sage.rings.finite_rings + sage: G2 = SO(2, GF(3), 1, invariant_form=m) # optional - sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -263,11 +264,11 @@ def GO(n, R, e=0, var='a', invariant_form=None): EXAMPLES:: - sage: GO( 3, GF(7)) # optional - sage.libs.pari + sage: GO(3, GF(7)) # optional - sage.rings.finite_rings General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: GO( 3, GF(7)).order() # optional - sage.libs.pari + sage: GO(3, GF(7)).order() # optional - sage.rings.finite_rings 672 - sage: GO( 3, GF(7)).gens() # optional - sage.libs.pari + sage: GO(3, GF(7)).gens() # optional - sage.rings.finite_rings ( [3 0 0] [0 1 0] [0 5 0] [1 6 6] @@ -276,9 +277,9 @@ def GO(n, R, e=0, var='a', invariant_form=None): Using the ``invariant_form`` option:: - sage: m = matrix(QQ, 3,3, [[0, 1, 0], [1, 0, 0], [0, 0, 3]]) - sage: GO3 = GO(3,QQ) - sage: GO3m = GO(3,QQ, invariant_form=m) + sage: m = matrix(QQ, 3, 3, [[0, 1, 0], [1, 0, 0], [0, 0, 3]]) + sage: GO3 = GO(3, QQ) + sage: GO3m = GO(3, QQ, invariant_form=m) sage: GO3 == GO3m False sage: GO3.invariant_form() @@ -289,13 +290,13 @@ def GO(n, R, e=0, var='a', invariant_form=None): [0 1 0] [1 0 0] [0 0 3] - sage: pm = Permutation([2,3,1]).to_matrix() # optional - sage.combinat - sage: g = GO3(pm); g in GO3; g # optional - sage.combinat + sage: pm = Permutation([2,3,1]).to_matrix() # optional - sage.combinat + sage: g = GO3(pm); g in GO3; g # optional - sage.combinat True [0 0 1] [1 0 0] [0 1 0] - sage: GO3m(pm) # optional - sage.combinat + sage: GO3m(pm) # optional - sage.combinat Traceback (most recent call last): ... TypeError: matrix must be orthogonal with respect to the symmetric form @@ -303,14 +304,14 @@ def GO(n, R, e=0, var='a', invariant_form=None): [1 0 0] [0 0 3] - sage: GO(3,3, invariant_form=[[1,0,0],[0,2,0],[0,0,1]]) + sage: GO(3,3, invariant_form=[[1,0,0], [0,2,0], [0,0,1]]) Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP - sage: 5+5 + sage: 5 + 5 10 sage: R. = ZZ[] - sage: GO(2, R, invariant_form=[[x,0],[0,1]]) + sage: GO(2, R, invariant_form=[[x,0], [0,1]]) General Orthogonal Group of degree 2 over Univariate Polynomial Ring in x over Integer Ring with respect to symmetric form [x 0] @@ -370,19 +371,19 @@ def SO(n, R, e=None, var='a', invariant_form=None): EXAMPLES:: - sage: G = SO(3,GF(5)) # optional - sage.libs.pari - sage: G # optional - sage.libs.pari + sage: G = SO(3,GF(5)) # optional - sage.rings.finite_rings + sage: G # optional - sage.rings.finite_rings Special Orthogonal Group of degree 3 over Finite Field of size 5 - sage: G = SO(3,GF(5)) # optional - sage.libs.pari - sage: G.gens() # optional - sage.libs.pari + sage: G = SO(3,GF(5)) # optional - sage.rings.finite_rings + sage: G.gens() # optional - sage.rings.finite_rings ( [2 0 0] [3 2 3] [1 4 4] [0 3 0] [0 2 0] [4 0 0] [0 0 1], [0 3 1], [2 0 4] ) - sage: G = SO(3,GF(5)) # optional - sage.libs.pari - sage: G.as_matrix_group() # optional - sage.libs.pari + sage: G = SO(3,GF(5)) # optional - sage.rings.finite_rings + sage: G.as_matrix_group() # optional - sage.rings.finite_rings Matrix group over Finite Field of size 5 with 3 generators ( [2 0 0] [3 2 3] [1 4 4] [0 3 0] [0 2 0] [4 0 0] @@ -391,27 +392,27 @@ def SO(n, R, e=None, var='a', invariant_form=None): Using the ``invariant_form`` option:: - sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) # optional - sage.rings.number_field - sage: SO3 = SO(3, CF3) # optional - sage.rings.number_field - sage: SO3m = SO(3, CF3, invariant_form=m) # optional - sage.rings.number_field - sage: SO3 == SO3m # optional - sage.rings.number_field + sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 3, 3, [[1,e3,0], [e3,2,0], [0,0,1]]) # optional - sage.rings.number_field + sage: SO3 = SO(3, CF3) # optional - sage.rings.number_field + sage: SO3m = SO(3, CF3, invariant_form=m) # optional - sage.rings.number_field + sage: SO3 == SO3m # optional - sage.rings.number_field False - sage: SO3.invariant_form() # optional - sage.rings.number_field + sage: SO3.invariant_form() # optional - sage.rings.number_field [1 0 0] [0 1 0] [0 0 1] - sage: SO3m.invariant_form() # optional - sage.rings.number_field + sage: SO3m.invariant_form() # optional - sage.rings.number_field [ 1 zeta3 0] [zeta3 2 0] [ 0 0 1] - sage: pm = Permutation([2,3,1]).to_matrix() # optional - sage.combinat - sage: g = SO3(pm); g in SO3; g # optional - sage.combinat sage.rings.number_field + sage: pm = Permutation([2,3,1]).to_matrix() # optional - sage.combinat + sage: g = SO3(pm); g in SO3; g # optional - sage.combinat sage.rings.number_field True [0 0 1] [1 0 0] [0 1 0] - sage: SO3m(pm) # optional - sage.combinat sage.rings.number_field + sage: SO3m(pm) # optional - sage.combinat sage.rings.number_field Traceback (most recent call last): ... TypeError: matrix must be orthogonal with respect to the symmetric form @@ -419,7 +420,7 @@ def SO(n, R, e=None, var='a', invariant_form=None): [zeta3 2 0] [ 0 0 1] - sage: SO(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) # optional - sage.combinat sage.rings.number_field + sage: SO(3, 5, invariant_form=[[1,0,0], [0,2,0], [0,0,3]]) # optional - sage.combinat sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -445,20 +446,20 @@ class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic): EXAMPLES:: - sage: G = GO(3, GF(7)); G # optional - sage.libs.pari + sage: G = GO(3, GF(7)); G # optional - sage.rings.finite_rings General Orthogonal Group of degree 3 over Finite Field of size 7 - sage: latex(G) # optional - sage.libs.pari + sage: latex(G) # optional - sage.rings.finite_rings \text{GO}_{3}(\Bold{F}_{7}) - sage: G = SO(3, GF(5)); G # optional - sage.libs.pari + sage: G = SO(3, GF(5)); G # optional - sage.rings.finite_rings Special Orthogonal Group of degree 3 over Finite Field of size 5 - sage: latex(G) # optional - sage.libs.pari + sage: latex(G) # optional - sage.rings.finite_rings \text{SO}_{3}(\Bold{F}_{5}) - sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) # optional - sage.rings.number_field - sage: G = SO(3, CF3, invariant_form=m) # optional - sage.rings.number_field - sage: latex(G) # optional - sage.rings.number_field + sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field + sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: G = SO(3, CF3, invariant_form=m) # optional - sage.rings.number_field + sage: latex(G) # optional - sage.rings.number_field \text{SO}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to non positive definite symmetric form }\left(\begin{array}{rrr} 1 & \zeta_{3} & 0 \\ \zeta_{3} & 2 & 0 \\ @@ -477,10 +478,10 @@ def invariant_bilinear_form(self): EXAMPLES:: - sage: GO(2,3,+1).invariant_bilinear_form() # optional - sage.libs.pari + sage: GO(2,3,+1).invariant_bilinear_form() # optional - sage.rings.finite_rings [0 1] [1 0] - sage: GO(2,3,-1).invariant_bilinear_form() # optional - sage.libs.pari + sage: GO(2,3,-1).invariant_bilinear_form() # optional - sage.rings.finite_rings [2 1] [1 1] sage: G = GO(4, QQ) @@ -489,7 +490,7 @@ def invariant_bilinear_form(self): [0 1 0 0] [0 0 1 0] [0 0 0 1] - sage: GO3m = GO(3,QQ, invariant_form=(1,0,0,0,2,0,0,0,3)) + sage: GO3m = GO(3, QQ, invariant_form=(1,0,0, 0,2,0, 0,0,3)) sage: GO3m.invariant_bilinear_form() [1 0 0] [0 2 0] @@ -522,8 +523,8 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = GO(4, GF(5), +1) # optional - sage.libs.pari - sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari + sage: G = GO(4, GF(5), +1) # optional - sage.rings.finite_rings + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.rings.finite_rings """ if self._special and x.determinant() != 1: raise TypeError('matrix must have determinant one') diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index a475ae189e6..8fda1c60962 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -3,17 +3,17 @@ EXAMPLES:: - sage: G = Sp(4, GF(7)); G # optional - sage.libs.pari + sage: G = Sp(4, GF(7)); G # optional - sage.rings.finite_rings Symplectic Group of degree 4 over Finite Field of size 7 - sage: g = prod(G.gens()); g # optional - sage.libs.pari + sage: g = prod(G.gens()); g # optional - sage.rings.finite_rings [3 0 3 0] [1 0 0 0] [0 1 0 1] [0 2 0 0] - sage: m = g.matrix() # optional - sage.libs.pari - sage: m * G.invariant_form() * m.transpose() == G.invariant_form() # optional - sage.libs.pari + sage: m = g.matrix() # optional - sage.rings.finite_rings + sage: m * G.invariant_form() * m.transpose() == G.invariant_form() # optional - sage.rings.finite_rings True - sage: G.order() # optional - sage.libs.pari + sage: G.order() # optional - sage.rings.finite_rings 276595200 AUTHORS: @@ -80,13 +80,13 @@ def Sp(n, R, var='a', invariant_form=None): EXAMPLES:: - sage: Sp(4, 5) # optional - sage.libs.pari + sage: Sp(4, 5) # optional - sage.rings.finite_rings Symplectic Group of degree 4 over Finite Field of size 5 sage: Sp(4, IntegerModRing(15)) Symplectic Group of degree 4 over Ring of integers modulo 15 - sage: Sp(3, GF(7)) # optional - sage.libs.pari + sage: Sp(3, GF(7)) # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: the degree must be even @@ -108,14 +108,14 @@ def Sp(n, R, var='a', invariant_form=None): [ 0 0 0 2] [-1 0 0 0] [ 0 -2 0 0] - sage: pm = Permutation([2,1,4,3]).to_matrix() # optional - sage.combinat - sage: g = Sp4(pm); g in Sp4; g # optional - sage.combinat + sage: pm = Permutation([2,1,4,3]).to_matrix() # optional - sage.combinat + sage: g = Sp4(pm); g in Sp4; g # optional - sage.combinat True [0 1 0 0] [1 0 0 0] [0 0 0 1] [0 0 1 0] - sage: Sp4m(pm) # optional - sage.combinat + sage: Sp4m(pm) # optional - sage.combinat Traceback (most recent call last): ... TypeError: matrix must be symplectic with respect to the alternating form @@ -124,7 +124,7 @@ def Sp(n, R, var='a', invariant_form=None): [-1 0 0 0] [ 0 -2 0 0] - sage: Sp(4,3, invariant_form=[[0,0,0,1],[0,0,1,0],[0,2,0,0], [2,0,0,0]]) # optional - sage.libs.pari + sage: Sp(4,3, invariant_form=[[0,0,0,1],[0,0,1,0],[0,2,0,0], [2,0,0,0]]) # optional - sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -133,11 +133,11 @@ def Sp(n, R, var='a', invariant_form=None): sage: TestSuite(Sp4).run() sage: TestSuite(Sp4m).run() - sage: groups.matrix.Sp(2, 3) # optional - sage.libs.pari + sage: groups.matrix.Sp(2, 3) # optional - sage.rings.finite_rings Symplectic Group of degree 2 over Finite Field of size 3 - sage: G = Sp(4,5) # optional - sage.libs.pari - sage: TestSuite(G).run() # optional - sage.libs.pari + sage: G = Sp(4,5) # optional - sage.rings.finite_rings + sage: TestSuite(G).run() # optional - sage.rings.finite_rings """ degree, ring = normalize_args_vectorspace(n, R, var=var) if degree % 2: @@ -179,13 +179,15 @@ class SymplecticMatrixGroup_generic(NamedMatrixGroup_generic): EXAMPLES:: - sage: Sp43 = Sp(4,3); Sp43 # optional - sage.libs.pari + sage: Sp43 = Sp(4,3); Sp43 # optional - sage.rings.finite_rings Symplectic Group of degree 4 over Finite Field of size 3 - sage: latex(Sp43) # optional - sage.libs.pari + sage: latex(Sp43) # optional - sage.rings.finite_rings \text{Sp}_{4}(\Bold{F}_{3}) - sage: Sp4m = Sp(4,QQ, invariant_form=(0, 0, 1, 0, 0, 0, 0, 2, -1, 0, 0, 0, 0, -2, 0, 0)); Sp4m - Symplectic Group of degree 4 over Rational Field with respect to alternating bilinear form + sage: Sp4m = Sp(4, QQ, invariant_form=(0, 0, 1, 0, 0, 0, 0, 2, + ....: -1, 0, 0, 0, 0, -2, 0, 0)); Sp4m + Symplectic Group of degree 4 over Rational Field + with respect to alternating bilinear form [ 0 0 1 0] [ 0 0 0 2] [-1 0 0 0] @@ -237,8 +239,8 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = Sp(4,GF(5)) # optional - sage.libs.pari - sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari + sage: G = Sp(4, GF(5)) # optional - sage.rings.finite_rings + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.rings.finite_rings """ F = self.invariant_form() if x * F * x.transpose() != F: diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index 7216d816bfd..578faf7703f 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -6,18 +6,18 @@ EXAMPLES:: - sage: G = SU(3,5) # optional - sage.libs.pari - sage: G.order() # optional - sage.libs.pari + sage: G = SU(3,5) # optional - sage.rings.finite_rings + sage: G.order() # optional - sage.rings.finite_rings 378000 - sage: G # optional - sage.libs.pari + sage: G # optional - sage.rings.finite_rings Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: G.gens() # optional - sage.libs.pari + sage: G.gens() # optional - sage.rings.finite_rings ( [ a 0 0] [4*a 4 1] [ 0 2*a + 2 0] [ 4 4 0] [ 0 0 3*a], [ 1 0 0] ) - sage: G.base_ring() # optional - sage.libs.pari + sage: G.base_ring() # optional - sage.rings.finite_rings Finite Field in a of size 5^2 AUTHORS: @@ -73,7 +73,7 @@ def finite_field_sqrt(ring): EXAMPLES:: sage: from sage.groups.matrix_gps.unitary import finite_field_sqrt - sage: finite_field_sqrt(GF(4, 'a')) # optional - sage.libs.pari + sage: finite_field_sqrt(GF(4, 'a')) # optional - sage.rings.finite_rings 2 """ if not isinstance(ring, FiniteField): @@ -96,7 +96,7 @@ def _UG(n, R, special, var='a', invariant_form=None): TESTS:: - sage: GU(3,25).order() # indirect doctest # optional - sage.libs.pari + sage: GU(3,25).order() # indirect doctest # optional - sage.rings.finite_rings 3961191000000 """ prefix = 'General' @@ -191,21 +191,21 @@ def GU(n, R, var='a', invariant_form=None): EXAMPLES:: - sage: G = GU(3, 7); G # optional - sage.libs.pari + sage: G = GU(3, 7); G # optional - sage.rings.finite_rings General Unitary Group of degree 3 over Finite Field in a of size 7^2 - sage: G.gens() # optional - sage.libs.pari + sage: G.gens() # optional - sage.rings.finite_rings ( [ a 0 0] [6*a 6 1] [ 0 1 0] [ 6 6 0] [ 0 0 5*a], [ 1 0 0] ) - sage: GU(2,QQ) + sage: GU(2, QQ) General Unitary Group of degree 2 over Rational Field - sage: G = GU(3, 5, var='beta') # optional - sage.libs.pari - sage: G.base_ring() # optional - sage.libs.pari + sage: G = GU(3, 5, var='beta') # optional - sage.rings.finite_rings + sage: G.base_ring() # optional - sage.rings.finite_rings Finite Field in beta of size 5^2 - sage: G.gens() # optional - sage.libs.pari + sage: G.gens() # optional - sage.rings.finite_rings ( [ beta 0 0] [4*beta 4 1] [ 0 1 0] [ 4 4 0] @@ -214,8 +214,8 @@ def GU(n, R, var='a', invariant_form=None): Using the ``invariant_form`` option:: - sage: UCF = UniversalCyclotomicField(); e5=UCF.gen(5) # optional - sage.rings.number_field - sage: m = matrix(UCF, 3,3, [[1,e5,0],[e5.conjugate(),2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: UCF = UniversalCyclotomicField(); e5 = UCF.gen(5) # optional - sage.rings.number_field + sage: m = matrix(UCF, 3, 3, [[1,e5,0], [e5.conjugate(),2,0], [0,0,1]]) # optional - sage.rings.number_field sage: G = GU(3, UCF) # optional - sage.rings.number_field sage: Gm = GU(3, UCF, invariant_form=m) # optional - sage.rings.number_field sage: G == Gm # optional - sage.rings.number_field @@ -242,12 +242,12 @@ def GU(n, R, var='a', invariant_form=None): [E(5)^4 2 0] [ 0 0 1] - sage: GU(3,3, invariant_form=[[1,0,0],[0,2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: GU(3, 3, invariant_form=[[1,0,0], [0,2,0], [0,0,1]]) # optional - sage.rings.number_field Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP - sage: GU(2,QQ, invariant_form=[[1,0],[2,0]]) + sage: GU(2, QQ, invariant_form=[[1,0], [2,0]]) Traceback (most recent call last): ... ValueError: invariant_form must be non-degenerate @@ -255,7 +255,7 @@ def GU(n, R, var='a', invariant_form=None): TESTS:: sage: TestSuite(G).run() # optional - sage.rings.number_field - sage: groups.matrix.GU(2, 3) # optional - sage.groups sage.libs.pari + sage: groups.matrix.GU(2, 3) # optional - sage.groups sage.rings.finite_rings General Unitary Group of degree 2 over Finite Field in a of size 3^2 """ return _UG(n, R, False, var=var, invariant_form=invariant_form) @@ -304,17 +304,17 @@ def SU(n, R, var='a', invariant_form=None): EXAMPLES:: - sage: SU(3,5) # optional - sage.libs.pari + sage: SU(3,5) # optional - sage.rings.finite_rings Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: SU(3, GF(5)) # optional - sage.libs.pari + sage: SU(3, GF(5)) # optional - sage.rings.finite_rings Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: SU(3,QQ) + sage: SU(3, QQ) Special Unitary Group of degree 3 over Rational Field Using the ``invariant_form`` option:: sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: m = matrix(CF3, 3, 3, [[1,e3,0], [e3.conjugate(),2,0], [0,0,1]]) # optional - sage.rings.number_field sage: G = SU(3, CF3) # optional - sage.rings.number_field sage: Gm = SU(3, CF3, invariant_form=m) # optional - sage.rings.number_field sage: G == Gm # optional - sage.rings.number_field @@ -340,7 +340,7 @@ def SU(n, R, var='a', invariant_form=None): [-zeta3 - 1 2 0] [ 0 0 1] - sage: SU(3,5, invariant_form=[[1,0,0],[0,2,0],[0,0,3]]) # optional - sage.libs.pari + sage: SU(3, 5, invariant_form=[[1,0,0], [0,2,0], [0,0,3]]) # optional - sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: invariant_form for finite groups is fixed by GAP @@ -348,7 +348,7 @@ def SU(n, R, var='a', invariant_form=None): TESTS:: sage: TestSuite(Gm).run() # optional - sage.rings.number_field - sage: groups.matrix.SU(2, 3) # optional - sage.libs.pari + sage: groups.matrix.SU(2, 3) # optional - sage.rings.finite_rings Special Unitary Group of degree 2 over Finite Field in a of size 3^2 """ return _UG(n, R, True, var=var, invariant_form=invariant_form) @@ -364,18 +364,18 @@ class UnitaryMatrixGroup_generic(NamedMatrixGroup_generic): EXAMPLES:: - sage: G = GU(3, GF(7)); G # optional - sage.libs.pari + sage: G = GU(3, GF(7)); G # optional - sage.rings.finite_rings General Unitary Group of degree 3 over Finite Field in a of size 7^2 - sage: latex(G) # optional - sage.libs.pari + sage: latex(G) # optional - sage.rings.finite_rings \text{GU}_{3}(\Bold{F}_{7^{2}}) - sage: G = SU(3, GF(5)); G # optional - sage.libs.pari + sage: G = SU(3, GF(5)); G # optional - sage.rings.finite_rings Special Unitary Group of degree 3 over Finite Field in a of size 5^2 - sage: latex(G) # optional - sage.libs.pari + sage: latex(G) # optional - sage.rings.finite_rings \text{SU}_{3}(\Bold{F}_{5^{2}}) sage: CF3 = CyclotomicField(3); e3 = CF3.gen() # optional - sage.rings.number_field - sage: m = matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) # optional - sage.rings.number_field + sage: m = matrix(CF3, 3, 3, [[1,e3,0], [e3.conjugate(),2,0], [0,0,1]]) # optional - sage.rings.number_field sage: G = SU(3, CF3, invariant_form=m) # optional - sage.rings.number_field sage: latex(G) # optional - sage.rings.number_field \text{SU}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to positive definite hermitian form }\left(\begin{array}{rrr} @@ -421,10 +421,10 @@ def _check_matrix(self, x, *args): EXAMPLES:: - sage: G = GU(2, GF(5)) # optional - sage.libs.pari - sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari - sage: G = SU(2, GF(5)) # optional - sage.libs.pari - sage: G._check_matrix(G.an_element().matrix()) # optional - sage.libs.pari + sage: G = GU(2, GF(5)) # optional - sage.rings.finite_rings + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.rings.finite_rings + sage: G = SU(2, GF(5)) # optional - sage.rings.finite_rings + sage: G._check_matrix(G.an_element().matrix()) # optional - sage.rings.finite_rings """ if self._special and x.determinant() != 1: raise TypeError('matrix must have determinant one') From 45a332d7d285428fbcc64b81d128fa7f362201e0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 1 Apr 2023 11:27:39 -0700 Subject: [PATCH 14/18] src/sage/groups/matrix_gps/all__sagemath_polyhedra.py: Remove (committed by mistake) --- .../groups/matrix_gps/all__sagemath_polyhedra.py | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/sage/groups/matrix_gps/all__sagemath_polyhedra.py diff --git a/src/sage/groups/matrix_gps/all__sagemath_polyhedra.py b/src/sage/groups/matrix_gps/all__sagemath_polyhedra.py deleted file mode 100644 index c6360cd6a03..00000000000 --- a/src/sage/groups/matrix_gps/all__sagemath_polyhedra.py +++ /dev/null @@ -1,13 +0,0 @@ -from sage.misc.lazy_import import lazy_import - -lazy_import('sage.groups.matrix_gps.linear', 'GL') -lazy_import('sage.groups.matrix_gps.linear', 'SL') -lazy_import('sage.groups.matrix_gps.symplectic', 'Sp') -lazy_import('sage.groups.matrix_gps.unitary', 'SU') -lazy_import('sage.groups.matrix_gps.unitary', 'GU') -lazy_import('sage.groups.matrix_gps.orthogonal', 'GO') -lazy_import('sage.groups.matrix_gps.orthogonal', 'SO') -lazy_import('sage.groups.matrix_gps.finitely_generated', 'MatrixGroup') -lazy_import('sage.groups.matrix_gps.finitely_generated', 'QuaternionMatrixGroupGF3') - -import sage.groups.matrix_gps.pickling_overrides From 9de361d0f820ebe714f07ba397ee92370d3bd16e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 14 Apr 2023 11:55:26 -0700 Subject: [PATCH 15/18] src/sage/groups/matrix_gps: Update/add copyright notices using 'git blame -M -C -w --date=format:%Y FILE.py | sort -k2' --- .../groups/matrix_gps/finitely_generated.py | 13 ++++++++--- .../matrix_gps/finitely_generated_gap.py | 23 +++++++++++++++++++ src/sage/groups/matrix_gps/group_element.pyx | 8 ++++--- .../groups/matrix_gps/group_element_gap.pyx | 15 ++++++++++++ src/sage/groups/matrix_gps/matrix_group.py | 6 +++++ .../groups/matrix_gps/matrix_group_gap.py | 17 ++++++++++++++ src/sage/groups/matrix_gps/named_group.py | 5 +++- src/sage/groups/matrix_gps/named_group_gap.py | 13 +++++++++++ src/sage/groups/matrix_gps/orthogonal.py | 6 ++++- src/sage/groups/matrix_gps/symplectic.py | 4 +++- src/sage/groups/matrix_gps/symplectic_gap.py | 13 +++++++++++ src/sage/groups/matrix_gps/unitary.py | 7 +++++- src/sage/groups/matrix_gps/unitary_gap.py | 13 +++++++++++ 13 files changed, 133 insertions(+), 10 deletions(-) diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index 54568c333f4..7f3db1f77e7 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -51,16 +51,23 @@ - Sebastian Oehms (2019-01): Revision of :trac:`25706` (:trac:`26903` and :trac:`27143`). """ -############################################################################## +# ############################################################################# # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun +# 2009 Mike Hansen +# 2012 Rob Beezer +# 2013 Volker Braun +# 2013 Nathann Cohen +# 2013 Travis Scrimshaw +# 2017 Peter Bruin +# 2021 Frédéric Chapoton +# 2023 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -############################################################################## +# ############################################################################# from sage.groups.matrix_gps.group_element import is_MatrixGroupElement from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py index 612fbd286ec..ab93bf46ef7 100644 --- a/src/sage/groups/matrix_gps/finitely_generated_gap.py +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -2,6 +2,29 @@ Finitely Generated Matrix Groups with GAP """ +# ############################################################################# +# Copyright (C) 2006 William Stein +# 2006-2008 David Joyner +# 2008-2010 Simon King +# 2009 Mike Hansen +# 2011-2013 Volker Braun +# 2013-2023 Travis Scrimshaw +# 2015 Pierre Guillot +# 2017 Ben Hutz +# 2017 Rebecca Lauren Miller +# 2018 Dima Pasechnik +# 2018-2019 Sebastian Oehms +# 2018-2020 Frédéric Chapoton +# 2019 Vincent Delecroix +# 2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# The full text of the GPL is available at: +# +# https://www.gnu.org/licenses/ +# ############################################################################# + from sage.combinat.integer_vector import IntegerVectors from sage.groups.matrix_gps.finitely_generated import MatrixGroup from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 67fda25d0cf..4a1ae82a68b 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -63,9 +63,11 @@ AUTHORS: """ #***************************************************************************** -# Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun -# Copyright (C) 2016 Travis Scrimshaw +# Copyright (C) 2006 David Joyner and William Stein +# 2013 Volker Braun +# 2016 Travis Scrimshaw +# 2016-2018 Jeroen Demeyer +# 2023 Matthias Koeppe # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/sage/groups/matrix_gps/group_element_gap.pyx b/src/sage/groups/matrix_gps/group_element_gap.pyx index 2e6116e7871..411f59a3b04 100644 --- a/src/sage/groups/matrix_gps/group_element_gap.pyx +++ b/src/sage/groups/matrix_gps/group_element_gap.pyx @@ -2,6 +2,21 @@ r""" Matrix group elements implemented in GAP """ +#***************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein +# 2013 Volker Braun +# 2015-2017 Vincent Delecroix +# 2016 Travis Scrimshaw +# 2018 Jeroen Demeyer +# 2023 Matthias Koeppe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +#***************************************************************************** + from sage.groups.matrix_gps.group_element cimport is_MatrixGroupElement from sage.libs.gap.element cimport GapElement, GapElement_List from sage.misc.cachefunc import cached_method diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index f3728709cf8..4561a9bbf0a 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -41,6 +41,12 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein +# 2009 Mike Hansen +# 2013 Volker Braun +# 2017-2021 Frédéric Chapoton +# 2018-2019 Sebastian Oehms +# 2020 Siddharth Singh +# 2023 Matthias Koeppe # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py index 9b327ff9250..632c4f8ee3b 100644 --- a/src/sage/groups/matrix_gps/matrix_group_gap.py +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -2,6 +2,23 @@ Matrix group over a ring that GAP understands """ +# **************************************************************************** +# Copyright (C) 2006 William Stein +# 2006-2008 David Joyner +# 2013 Volker Braun +# 2017 Dima Pasechnik +# 2021 Frédéric Chapoton +# 2018-2019 Sebastian Oehms +# 2020 Vincent Delecroix +# 2023 Matthias Koeppe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from sage.categories.groups import Groups from sage.groups.group import Group from sage.groups.libgap_mixin import GroupMixinLibGAP diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index dce2e17e9d0..08717dd7110 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -31,7 +31,10 @@ ############################################################################## # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun +# 2013 Volker Braun +# 2017 Frédéric Chapoton +# 2018 Travis Scrimshaw +# 2018 Sebastian Oehms # # Distributed under the terms of the GNU General Public License (GPL) # diff --git a/src/sage/groups/matrix_gps/named_group_gap.py b/src/sage/groups/matrix_gps/named_group_gap.py index ecc24d0bd1a..b8b1f54722c 100644 --- a/src/sage/groups/matrix_gps/named_group_gap.py +++ b/src/sage/groups/matrix_gps/named_group_gap.py @@ -2,6 +2,19 @@ Base for Classical Matrix Groups with GAP """ +############################################################################## +# Copyright (C) 2006 David Joyner and William Stein +# 2013 Volker Braun +# 2017 John Palmieri +# 2023 Matthias Koeppe +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# The full text of the GPL is available at: +# +# http://www.gnu.org/licenses/ +############################################################################## + from sage.groups.matrix_gps.matrix_group_gap import MatrixGroup_gap from sage.groups.matrix_gps.named_group import NamedMatrixGroup_generic diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 1de6593eb7c..694401d6d31 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -76,7 +76,11 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun +# 2009 Mike Hansen +# 2013 Volker Braun +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index 8fda1c60962..dfd6de48b13 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -31,7 +31,9 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun +# 2013 Volker Braun +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/sage/groups/matrix_gps/symplectic_gap.py b/src/sage/groups/matrix_gps/symplectic_gap.py index 891c5bac832..10e7639df17 100644 --- a/src/sage/groups/matrix_gps/symplectic_gap.py +++ b/src/sage/groups/matrix_gps/symplectic_gap.py @@ -2,6 +2,19 @@ Symplectic Linear Groups with GAP """ +# **************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein +# 2013 Volker Braun +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap from sage.groups.matrix_gps.symplectic import SymplecticMatrixGroup_generic diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index 578faf7703f..48a5351bd2f 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -40,7 +40,12 @@ # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein -# Copyright (C) 2013 Volker Braun +# 2012 Rob Beezer +# 2013 Volker Braun +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2019 Jeroen Demeyer +# 2023 Matthias Koeppe # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/sage/groups/matrix_gps/unitary_gap.py b/src/sage/groups/matrix_gps/unitary_gap.py index f760e880d40..26c1a8eb82f 100644 --- a/src/sage/groups/matrix_gps/unitary_gap.py +++ b/src/sage/groups/matrix_gps/unitary_gap.py @@ -2,6 +2,19 @@ Unitary Groups `GU(n,q)` and `SU(n,q)` with GAP """ +# **************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap from sage.groups.matrix_gps.unitary import UnitaryMatrixGroup_generic From bea635b2301203bcb2bae7191409c6e5a1d4bb1e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 14 Apr 2023 15:51:09 -0700 Subject: [PATCH 16/18] sage.groups.matrix_gps: Docstring cosmetics --- src/sage/groups/affine_gps/affine_group.py | 12 ++--- src/sage/groups/affine_gps/euclidean_group.py | 2 +- src/sage/groups/affine_gps/group_element.py | 26 +++------ src/sage/groups/matrix_gps/coxeter_group.py | 12 +++-- .../groups/matrix_gps/finitely_generated.py | 2 +- .../matrix_gps/finitely_generated_gap.py | 53 +++++++++++-------- src/sage/groups/matrix_gps/group_element.pyx | 31 +++++------ .../groups/matrix_gps/group_element_gap.pyx | 6 +-- src/sage/groups/matrix_gps/isometries.py | 36 ++++++------- src/sage/groups/matrix_gps/linear.py | 4 +- src/sage/groups/matrix_gps/matrix_group.py | 10 ++-- .../groups/matrix_gps/matrix_group_gap.py | 4 +- src/sage/groups/matrix_gps/orthogonal_gap.py | 2 +- src/sage/groups/matrix_gps/symplectic.py | 4 +- src/sage/groups/matrix_gps/symplectic_gap.py | 4 +- src/sage/groups/matrix_gps/unitary.py | 28 ++++------ src/sage/groups/matrix_gps/unitary_gap.py | 2 +- 17 files changed, 108 insertions(+), 130 deletions(-) diff --git a/src/sage/groups/affine_gps/affine_group.py b/src/sage/groups/affine_gps/affine_group.py index 85191710aca..81074a3e50d 100644 --- a/src/sage/groups/affine_gps/affine_group.py +++ b/src/sage/groups/affine_gps/affine_group.py @@ -301,9 +301,7 @@ def degree(self): """ Return the dimension of the affine space. - OUTPUT: - - An integer. + OUTPUT: An integer. EXAMPLES:: @@ -388,9 +386,7 @@ def linear(self, A): - ``A`` -- anything that determines a matrix - OUTPUT: - - The affine group element `x \mapsto A x`. + OUTPUT: The affine group element `x \mapsto A x`. EXAMPLES:: @@ -411,9 +407,7 @@ def translation(self, b): - ``b`` -- anything that determines a vector - OUTPUT: - - The affine group element `x \mapsto x + b`. + OUTPUT: The affine group element `x \mapsto x + b`. EXAMPLES:: diff --git a/src/sage/groups/affine_gps/euclidean_group.py b/src/sage/groups/affine_gps/euclidean_group.py index 4dee50f329b..b88b4f741ac 100644 --- a/src/sage/groups/affine_gps/euclidean_group.py +++ b/src/sage/groups/affine_gps/euclidean_group.py @@ -21,7 +21,7 @@ class EuclideanGroup(AffineGroup): r""" - an Euclidean group. + A Euclidean group. The Euclidean group `E(A)` (or general affine group) of an affine space `A` is the group of all invertible affine transformations from diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index 590d4bf400d..48126ba64a8 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -67,16 +67,14 @@ class AffineGroupElement(MultiplicativeGroupElement): correct vector space. - ``check`` - bool (default: ``True``). Whether to do some - checks or just accept the input as valid. + checks or just accept the input as valid. As a special case, ``A`` can be a matrix obtained from :meth:`matrix`, that is, one row and one column larger. In that case, the group element defining that matrix is reconstructed. - OUTPUT: - - The affine group element `x \mapsto Ax + b` + OUTPUT: The affine group element `x \mapsto Ax + b` EXAMPLES:: @@ -144,9 +142,7 @@ def A(self): """ Return the general linear part of an affine group element. - OUTPUT: - - The matrix `A` of the affine group element `Ax + b`. + OUTPUT: The matrix `A` of the affine group element `Ax + b`. EXAMPLES:: @@ -163,9 +159,7 @@ def b(self): """ Return the translation part of an affine group element. - OUTPUT: - - The vector `b` of the affine group element `Ax + b`. + OUTPUT: The vector `b` of the affine group element `Ax + b`. EXAMPLES:: @@ -361,9 +355,7 @@ def __call__(self, v): - ``v`` -- a polynomial, a multivariate polynomial, a polyhedron, a vector, or anything that can be converted into a vector. - OUTPUT: - - The image of ``v`` under the affine group element. + OUTPUT: The image of ``v`` under the affine group element. EXAMPLES:: @@ -459,9 +451,7 @@ def __invert__(self): """ Return the inverse group element. - OUTPUT: - - Another affine group element. + OUTPUT: Another affine group element. EXAMPLES:: @@ -488,9 +478,7 @@ def _richcmp_(self, other, op): """ Compare ``self`` with ``other``. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index 607eda9519a..66a877c61ac 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -186,10 +186,12 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene [2 2 3 2 1] sage: W = CoxeterGroup(['H',3], implementation="reflection") sage: W - Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? with Coxeter matrix: - [1 3 2] - [3 1 5] - [2 5 1] + Finite Coxeter group over + Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? + with Coxeter matrix: + [1 3 2] + [3 1 5] + [2 5 1] """ @staticmethod def __classcall_private__(cls, data, base_ring=None, index_set=None): @@ -834,7 +836,7 @@ def action_on_root_indices(self, i, side="left"): """ Return the action on the set of roots. - The roots are ordered as in the output of the method `roots`. + The roots are ordered as in the output of the method :meth:`roots`. EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index 7f3db1f77e7..874b6b72d7b 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -141,7 +141,7 @@ def normalize_square_matrices(matrices): def QuaternionMatrixGroupGF3(): r""" - The quaternion group as a set of `2\times 2` matrices over `GF(3)`. + The quaternion group as a set of `2\times 2` matrices over `\GF{3}`. OUTPUT: diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py index ab93bf46ef7..a58ff05291d 100644 --- a/src/sage/groups/matrix_gps/finitely_generated_gap.py +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -93,7 +93,7 @@ def as_permutation_group(self, algorithm=None, seed=None): - ``seed`` -- ``None`` or an integer specifying the seed to fix results depending on pseudo-random-numbers. Here it makes sense to be used with respect to the ``'smaller'`` - option, since gap produces random output in that context. + option, since GAP produces random output in that context. OUTPUT: @@ -112,7 +112,7 @@ def as_permutation_group(self, algorithm=None, seed=None): sage: G.as_permutation_group().order() 2 - A finite subgroup of GL(12,Z) as a permutation group:: + A finite subgroup of `GL(12,\ZZ)` as a permutation group:: sage: imf = libgap.function_factory('ImfMatrixGroup') sage: GG = imf( 12, 3 ) @@ -137,7 +137,7 @@ def as_permutation_group(self, algorithm=None, seed=None): In this case, the "smaller" option returned an isomorphic group of lower degree. The above example used GAP's library of irreducible maximal finite ("imf") integer matrix groups - to construct the MatrixGroup G over GF(7). The section + to construct the :class:`MatrixGroup` `G` over `\GF{7}`. The section "Irreducible Maximal Finite Integral Matrix Groups" in the GAP reference manual has more details. @@ -148,7 +148,7 @@ def as_permutation_group(self, algorithm=None, seed=None): involve the use of random elements and the permutation representation (or even the degree of the representation) is not guaranteed to be the same for different calls of - SmallerDegreePermutationRepresentation." + ``SmallerDegreePermutationRepresentation``." To obtain a reproducible result the optional argument ``seed`` may be used as in the example above. @@ -161,7 +161,7 @@ def as_permutation_group(self, algorithm=None, seed=None): sage: a.order(), b.order() (2, 1) - The above example in GL(12,Z), reduced modulo 7:: + The above example in `GL(12,\ZZ)`, reduced modulo 7:: sage: MS = MatrixSpace(GF(7), 12, 12) sage: G = MatrixGroup([MS(g) for g in GG.GeneratorsOfGroup()]) @@ -481,7 +481,8 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): sage: K. = CyclotomicField(8) sage: a = v-v^3 #sqrt(2) sage: i = v^2 - sage: Octa = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [(1+i)/a,0, 0,(1-i)/a]) + sage: Octa = MatrixGroup([(-1+i)/2, (-1+i)/2, (1+i)/2, (-1-i)/2], + ....: [(1+i)/a, 0, 0, (1-i)/a]) sage: Octa.molien_series(prec=30) 1 + t^8 + t^12 + t^16 + t^18 + t^20 + 2*t^24 + t^26 + t^28 + O(t^30) @@ -491,7 +492,9 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): sage: z5 = v^2 sage: i = z5^5 sage: a = 2*z5^3 + 2*z5^2 + 1 #sqrt(5) - sage: Ico = MatrixGroup([[z5^3,0, 0,z5^2], [0,1, -1,0], [(z5^4-z5)/a, (z5^2-z5^3)/a, (z5^2-z5^3)/a, -(z5^4-z5)/a]]) + sage: Ico = MatrixGroup([[z5^3,0, 0,z5^2], + ....: [0,1, -1,0], + ....: [(z5^4-z5)/a, (z5^2-z5^3)/a, (z5^2-z5^3)/a, -(z5^4-z5)/a]]) sage: Ico.molien_series(prec=40) 1 + t^12 + t^20 + t^24 + t^30 + t^32 + t^36 + O(t^40) @@ -500,20 +503,22 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): sage: G = MatrixGroup(CyclicPermutationGroup(3)) sage: chi = G.character(G.character_table()[1]) sage: G.molien_series(chi, prec=10) - t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 9*t^6 + 12*t^7 + 15*t^8 + 18*t^9 + 22*t^10 + O(t^11) + t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 9*t^6 + + 12*t^7 + 15*t^8 + 18*t^9 + 22*t^10 + O(t^11) :: sage: K = GF(5) sage: S = MatrixGroup(SymmetricGroup(4)) - sage: G = MatrixGroup([matrix(K,4,4,[K(y) for u in m.list() for y in u])for m in S.gens()]) + sage: G = MatrixGroup([matrix(K, 4, 4, [K(y) for u in m.list() for y in u]) + ....: for m in S.gens()]) sage: G.molien_series(return_series=False) 1/(t^10 - t^9 - t^8 + 2*t^5 - t^2 - t + 1) :: sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) + sage: G = MatrixGroup([[i^3,0, 0,-i^3], [i^2,0, 0,-i^2]]) sage: chi = G.character(G.character_table()[4]) sage: G.molien_series(chi) 3*t^5 + 6*t^11 + 9*t^17 + 12*t^23 + O(t^25) @@ -597,7 +602,7 @@ def reynolds_operator(self, poly, chi=None): K[x]^G_{\chi} = \{f \in K[x] | \pi f = \chi(\pi) f \forall \pi\in G\} - be the ring of invariants of `G` relative to `\chi`. Then the Reynold's operator + be the ring of invariants of `G` relative to `\chi`. Then the Reynolds operator is a map `R` from `K[x]` into `K[x]^G_{\chi}` defined by .. MATH: @@ -644,10 +649,12 @@ def reynolds_operator(self, poly, chi=None): sage: chi = G.character(G.character_table()[1]) sage: R. = K[] sage: G.reynolds_operator(x*y^5, chi) - 1/3*x*y^5 + (-2/3*izeta3^3 - izeta3^2 - 8/3*izeta3 - 4/3)*x^5*z + (2/3*izeta3^3 + izeta3^2 + 8/3*izeta3 + 1)*y*z^5 + 1/3*x*y^5 + (-2/3*izeta3^3 - izeta3^2 - 8/3*izeta3 - 4/3)*x^5*z + + (2/3*izeta3^3 + izeta3^2 + 8/3*izeta3 + 1)*y*z^5 sage: R. = QQbar[] sage: G.reynolds_operator(x*y^5, chi) - 1/3*x*y^5 + (-0.1666666666666667? + 0.2886751345948129?*I)*x^5*z + (-0.1666666666666667? - 0.2886751345948129?*I)*y*z^5 + 1/3*x*y^5 + (-0.1666666666666667? + 0.2886751345948129?*I)*x^5*z + + (-0.1666666666666667? - 0.2886751345948129?*I)*y*z^5 :: @@ -661,7 +668,7 @@ def reynolds_operator(self, poly, chi=None): sage: Tetra.reynolds_operator(x^4, chi) 1/4*x^4 + (1/2*v)*x^2*y^2 + 1/4*y^4 sage: R.=L[] - sage: LL. = L.extension(x^2+v) + sage: LL. = L.extension(x^2 + v) sage: R. = LL[] sage: Tetra.reynolds_operator(x^4, chi) Traceback (most recent call last): @@ -684,9 +691,9 @@ def reynolds_operator(self, poly, chi=None): 1/8*x^3*y - 1/8*x*y^3 + 1/8*y^3*z - 1/8*y*z^3 - 1/8*x^3*w + 1/8*z^3*w + 1/8*x*w^3 - 1/8*z*w^3 - Characteristic p>0 examples:: + Characteristic `p>0` examples:: - sage: G = MatrixGroup([[0,1,1,0]]) + sage: G = MatrixGroup([[0,1, 1,0]]) sage: R. = GF(2)[] sage: G.reynolds_operator(x) Traceback (most recent call last): @@ -696,7 +703,7 @@ def reynolds_operator(self, poly, chi=None): :: sage: i = GF(7)(3) - sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) + sage: G = MatrixGroup([[i^3,0, 0,-i^3], [i^2,0, 0,-i^2]]) sage: chi = G.character(G.character_table()[4]) sage: R. = GF(7)[] sage: f = w^5*x + x^6 @@ -710,7 +717,7 @@ def reynolds_operator(self, poly, chi=None): :: sage: K = GF(3^2,'t') - sage: G = MatrixGroup([matrix(K,2,2, [0,K.gen(),1,0])]) + sage: G = MatrixGroup([matrix(K, 2, 2, [0,K.gen(), 1,0])]) sage: R. = GF(3)[] sage: G.reynolds_operator(x^8) -x^8 - y^8 @@ -718,7 +725,7 @@ def reynolds_operator(self, poly, chi=None): :: sage: K = GF(3^2,'t') - sage: G = MatrixGroup([matrix(GF(3),2,2, [0,1,1,0])]) + sage: G = MatrixGroup([matrix(GF(3), 2, 2, [0,1, 1,0])]) sage: R. = K[] sage: f = -K.gen()*x sage: G.reynolds_operator(f) @@ -863,8 +870,10 @@ def invariants_of_degree(self, deg, chi=None, R=None): sage: chi = G.character(G.character_table()[1]) sage: R. = K[] sage: sorted(G.invariants_of_degree(2, R=R, chi=chi)) - [x*y + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*x*z + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y*z, - x^2 + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y^2 + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*z^2] + [x*y + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*x*z + + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y*z, + x^2 + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*y^2 + + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*z^2] :: @@ -872,7 +881,7 @@ def invariants_of_degree(self, deg, chi=None, R=None): sage: chi = S3.character(S3.character_table()[0]) sage: sorted(S3.invariants_of_degree(5, chi=chi)) [x0^3*x1^2 - x0^2*x1^3 - x0^3*x2^2 + x1^3*x2^2 + x0^2*x2^3 - x1^2*x2^3, - x0^4*x1 - x0*x1^4 - x0^4*x2 + x1^4*x2 + x0*x2^4 - x1*x2^4] + x0^4*x1 - x0*x1^4 - x0^4*x2 + x1^4*x2 + x0*x2^4 - x1*x2^4] """ D = self.degree() deg = int(deg) diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 4a1ae82a68b..c18476a45ba 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -98,9 +98,7 @@ cpdef is_MatrixGroupElement(x): - ``x`` -- anything. - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: @@ -133,7 +131,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): - ``parent`` -- the parent - ``check`` -- bool (default: ``True``); if ``True``, then - does some type checking + do some type checking - ``convert`` -- bool (default: ``True``); if ``True``, then convert ``M`` to the right matrix space @@ -141,8 +139,7 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): EXAMPLES:: sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat - sage: g = W.an_element() # optional - sage.combinat - sage: g # optional - sage.combinat + sage: g = W.an_element(); g # optional - sage.combinat [ 0 0 -1] [ 1 0 -1] [ 0 1 -1] @@ -371,28 +368,26 @@ cdef class MatrixGroupElement_generic(MultiplicativeGroupElement): """ Return the inverse group element - OUTPUT: - - A matrix group element. + OUTPUT: A matrix group element. EXAMPLES:: - sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat - sage: g = W.an_element() # optional - sage.combinat - sage: ~g # optional - sage.combinat + sage: W = CoxeterGroup(['A',3], base_ring=ZZ) # optional - sage.combinat + sage: g = W.an_element() # optional - sage.combinat + sage: ~g # optional - sage.combinat [-1 1 0] [-1 0 1] [-1 0 0] - sage: g * ~g == W.one() # optional - sage.combinat + sage: g * ~g == W.one() # optional - sage.combinat True - sage: ~g * g == W.one() # optional - sage.combinat + sage: ~g * g == W.one() # optional - sage.combinat True - sage: W = CoxeterGroup(['B',3]) # optional - sage.combinat sage.rings.number_field - sage: W.base_ring() # optional - sage.combinat sage.rings.number_field + sage: W = CoxeterGroup(['B',3]) # optional - sage.combinat sage.rings.number_field + sage: W.base_ring() # optional - sage.combinat sage.rings.number_field Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? - sage: g = W.an_element() # optional - sage.combinat sage.rings.number_field - sage: ~g # optional - sage.combinat sage.rings.number_field + sage: g = W.an_element() # optional - sage.combinat sage.rings.number_field + sage: ~g # optional - sage.combinat sage.rings.number_field [-1 1 0] [-1 0 a] [-a 0 1] diff --git a/src/sage/groups/matrix_gps/group_element_gap.pyx b/src/sage/groups/matrix_gps/group_element_gap.pyx index 411f59a3b04..7aba88e9b88 100644 --- a/src/sage/groups/matrix_gps/group_element_gap.pyx +++ b/src/sage/groups/matrix_gps/group_element_gap.pyx @@ -37,10 +37,10 @@ cdef class MatrixGroupElement_gap(ElementLibGAP): - ``parent`` -- the parent - - ``check`` -- bool (default: ``True``); if ``True`` does some + - ``check`` -- bool (default: ``True``); if ``True``, do some type checking - - ``convert`` -- bool (default: ``True``); if ``True`` convert + - ``convert`` -- bool (default: ``True``); if ``True``, convert ``M`` to the right matrix space """ def __init__(self, parent, M, check=True, convert=True): @@ -318,7 +318,7 @@ cdef class MatrixGroupElement_gap(ElementLibGAP): OUTPUT: A factorization object that contains information about the - order of factors and the exponents. A ``ValueError`` is raised + order of factors and the exponents. A :class:`ValueError` is raised if the group element cannot be written as a word in ``gens``. ALGORITHM: diff --git a/src/sage/groups/matrix_gps/isometries.py b/src/sage/groups/matrix_gps/isometries.py index e7445166db6..3810a80cadc 100644 --- a/src/sage/groups/matrix_gps/isometries.py +++ b/src/sage/groups/matrix_gps/isometries.py @@ -1,5 +1,5 @@ r""" -Groups of isometries. +Groups of isometries Let `M = \ZZ^n` or `\QQ^n`, `b: M \times M \rightarrow \QQ` a bilinear form and `f: M \rightarrow M` a linear map. We say that `f` is an isometry if for all @@ -68,9 +68,9 @@ class GroupOfIsometries(FinitelyGeneratedMatrixGroup_gap): EXAMPLES:: sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries - sage: bil = Matrix(ZZ,2,[3,2,2,3]) - sage: gens = [-Matrix(ZZ,2,[0,1,1,0])] - sage: O = GroupOfIsometries(2,ZZ,gens,bil) + sage: bil = Matrix(ZZ, 2, [3,2,2,3]) + sage: gens = [-Matrix(ZZ, 2, [0,1,1,0])] + sage: O = GroupOfIsometries(2, ZZ, gens, bil) sage: O Group of isometries with 1 generator ( [ 0 -1] @@ -83,7 +83,7 @@ class GroupOfIsometries(FinitelyGeneratedMatrixGroup_gap): sage: bil = Matrix(ZZ,4,[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0]) sage: f = Matrix(ZZ,4,[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, 1, 1, 1]) - sage: O = GroupOfIsometries(2,ZZ,[f],bil) + sage: O = GroupOfIsometries(2, ZZ, [f], bil) sage: O.cardinality() +Infinity """ @@ -135,9 +135,7 @@ def _repr_(self): r""" Return the string representation of this matrix group. - OUTPUT: - - - a string + OUTPUT: a string EXAMPLES:: @@ -186,9 +184,7 @@ def invariant_bilinear_form(self): r""" Return the symmetric bilinear form preserved by the orthogonal group. - OUTPUT: - - - the matrix defining the bilinear form + OUTPUT: the matrix defining the bilinear form EXAMPLES:: @@ -278,9 +274,11 @@ class GroupActionOnSubmodule(Action): EXAMPLES:: sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries - sage: S = span(ZZ,[[0,1]]) - sage: g = Matrix(QQ,2,[1,0,0,-1]) - sage: G = GroupOfIsometries(2, ZZ, [g], invariant_bilinear_form=matrix.identity(2), invariant_submodule=S) + sage: S = span(ZZ, [[0,1]]) + sage: g = Matrix(QQ, 2, [1,0,0,-1]) + sage: G = GroupOfIsometries(2, ZZ, [g], + ....: invariant_bilinear_form=matrix.identity(2), + ....: invariant_submodule=S) sage: g = G.an_element() sage: x = S.an_element() sage: x*g @@ -297,11 +295,11 @@ def __init__(self, MatrixGroup,submodule, is_left=False): TESTS:: sage: from sage.groups.matrix_gps.isometries import GroupOfIsometries, GroupActionOnSubmodule - sage: S = span(ZZ,[[0,1]]) - sage: g = Matrix(QQ,2,[1,0,0,-1]) + sage: S = span(ZZ, [[0,1]]) + sage: g = Matrix(QQ, 2, [1,0,0,-1]) sage: e = Matrix.identity(2) sage: G = GroupOfIsometries(2, ZZ, [g], e) - sage: GroupActionOnSubmodule(G,S) + sage: GroupActionOnSubmodule(G, S) Right action by Group of isometries with 1 generator ( [ 1 0] [ 0 -1] @@ -406,9 +404,7 @@ def _act_(self, g, a): - ``a`` -- an element of the invariant submodule - OUTPUT: - - - an element of the invariant quotient module + OUTPUT: an element of the invariant quotient module EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index f56edc3cea0..8dc29267923 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -195,7 +195,7 @@ def SL(n, R, var='a'): This group is also available via ``groups.matrix.SL()``. - INPUT: + INPUT: - ``n`` -- a positive integer. @@ -277,7 +277,7 @@ def SL(n, R, var='a'): class LinearMatrixGroup_generic(NamedMatrixGroup_generic): def _check_matrix(self, x, *args): - """a + r""" Check whether the matrix ``x`` is special linear. See :meth:`~sage.groups.matrix_gps.matrix_group._check_matrix` diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 4561a9bbf0a..f9b864f770a 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -1,6 +1,8 @@ """ Base classes for Matrix Groups +TESTS: + Loading, saving, ... works:: sage: G = GL(2,5); G # optional - sage.rings.finite_rings @@ -182,10 +184,10 @@ def subgroup(self, generators, check=True): INPUT: - - ``generators`` -- a list/tuple/iterable of group elements of self + - ``generators`` -- a list/tuple/iterable of group elements of ``self`` - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. - OUTPUT: The subgroup generated by ``generators`` as an instance of FinitelyGeneratedMatrixGroup_gap + OUTPUT: The subgroup generated by :meth:`generators` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` EXAMPLES:: @@ -341,7 +343,9 @@ def sign_representation(self, base_ring=None, side="twosided"): r""" Return the sign representation of ``self`` over ``base_ring``. - WARNING: assumes ``self`` is a matrix group over a field which has embedding over real numbers. + .. WARNING:: + + Assumes ``self`` is a matrix group over a field which has embedding over real numbers. INPUT: diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py index 632c4f8ee3b..1ec41dfc678 100644 --- a/src/sage/groups/matrix_gps/matrix_group_gap.py +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -231,10 +231,10 @@ def subgroup(self, generators, check=True): INPUT: - - ``generators`` -- a list/tuple/iterable of group elements of self + - ``generators`` -- a list/tuple/iterable of group elements of ``self`` - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. - OUTPUT: The subgroup generated by ``generators`` as an instance of FinitelyGeneratedMatrixGroup_gap + OUTPUT: The subgroup generated by :meth:`generators` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/orthogonal_gap.py b/src/sage/groups/matrix_gps/orthogonal_gap.py index f75958276ce..5e7e4e4611a 100644 --- a/src/sage/groups/matrix_gps/orthogonal_gap.py +++ b/src/sage/groups/matrix_gps/orthogonal_gap.py @@ -29,7 +29,7 @@ def invariant_bilinear_form(self): OUTPUT: - A matrix `M` such that, for every group element g, the + A matrix `M` such that, for every group element `g`, the identity `g m g^T = m` holds. In characteristic different from two, this uniquely determines the orthogonal group. diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index dfd6de48b13..aad18def93b 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -208,9 +208,7 @@ def invariant_form(self): """ Return the quadratic form preserved by the symplectic group. - OUTPUT: - - A matrix. + OUTPUT: A matrix. EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/symplectic_gap.py b/src/sage/groups/matrix_gps/symplectic_gap.py index 10e7639df17..adeefea218f 100644 --- a/src/sage/groups/matrix_gps/symplectic_gap.py +++ b/src/sage/groups/matrix_gps/symplectic_gap.py @@ -48,9 +48,7 @@ def invariant_form(self): """ Return the quadratic form preserved by the symplectic group. - OUTPUT: - - A matrix. + OUTPUT: A matrix. EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index 48a5351bd2f..8d8a4d23491 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -67,13 +67,11 @@ def finite_field_sqrt(ring): """ Helper function. - INPUT: - - A ring. + INPUT: A ring. OUTPUT: - Integer q such that ``ring`` is the finite field with `q^2` elements. + Integer `q` such that ``ring`` is the finite field with `q^2` elements. EXAMPLES:: @@ -165,9 +163,9 @@ def GU(n, R, var='a', invariant_form=None): .. NOTE:: - For a finite field the matrices that preserve a sesquilinear - form over `F_q` live over `F_{q^2}`. So ``GU(n,q)`` for - a prime power ``q`` constructs the matrix group over the base + For a finite field, the matrices that preserve a sesquilinear + form over `\GF{q}` live over `\GF{q^2}`. So ``GU(n,q)`` for + a prime power `q` constructs the matrix group over the base ring ``GF(q^2)``. .. NOTE:: @@ -186,13 +184,11 @@ def GU(n, R, var='a', invariant_form=None): - ``invariant_form`` -- (optional) instances being accepted by the matrix-constructor which define a `n \times n` square matrix - over R describing the hermitian form to be kept invariant + over `R` describing the hermitian form to be kept invariant by the unitary group; the form is checked to be non-degenerate and hermitian but not to be positive definite - OUTPUT: - - Return the general unitary group. + OUTPUT: The general unitary group. EXAMPLES:: @@ -279,8 +275,8 @@ def SU(n, R, var='a', invariant_form=None): .. NOTE:: For a finite field the matrices that preserve a sesquilinear - form over `F_q` live over `F_{q^2}`. So ``SU(n,q)`` for - a prime power ``q`` constructs the matrix group over the base + form over `\GF{q}` live over `\GF{q^2}`. So ``SU(n,q)`` for + a prime power `q` constructs the matrix group over the base ring ``GF(q^2)``. .. NOTE:: @@ -396,13 +392,11 @@ def invariant_form(self): Return the hermitian form preserved by the unitary group. - OUTPUT: - - A square matrix describing the bilinear form + OUTPUT: A square matrix describing the bilinear form EXAMPLES:: - sage: SU4 = SU(4,QQ) + sage: SU4 = SU(4, QQ) sage: SU4.invariant_form() [1 0 0 0] [0 1 0 0] diff --git a/src/sage/groups/matrix_gps/unitary_gap.py b/src/sage/groups/matrix_gps/unitary_gap.py index 26c1a8eb82f..02b0456decb 100644 --- a/src/sage/groups/matrix_gps/unitary_gap.py +++ b/src/sage/groups/matrix_gps/unitary_gap.py @@ -46,7 +46,7 @@ def invariant_form(self): EXAMPLES:: - sage: G32=GU(3,2) + sage: G32 = GU(3,2) sage: G32.invariant_form() [0 0 1] [0 1 0] From e15c6e83d98f899a6c2d23bd244f70fd8bd67856 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 16 Apr 2023 10:10:36 -0700 Subject: [PATCH 17/18] src/sage/groups/matrix_gps/matrix_group*.py: Fix up markup of 'generators' --- src/sage/groups/matrix_gps/matrix_group.py | 2 +- src/sage/groups/matrix_gps/matrix_group_gap.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index f9b864f770a..526c86695b0 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -187,7 +187,7 @@ def subgroup(self, generators, check=True): - ``generators`` -- a list/tuple/iterable of group elements of ``self`` - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. - OUTPUT: The subgroup generated by :meth:`generators` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` + OUTPUT: The subgroup generated by ``generators`` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` EXAMPLES:: diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py index 1ec41dfc678..b4c06acbd0f 100644 --- a/src/sage/groups/matrix_gps/matrix_group_gap.py +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -234,7 +234,7 @@ def subgroup(self, generators, check=True): - ``generators`` -- a list/tuple/iterable of group elements of ``self`` - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. - OUTPUT: The subgroup generated by :meth:`generators` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` + OUTPUT: The subgroup generated by ``generators`` as an instance of :class:`FinitelyGeneratedMatrixGroup_gap` EXAMPLES:: From 1024a2378778070e856314130a9f9196d9dd5360 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 16 Apr 2023 19:27:28 -0700 Subject: [PATCH 18/18] src/sage/groups/matrix_gps/orthogonal_gap.py: Add copyright notice based on 'git blame -M -C -w --date=format:%Y FILE.py | sort -k2' --- src/sage/groups/matrix_gps/orthogonal_gap.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/groups/matrix_gps/orthogonal_gap.py b/src/sage/groups/matrix_gps/orthogonal_gap.py index 5e7e4e4611a..17dabb698f2 100644 --- a/src/sage/groups/matrix_gps/orthogonal_gap.py +++ b/src/sage/groups/matrix_gps/orthogonal_gap.py @@ -2,6 +2,21 @@ Orthogonal Linear Groups with GAP """ +# **************************************************************************** +# Copyright (C) 2006 David Joyner and William Stein +# 2009 Mike Hansen +# 2013 Volker Braun +# 2018 Sebastian Oehms +# 2018 Travis Scrimshaw +# 2023 Matthias Koeppe +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.named_group_gap import NamedMatrixGroup_gap from sage.groups.matrix_gps.orthogonal import OrthogonalMatrixGroup_generic