Path: blob/master/src/sage/groups/matrix_gps/finitely_generated.py
8815 views
"""1Finitely Generated Matrix Groups23This class is designed for computing with matrix groups defined by a4finite set of generating matrices.56EXAMPLES::78sage: F = GF(3)9sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F,2, [1,1,0,1])]10sage: G = MatrixGroup(gens)11sage: G.conjugacy_class_representatives()12(13[1 0] [0 1] [0 1] [0 2] [0 2] [0 1] [2 0]14[0 1], [2 1], [2 2], [1 1], [1 2], [2 0], [0 2]15)1617The finitely generated matrix groups can also be constructed as18subgroups of matrix groups::1920sage: SL2Z = SL(2,ZZ)21sage: S, T = SL2Z.gens()22sage: SL2Z.subgroup([T^2])23Matrix group over Integer Ring with 1 generators (24[1 2]25[0 1]26)2728AUTHORS:2930- William Stein: initial version3132- David Joyner (2006-03-15): degree, base_ring, _contains_, list,33random, order methods; examples3435- William Stein (2006-12): rewrite3637- David Joyner (2007-12): Added invariant_generators (with Martin38Albrecht and Simon King)3940- David Joyner (2008-08): Added module_composition_factors (interface41to GAP's MeatAxe implementation) and as_permutation_group (returns42isomorphic PermutationGroup).4344- Simon King (2010-05): Improve invariant_generators by using GAP45for the construction of the Reynolds operator in Singular.4647- Volker Braun (2013-1) port to new Parent, libGAP.48"""4950##############################################################################51# Copyright (C) 2006 David Joyner and William Stein <[email protected]>52# Copyright (C) 2013 Volker Braun <[email protected]>53#54# Distributed under the terms of the GNU General Public License (GPL)55#56# The full text of the GPL is available at:57#58# http://www.gnu.org/licenses/59##############################################################################6061from sage.groups.group import Group62from sage.rings.all import ZZ63from sage.rings.integer import is_Integer64from sage.rings.ring import is_Ring65from sage.rings.finite_rings.constructor import is_FiniteField66from sage.interfaces.gap import gap67from sage.matrix.matrix import is_Matrix68from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace69from sage.matrix.all import matrix70from sage.misc.latex import latex71from sage.structure.sequence import Sequence72from sage.misc.cachefunc import cached_method7374from sage.groups.matrix_gps.matrix_group import (75is_MatrixGroup, MatrixGroup_generic, MatrixGroup_gap )76from sage.groups.matrix_gps.group_element import (77is_MatrixGroupElement, MatrixGroupElement_generic, MatrixGroupElement_gap)7879808182def normalize_square_matrices(matrices):83"""84Find a common space for all matrices.8586OUTPUT:8788A list of matrices, all elements of the same matrix space.8990EXAMPLES::9192sage: from sage.groups.matrix_gps.finitely_generated import normalize_square_matrices93sage: m1 = [[1,2],[3,4]]94sage: m2 = [2, 3, 4, 5]95sage: m3 = matrix(QQ, [[1/2,1/3],[1/4,1/5]])96sage: m4 = MatrixGroup(m3).gen(0)97sage: normalize_square_matrices([m1, m2, m3, m4])98[99[1 2] [2 3] [1/2 1/3] [1/2 1/3]100[3 4], [4 5], [1/4 1/5], [1/4 1/5]101]102"""103deg = []104gens = []105for m in matrices:106if is_MatrixGroupElement(m):107deg.append(m.parent().degree())108gens.append(m.matrix())109continue110if is_Matrix(m):111if not m.is_square():112raise TypeError('matrix must be square')113deg.append(m.ncols())114gens.append(m)115continue116try:117m = list(m)118except TypeError:119gens.append(m)120continue121if isinstance(m[0], (list, tuple)):122m = map(list, m)123degree = ZZ(len(m))124else:125degree, rem = ZZ(len(m)).sqrtrem()126if rem!=0:127raise ValueError('list of plain numbers must have square integer length')128deg.append(degree)129gens.append(matrix(degree, degree, m))130deg = set(deg)131if len(set(deg)) != 1:132raise ValueError('not all matrices have the same size')133gens = Sequence(gens, immutable=True)134MS = gens.universe()135if not is_MatrixSpace(MS):136raise TypeError('all generators must be matrices')137if MS.nrows() != MS.ncols():138raise ValueError('matrices must be square')139return gens140141def QuaternionMatrixGroupGF3():142r"""143The quaternion group as a set of `2\times 2` matrices over `GF(3)`.144145OUTPUT:146147A matrix group consisting of `2\times 2` matrices with148elements from the finite field of order 3. The group is149the quaternion group, the nonabelian group of order 8 that150is not isomorphic to the group of symmetries of a square151(the dihedral group `D_4`).152153.. note::154This group is most easily available via ``groups.matrix.QuaternionGF3()``.155156EXAMPLES:157158The generators are the matrix representations of the159elements commonly called `I` and `J`, while `K`160is the product of `I` and `J`. ::161162sage: from sage.groups.matrix_gps.finitely_generated import QuaternionMatrixGroupGF3163sage: Q = QuaternionMatrixGroupGF3()164sage: Q.order()1658166sage: aye = Q.gens()[0]; aye167[1 1]168[1 2]169sage: jay = Q.gens()[1]; jay170[2 1]171[1 1]172sage: kay = aye*jay; kay173[0 2]174[1 0]175176TESTS::177178sage: groups.matrix.QuaternionGF3()179Matrix group over Finite Field of size 3 with 2 generators (180[1 1] [2 1]181[1 2], [1 1]182)183184sage: Q = QuaternionMatrixGroupGF3()185sage: QP = Q.as_permutation_group()186sage: QP.is_isomorphic(QuaternionGroup())187True188sage: H = DihedralGroup(4)189sage: H.order()1908191sage: QP.is_abelian(), H.is_abelian()192(False, False)193sage: QP.is_isomorphic(H)194False195"""196from sage.rings.finite_rings.constructor import FiniteField197from sage.matrix.matrix_space import MatrixSpace198MS = MatrixSpace(FiniteField(3), 2)199aye = MS([1,1,1,2])200jay = MS([2,1,1,1])201return MatrixGroup([aye, jay])202203def MatrixGroup(*gens, **kwds):204r"""205Return the matrix group with given generators.206207INPUT:208209- ``*gens`` -- matrices, or a single list/tuple/iterable of210matrices, or a matrix group.211212- ``check`` -- boolean keyword argument (optional, default:213``True``). Whether to check that each matrix is invertible.214215EXAMPLES::216217sage: F = GF(5)218sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])]219sage: G = MatrixGroup(gens); G220Matrix group over Finite Field of size 5 with 2 generators (221[1 2] [1 1]222[4 1], [0 1]223)224225In the second example, the generators are a matrix over226`\ZZ`, a matrix over a finite field, and the integer227`2`. Sage determines that they both canonically map to228matrices over the finite field, so creates that matrix group229there::230231sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2]232sage: G = MatrixGroup(gens); G233Matrix group over Finite Field of size 7 with 3 generators (234[1 2] [1 1] [2 0]235[6 1], [0 1], [0 2]236)237238Each generator must be invertible::239240sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])])241Traceback (most recent call last):242...243ValueError: each generator must be an invertible matrix244245sage: F = GF(5); MS = MatrixSpace(F,2,2)246sage: MatrixGroup([MS.0])247Traceback (most recent call last):248...249ValueError: each generator must be an invertible matrix250sage: MatrixGroup([MS.0], check=False) # works formally but is mathematical nonsense251Matrix group over Finite Field of size 5 with 1 generators (252[1 0]253[0 0]254)255256Some groups are not supported, or do not have much functionality257implemented::258259sage: G = SL(0, QQ)260Traceback (most recent call last):261...262ValueError: the degree must be at least 1263264sage: SL2C = SL(2, CC); SL2C265Special Linear Group of degree 2 over Complex Field with 53 bits of precision266sage: SL2C.gens()267Traceback (most recent call last):268...269AttributeError: 'LinearMatrixGroup_generic_with_category' object has no attribute 'gens'270"""271if isinstance(gens[-1], dict): # hack for unpickling272kwds.update(gens[-1])273gens = gens[:-1]274check = kwds.get('check', True)275if len(gens) == 1:276if isinstance(gens[0], (list, tuple)):277gens = list(gens[0])278else:279try:280gens = [g.matrix() for g in gens[0]]281except AttributeError:282pass283if len(gens) == 0:284raise ValueError('need at least one generator')285gens = normalize_square_matrices(gens)286if check and any(not g.is_invertible() for g in gens):287raise ValueError('each generator must be an invertible matrix')288MS = gens.universe()289base_ring = MS.base_ring()290degree = ZZ(MS.ncols()) # == MS.nrows()291from sage.libs.gap.libgap import libgap292try:293gap_gens = [libgap(matrix_gen) for matrix_gen in gens]294gap_group = libgap.Group(gap_gens)295return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group)296except (TypeError, ValueError):297return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens)298299###################################################################300#301# Matrix group over a generic ring302#303###################################################################304305class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic):306307def __init__(self, degree, base_ring, generator_matrices, category=None):308"""309Matrix group generated by a finite number of matrices.310311EXAMPLES::312313sage: m1 = matrix(SR, [[1,2],[3,4]])314sage: m2 = matrix(SR, [[1,3],[-1,0]])315sage: G = MatrixGroup(m1, m2)316sage: TestSuite(G).run()317sage: type(G)318<class 'sage.groups.matrix_gps.finitely_generated.FinitelyGeneratedMatrixGroup_generic_with_category'>319320sage: from sage.groups.matrix_gps.finitely_generated import \321....: FinitelyGeneratedMatrixGroup_generic322sage: G = FinitelyGeneratedMatrixGroup_generic(2, QQ, [matrix(QQ,[[1,2],[3,4]])])323sage: G.gens()324(325[1 2]326[3 4]327)328"""329self._gens_matrix = generator_matrices330MatrixGroup_generic.__init__(self, degree, base_ring, category=category)331332def __cmp__(self, other):333"""334Implement comparison.335336EXAMPLES::337338sage: m1 = matrix(SR, [[1,2],[3,4]])339sage: m2 = matrix(SR, [[1,3],[-1,0]])340sage: cmp(MatrixGroup(m1), MatrixGroup(m1))3410342sage: abs(cmp(MatrixGroup(m1), MatrixGroup(m1.change_ring(QQ))))3431344sage: abs(cmp(MatrixGroup(m1), MatrixGroup(m2)))3451346sage: abs(cmp(MatrixGroup(m1, m2), MatrixGroup(m2, m1)))3471348"""349c = super(FinitelyGeneratedMatrixGroup_generic, self).__cmp__(other)350if c != 0:351return c352return cmp(self._gens_matrix, other._gens_matrix)353354@cached_method355def gens(self):356"""357Return the generators of the matrix group.358359EXAMPLES::360361sage: F = GF(3); MS = MatrixSpace(F,2,2)362sage: gens = [MS([[1,0],[0,1]]), MS([[1,1],[0,1]])]363sage: G = MatrixGroup(gens)364sage: gens[0] in G365True366sage: gens = G.gens()367sage: gens[0] in G368True369sage: gens = [MS([[1,0],[0,1]]),MS([[1,1],[0,1]])]370371sage: F = GF(5); MS = MatrixSpace(F,2,2)372sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])373sage: G374Matrix group over Finite Field of size 5 with 2 generators (375[1 0] [1 2]376[0 1], [3 4]377)378sage: G.gens()379(380[1 0] [1 2]381[0 1], [3 4]382)383"""384return tuple(self.element_class(self, x, check=False, convert=False)385for x in self._gens_matrix)386387def gen(self, i):388"""389Return the `i`-th generator390391OUTPUT:392393The `i`-th generator of the group.394395EXAMPLES::396397sage: H = GL(2, GF(3))398sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]])399sage: G = H.subgroup([h1, h2])400sage: G.gen(0)401[1 0]402[2 1]403sage: G.gen(0).matrix() == h1.matrix()404True405"""406return self.gens()[i]407408def ngens(self):409"""410Return the number of generators411412OUTPUT:413414An integer. The number of generators.415416EXAMPLES::417418sage: H = GL(2, GF(3))419sage: h1, h2 = H([[1,0],[2,1]]), H([[1,1],[0,1]])420sage: G = H.subgroup([h1, h2])421sage: G.ngens()4222423"""424return len(self._gens_matrix)425426def _test_matrix_generators(self, **options):427"""428EXAMPLES::429430sage: m1 = matrix(SR, [[1,2],[3,4]])431sage: m2 = matrix(SR, [[1,3],[-1,0]])432sage: G = MatrixGroup(m1, m2)433sage: G._test_matrix_generators()434"""435tester = self._tester(**options)436for g,h in zip(self.gens(), MatrixGroup(self.gens()).gens()):437tester.assertEqual(g.matrix(), h.matrix())438439###################################################################440#441# Matrix group over a ring that GAP understands442#443###################################################################444445class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap):446"""447Matrix group generated by a finite number of matrices.448449EXAMPLES::450451sage: m1 = matrix(GF(11), [[1,2],[3,4]])452sage: m2 = matrix(GF(11), [[1,3],[10,0]])453sage: G = MatrixGroup(m1, m2); G454Matrix group over Finite Field of size 11 with 2 generators (455[1 2] [ 1 3]456[3 4], [10 0]457)458sage: type(G)459<class 'sage.groups.matrix_gps.finitely_generated.FinitelyGeneratedMatrixGroup_gap_with_category'>460sage: TestSuite(G).run()461"""462463def __reduce__(self):464"""465Implement pickling.466467EXAMPLES::468469sage: m1 = matrix(QQ, [[1,2],[3,4]])470sage: m2 = matrix(QQ, [[1,3],[-1,0]])471sage: loads(MatrixGroup(m1, m2).dumps())472Matrix group over Rational Field with 2 generators (473[1 2] [ 1 3]474[3 4], [-1 0]475)476"""477return (MatrixGroup,478tuple(g.matrix() for g in self.gens()) + ({'check':False},))479480def __cmp__(self, other):481"""482Implement comparison.483484EXAMPLES::485486sage: m1 = matrix(QQ, [[1,2],[3,4]])487sage: m2 = matrix(QQ, [[1,3],[-1,0]])488sage: cmp(MatrixGroup(m1), MatrixGroup(m1))4890490sage: abs(cmp(MatrixGroup(m1), MatrixGroup(m2)))4911492sage: abs(cmp(MatrixGroup(m1, m2), MatrixGroup(m2, m1)))4931494495sage: G = GL(2, GF(3))496sage: H = G.as_matrix_group()497sage: cmp(H, G), cmp(G, H)498(0, 0)499sage: H == G, G == H500(True, True)501"""502c = super(FinitelyGeneratedMatrixGroup_gap, self).__cmp__(other)503if c != 0:504return c505try:506other_ngens = other.ngens507other_gen = other.gen508except AttributeError:509return 1510n = self.ngens()511m = other_ngens()512if n != m:513return cmp(n, m)514for i in range(n):515g = self.gen(i)516h = other_gen(i)517c = cmp(g.gap(), h.gap())518if c != 0:519return c520return 0521522def as_permutation_group(self, algorithm=None):523r"""524Return a permutation group representation for the group.525526In most cases occurring in practice, this is a permutation527group of minimal degree (the degree begin determined from528orbits under the group action). When these orbits are hard to529compute, the procedure can be time-consuming and the degree530may not be minimal.531532INPUT:533534- ``algorithm`` -- ``None`` or ``'smaller'``. In the latter535case, try harder to find a permutation representation of536small degree.537538OUTPUT:539540A permutation group isomorphic to ``self``. The541``algorithm='smaller'`` option tries to return an isomorphic542group of low degree, but is not guaranteed to find the543smallest one.544545EXAMPLES::546547sage: MS = MatrixSpace(GF(2), 5, 5)548sage: 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]])549sage: G = MatrixGroup([A])550sage: G.as_permutation_group()551Permutation Group with generators [(1,2)]552sage: MS = MatrixSpace( GF(7), 12, 12)553sage: GG = gap("ImfMatrixGroup( 12, 3 )")554sage: GG.GeneratorsOfGroup().Length()5553556sage: g1 = MS(eval(str(GG.GeneratorsOfGroup()[1]).replace("\n","")))557sage: g2 = MS(eval(str(GG.GeneratorsOfGroup()[2]).replace("\n","")))558sage: g3 = MS(eval(str(GG.GeneratorsOfGroup()[3]).replace("\n","")))559sage: G = MatrixGroup([g1, g2, g3])560sage: G.cardinality()56121499084800562sage: set_random_seed(0); current_randstate().set_seed_gap()563sage: P = G.as_permutation_group()564sage: P.cardinality()56521499084800566sage: P.degree() # random output567144568sage: set_random_seed(3); current_randstate().set_seed_gap()569sage: Psmaller = G.as_permutation_group(algorithm="smaller")570sage: Psmaller.cardinality()57121499084800572sage: Psmaller.degree() # random output573108574575In this case, the "smaller" option returned an isomorphic group of576lower degree. The above example used GAP's library of irreducible577maximal finite ("imf") integer matrix groups to construct the578MatrixGroup G over GF(7). The section "Irreducible Maximal Finite579Integral Matrix Groups" in the GAP reference manual has more580details.581"""582# Note that the output of IsomorphismPermGroup() depends on583# memory locations and will change if you change the order of584# doctests and/or architecture585from sage.groups.perm_gps.permgroup import PermutationGroup586if not self.is_finite():587raise NotImplementedError, "Group must be finite."588n = self.degree()589MS = MatrixSpace(self.base_ring(), n, n)590mats = [] # initializing list of mats by which the gens act on self591for g in self.gens():592p = MS(g.matrix())593m = p.rows()594mats.append(m)595mats_str = str(gap([[list(r) for r in m] for m in mats]))596gap.eval("iso:=IsomorphismPermGroup(Group("+mats_str+"))")597if algorithm == "smaller":598gap.eval("small:= SmallerDegreePermutationRepresentation( Image( iso ) );")599C = gap("Image( small )")600else:601C = gap("Image( iso )")602return PermutationGroup(gap_group=C)603604def module_composition_factors(self, algorithm=None):605r"""606Return a list of triples consisting of [base field, dimension,607irreducibility], for each of the Meataxe composition factors608modules. The ``algorithm="verbose"`` option returns more information,609but in Meataxe notation.610611EXAMPLES::612613sage: F=GF(3);MS=MatrixSpace(F,4,4)614sage: M=MS(0)615sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1616sage: G = MatrixGroup([M])617sage: G.module_composition_factors()618[(Finite Field of size 3, 1, True),619(Finite Field of size 3, 1, True),620(Finite Field of size 3, 2, True)]621sage: F = GF(7); MS = MatrixSpace(F,2,2)622sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]623sage: G = MatrixGroup(gens)624sage: G.module_composition_factors()625[(Finite Field of size 7, 2, True)]626627Type ``G.module_composition_factors(algorithm='verbose')`` to get a628more verbose version.629630For more on MeatAxe notation, see631http://www.gap-system.org/Manuals/doc/ref/chap69.html632"""633from sage.misc.sage_eval import sage_eval634F = self.base_ring()635if not(F.is_finite()):636raise NotImplementedError, "Base ring must be finite."637q = F.cardinality()638gens = self.gens()639n = self.degree()640MS = MatrixSpace(F,n,n)641mats = [] # initializing list of mats by which the gens act on self642W = self.matrix_space().row_space()643for g in gens:644p = MS(g.matrix())645m = p.rows()646mats.append(m)647mats_str = str(gap([[list(r) for r in m] for m in mats]))648gap.eval("M:=GModuleByMats("+mats_str+", GF("+str(q)+"))")649gap.eval("MCFs := MTX.CompositionFactors( M )")650N = eval(gap.eval("Length(MCFs)"))651if algorithm == "verbose":652print gap.eval('MCFs')+"\n"653L = []654for i in range(1,N+1):655gap.eval("MCF := MCFs[%s]"%i)656L.append(tuple([sage_eval(gap.eval("MCF.field")),657eval(gap.eval("MCF.dimension")),658sage_eval(gap.eval("MCF.IsIrreducible")) ]))659return sorted(L)660661def invariant_generators(self):662r"""663Return invariant ring generators.664665Computes generators for the polynomial ring666`F[x_1,\ldots,x_n]^G`, where `G` in `GL(n,F)` is a finite matrix667group.668669In the "good characteristic" case the polynomials returned670form a minimal generating set for the algebra of `G`-invariant671polynomials. In the "bad" case, the polynomials returned672are primary and secondary invariants, forming a not673necessarily minimal generating set for the algebra of674`G`-invariant polynomials.675676ALGORITHM:677678Wraps Singular's ``invariant_algebra_reynolds`` and ``invariant_ring``679in ``finvar.lib``.680681EXAMPLES::682683sage: F = GF(7); MS = MatrixSpace(F,2,2)684sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]685sage: G = MatrixGroup(gens)686sage: G.invariant_generators()687[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]688sage: q = 4; a = 2689sage: MS = MatrixSpace(QQ, 2, 2)690sage: gen1 = [[1/a,(q-1)/a],[1/a, -1/a]]; gen2 = [[1,0],[0,-1]]; gen3 = [[-1,0],[0,1]]691sage: G = MatrixGroup([MS(gen1),MS(gen2),MS(gen3)])692sage: G.cardinality()69312694sage: G.invariant_generators()695[x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6]696sage: F = GF(5); MS = MatrixSpace(F,2,2)697sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[-1,1]])]698sage: G = MatrixGroup(gens)699sage: G.invariant_generators() # long time (67s on sage.math, 2012)700[x1^20 + x1^16*x2^4 + x1^12*x2^8 + x1^8*x2^12 + x1^4*x2^16 + x2^20, x1^20*x2^4 + x1^16*x2^8 + x1^12*x2^12 + x1^8*x2^16 + x1^4*x2^20]701sage: F=CyclotomicField(8)702sage: z=F.gen()703sage: a=z+1/z704sage: b=z^2705sage: MS=MatrixSpace(F,2,2)706sage: g1=MS([[1/a,1/a],[1/a,-1/a]])707sage: g2=MS([[1,0],[0,b]])708sage: g3=MS([[b,0],[0,1]])709sage: G=MatrixGroup([g1,g2,g3])710sage: G.invariant_generators() # long time (12s on sage.math, 2011)711[x1^8 + 14*x1^4*x2^4 + x2^8,712x1^24 + 10626/1025*x1^20*x2^4 + 735471/1025*x1^16*x2^8 + 2704156/1025*x1^12*x2^12 + 735471/1025*x1^8*x2^16 + 10626/1025*x1^4*x2^20 + x2^24]713714AUTHORS:715716- David Joyner, Simon King and Martin Albrecht.717718REFERENCES:719720- Singular reference manual721722- B. Sturmfels, "Algorithms in invariant theory", Springer-Verlag,7231993.724725- S. King, "Minimal Generating Sets of non-modular invariant726rings of finite groups", :arxiv:`math/0703035`.727"""728from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing729from sage.interfaces.singular import singular730gens = self.gens()731singular.LIB("finvar.lib")732n = self.degree() #len((gens[0].matrix()).rows())733F = self.base_ring()734q = F.characteristic()735## test if the field is admissible736if F.gen()==1: # we got the rationals or GF(prime)737FieldStr = str(F.characteristic())738elif hasattr(F,'polynomial'): # we got an algebraic extension739if len(F.gens())>1:740raise NotImplementedError("can only deal with finite fields and (simple algebraic extensions of) the rationals")741FieldStr = '(%d,%s)'%(F.characteristic(),str(F.gen()))742else: # we have a transcendental extension743FieldStr = '(%d,%s)'%(F.characteristic(),','.join([str(p) for p in F.gens()]))744745## Setting Singular's variable names746## We need to make sure that field generator and variables get different names.747if str(F.gen())[0]=='x':748VarStr = 'y'749else:750VarStr = 'x'751VarNames='('+','.join((VarStr+str(i+1) for i in range(n)))+')'752R=singular.ring(FieldStr,VarNames,'dp')753if hasattr(F,'polynomial') and F.gen()!=1: # we have to define minpoly754singular.eval('minpoly = '+str(F.polynomial()).replace('x',str(F.gen())))755A = [singular.matrix(n,n,str((x.matrix()).list())) for x in gens]756Lgens = ','.join((x.name() for x in A))757PR = PolynomialRing(F,n,[VarStr+str(i) for i in range(1,n+1)])758759if q == 0 or (q > 0 and self.cardinality()%q != 0):760from sage.all import Integer, Matrix761try:762elements = [ g.matrix() for g in self.list() ]763except (TypeError,ValueError):764elements765if elements is not None:766ReyName = 't'+singular._next_var_name()767singular.eval('matrix %s[%d][%d]'%(ReyName,self.cardinality(),n))768for i in range(1,self.cardinality()+1):769M = Matrix(elements[i-1],F)770D = [{} for foobar in range(self.degree())]771for x,y in M.dict().items():772D[x[0]][x[1]] = y773for row in range(self.degree()):774for t in D[row].items():775singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)'776%(ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1))777foobar = singular(ReyName)778IRName = 't'+singular._next_var_name()779singular.eval('matrix %s = invariant_algebra_reynolds(%s)'%(IRName,ReyName))780else:781ReyName = 't'+singular._next_var_name()782singular.eval('list %s=group_reynolds((%s))'%(ReyName,Lgens))783IRName = 't'+singular._next_var_name()784singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])'%(IRName,ReyName))785786OUT = [singular.eval(IRName+'[1,%d]'%(j))787for j in range(1,1+singular('ncols('+IRName+')'))]788return [PR(gen) for gen in OUT]789if self.cardinality()%q == 0:790PName = 't'+singular._next_var_name()791SName = 't'+singular._next_var_name()792singular.eval('matrix %s,%s=invariant_ring(%s)'%(PName,SName,Lgens))793OUT = [794singular.eval(PName+'[1,%d]'%(j))795for j in range(1,1+singular('ncols('+PName+')'))796] + [797singular.eval(SName+'[1,%d]'%(j)) for j in range(2,1+singular('ncols('+SName+')'))798]799return [PR(gen) for gen in OUT]800801802803