Path: blob/master/src/sage/groups/matrix_gps/matrix_group.py
8815 views
"""1Base classes for Matrix Groups23Loading, saving, ... works::45sage: G = GL(2,5); G6General Linear Group of degree 2 over Finite Field of size 57sage: TestSuite(G).run()89sage: g = G.1; g10[4 1]11[4 0]12sage: TestSuite(g).run()1314We test that :trac:`9437` is fixed::1516sage: len(list(SL(2, Zmod(4))))17481819AUTHORS:2021- William Stein: initial version2223- David Joyner (2006-03-15): degree, base_ring, _contains_, list,24random, order methods; examples2526- William Stein (2006-12): rewrite2728- David Joyner (2007-12): Added invariant_generators (with Martin29Albrecht and Simon King)3031- David Joyner (2008-08): Added module_composition_factors (interface32to GAP's MeatAxe implementation) and as_permutation_group (returns33isomorphic PermutationGroup).3435- Simon King (2010-05): Improve invariant_generators by using GAP36for the construction of the Reynolds operator in Singular.37"""3839##############################################################################40# Copyright (C) 2006 David Joyner and William Stein <[email protected]>41#42# Distributed under the terms of the GNU General Public License (GPL)43#44# The full text of the GPL is available at:45#46# http://www.gnu.org/licenses/47##############################################################################4849from sage.rings.all import ZZ50from sage.rings.integer import is_Integer51from sage.rings.ring import is_Ring52from sage.rings.finite_rings.constructor import is_FiniteField53from sage.interfaces.gap import gap54from sage.matrix.matrix import is_Matrix55from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace56from sage.misc.latex import latex57from sage.structure.sequence import Sequence58from sage.structure.sage_object import SageObject59from sage.misc.decorators import rename_keyword60from sage.misc.cachefunc import cached_method6162from sage.groups.group import Group63from sage.groups.libgap_wrapper import ParentLibGAP64from sage.groups.libgap_mixin import GroupMixinLibGAP6566from sage.groups.matrix_gps.group_element import (67is_MatrixGroupElement, MatrixGroupElement_generic, MatrixGroupElement_gap)6869#################################################################7071def is_MatrixGroup(x):72"""73Test whether ``x`` is a matrix group.7475EXAMPLES::7677sage: from sage.groups.matrix_gps.matrix_group import is_MatrixGroup78sage: is_MatrixGroup(MatrixSpace(QQ,3))79False80sage: is_MatrixGroup(Mat(QQ,3))81False82sage: is_MatrixGroup(GL(2,ZZ))83True84sage: is_MatrixGroup(MatrixGroup([matrix(2,[1,1,0,1])]))85True86"""87return isinstance(x, MatrixGroup_base)8889###################################################################90#91# Base class for all matrix groups92#93###################################################################949596class MatrixGroup_base(Group):97"""98Base class for all matrix groups.99100This base class just holds the base ring, but not the degree. So101it can be a base for affine groups where the natural matrix is102larger than the degree of the affine group. Makes no assumption103about the group except that its elements have a ``matrix()``104method.105"""106107def _check_matrix(self, x, *args):108"""109Check whether the matrix ``x`` defines a group element.110111This is used by the element constructor (if you pass112``check=True``, the default) that the defining matrix is valid113for this parent. Derived classes must override this to verify114that the matrix is, for example, orthogonal or symplectic.115116INPUT:117118- ``x`` -- a Sage matrix in the correct matrix space (degree119and base ring).120121- ``*args`` -- optional other representations of ``x``,122depending on the group implementation. Ignored by default.123124OUTPUT:125126A ``TypeError`` must be raised if ``x`` is invalid.127128EXAMPLES::129130sage: G = SU(2,GF(5))131sage: G._check_matrix(identity_matrix(GF(5),2))132sage: G._check_matrix(matrix(GF(5),[[1,1],[0,1]]))133Traceback (most recent call last):134...135TypeError: matrix must be unitary136"""137if not x.is_invertible():138raise TypeError('matrix is not invertible')139140def as_matrix_group(self):141"""142Return a new matrix group from the generators.143144This will throw away any extra structure (encoded in a derived145class) that a group of special matrices has.146147EXAMPLES::148149sage: G = SU(4,GF(5))150sage: G.as_matrix_group()151Matrix group over Finite Field in a of size 5^2 with 2 generators (152[ a 0 0 0] [ 1 0 4*a + 3 0]153[ 0 2*a + 3 0 0] [ 1 0 0 0]154[ 0 0 4*a + 1 0] [ 0 2*a + 4 0 1]155[ 0 0 0 3*a], [ 0 3*a + 1 0 0]156)157158sage: G = GO(3,GF(5))159sage: G.as_matrix_group()160Matrix group over Finite Field of size 5 with 2 generators (161[2 0 0] [0 1 0]162[0 3 0] [1 4 4]163[0 0 1], [0 2 1]164)165"""166from sage.groups.matrix_gps.finitely_generated import MatrixGroup167return MatrixGroup(self.gens())168169def field_of_definition(self, **kwds):170"""171Return a field that contains all the matrices in this matrix172group.173174EXAMPLES::175176sage: G = SU(3,GF(5))177sage: G.base_ring()178Finite Field in a of size 5^2179sage: G.field_of_definition()180doctest:...: DeprecationWarning: Use base_ring() instead.181See http://trac.sagemath.org/14014 for details.182Finite Field in a of size 5^2183sage: G = GO(4,GF(7),1)184sage: G.field_of_definition()185Finite Field of size 7186sage: G.base_ring()187Finite Field of size 7188"""189from sage.misc.superseded import deprecation190deprecation(14014, 'Use base_ring() instead.')191return self.base_ring()192193def base_field(self):194"""195Deprecated alias of :meth:`base_ring`196197EXAMPLES::198199sage: G = SU(3,GF(5))200sage: G.base_field()201doctest:...: DeprecationWarning: Use base_ring() instead.202See http://trac.sagemath.org/14014 for details.203Finite Field in a of size 5^2204"""205from sage.misc.superseded import deprecation206deprecation(14014, 'Use base_ring() instead.')207return self.base_ring()208209def _repr_(self):210"""211Return a string representation.212213OUTPUT:214215String.216217EXAMPLES::218219sage: F = GF(5); MS = MatrixSpace(F,2,2)220sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[0,1]])]221sage: G = MatrixGroup(gens)222sage: G223Matrix group over Finite Field of size 5 with 2 generators (224[1 2] [1 1]225[4 1], [0 1]226)227"""228if self.ngens() > 5:229return 'Matrix group over {0} with {1} generators'.format(230self.base_ring(), self.ngens())231else:232from sage.misc.displayhook import format_list233return 'Matrix group over {0} with {1} generators {2}'.format(234self.base_ring(), self.ngens(), format_list(self.gens()))235236def _repr_option(self, key):237"""238Metadata about the :meth:`_repr_` output.239240See :meth:`sage.structure.parent._repr_option` for details.241242EXAMPLES::243244sage: SO3 = groups.matrix.SO(3, QQ)245sage: SO3._repr_option('element_ascii_art')246True247"""248if key == 'element_ascii_art':249return True250return super(MatrixGroup_base, self)._repr_option(key)251252def _latex_(self):253r"""254EXAMPLES::255256sage: MS = MatrixSpace(GF(5), 2, 2)257sage: G = MatrixGroup(MS([[1,2],[-1,1]]),MS([[1,1],[0,1]]))258sage: latex(G)259\left\langle \left(\begin{array}{rr}2601 & 2 \\2614 & 1262\end{array}\right), \left(\begin{array}{rr}2631 & 1 \\2640 & 1265\end{array}\right) \right\rangle266"""267gens = ', '.join([latex(x) for x in self.gens()])268return '\\left\\langle %s \\right\\rangle'%gens269270271272###################################################################273#274# Matrix group over a generic ring275#276###################################################################277278class MatrixGroup_generic(MatrixGroup_base):279280Element = MatrixGroupElement_generic281282def __init__(self, degree, base_ring, category=None):283"""284Base class for matrix groups over generic base rings285286You should not use this class directly. Instead, use one of287the more specialized derived classes.288289INPUT:290291- ``degree`` -- integer. The degree (matrix size) of the292matrix group.293294- ``base_ring`` -- ring. The base ring of the matrices.295296TESTS::297298sage: G = GL(2, QQ)299sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic300sage: isinstance(G, MatrixGroup_generic)301True302"""303assert is_Ring(base_ring)304assert is_Integer(degree)305306self._deg = degree307if self._deg <= 0:308raise ValueError('the degree must be at least 1')309310if (category is None) and is_FiniteField(base_ring):311from sage.categories.finite_groups import FiniteGroups312category = FiniteGroups()313super(MatrixGroup_generic, self).__init__(base=base_ring, category=category)314315def degree(self):316"""317Return the degree of this matrix group.318319OUTPUT:320321Integer. The size (number of rows equals number of columns) of322the matrices.323324EXAMPLES::325326sage: SU(5,5).degree()3275328"""329return self._deg330331@cached_method332def matrix_space(self):333"""334Return the matrix space corresponding to this matrix group.335336This is a matrix space over the field of definition of this matrix337group.338339EXAMPLES::340341sage: F = GF(5); MS = MatrixSpace(F,2,2)342sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])343sage: G.matrix_space()344Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5345sage: G.matrix_space() is MS346True347"""348return MatrixSpace(self.base_ring(), self.degree())349350def _cmp_generators(self, other):351"""352Implement comparison353354We treat two matrix groups as equal if their generators are355the same in the same order. Infinitely-generated groups are356compared by identity.357358INPUT:359360- ``other`` -- anything.361362OUTPUT:363364``-1``, ``0``, or ``+1``.365366EXAMPLES::367368sage: G = GL(2,3)369sage: H = MatrixGroup(G.gens())370sage: G._cmp_generators(H)3710372sage: cmp(G,H)3730374sage: cmp(H,G)3750376sage: G == H377True378"""379if not is_MatrixGroup(other):380return cmp(type(self), type(other))381c = cmp(self.matrix_space(), other.matrix_space())382if c != 0:383return c384385def identity_cmp():386return cmp(id(self), id(other))387388# compare number of generators389try:390n_self = self.ngens()391n_other = other.ngens()392except (AttributeError, NotImplementedError):393return identity_cmp()394c = cmp(n_self, n_other)395if c != 0:396return c397from sage.structure.element import is_InfinityElement398if is_InfinityElement(n_self) or is_InfinityElement(n_other):399return identity_cmp()400401# compacte generator matrices402try:403self_gens = self.gens()404other_gens = other.gens()405except (AttributeError, NotImplementedError):406return identity_cmp()407assert(n_self == n_other)408for g,h in zip(self_gens, other_gens):409c = cmp(g.matrix(), h.matrix())410if c != 0:411return c412return c413414def __cmp__(self, other):415"""416Implement comparison417418EXAMPLES::419420sage: MS = MatrixSpace(SR, 2, 2)421sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])422sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic423sage: MatrixGroup_generic.__cmp__(G, G)4240425sage: cmp(G,G)4260427sage: cmp(G, MatrixGroup(G.gens()))4280429sage: G == MatrixGroup(G.gens())430True431"""432return self._cmp_generators(other)433434def _Hom_(self, G, cat=None):435"""436Construct a homset.437438INPUT:439440- ``G`` -- group. The codomain.441442- ``cat`` -- a category. Must be unset.443444OUTPUT:445446The set of homomorphisms from ``self`` to ``G``.447448EXAMPLES::449450sage: MS = MatrixSpace(SR, 2, 2)451sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])452sage: G.Hom(G)453Set of Homomorphisms from Matrix group over Symbolic Ring with 2 generators (454[1 0] [1 2]455[0 1], [3 4]456) to Matrix group over Symbolic Ring with 2 generators (457[1 0] [1 2]458[0 1], [3 4]459)460"""461if not (cat is None or (cat is G.category() and cat is self.category())):462raise TypeError463if not is_MatrixGroup(G):464raise TypeError, "G (=%s) must be a matrix group."%G465import homset466return homset.MatrixGroupHomset(self, G)467468def hom(self, x):469"""470Return the group homomorphism defined by ``x``471472INPUT:473474- ``x`` -- a list/tuple/iterable of matrix group elements.475476OUTPUT:477478The group homomorphism defined by ``x``.479480EXAMPLES::481482sage: G = MatrixGroup([matrix(GF(5), [[1,3],[0,1]])])483sage: H = MatrixGroup([matrix(GF(5), [[1,2],[0,1]])])484sage: G.hom([H.gen(0)])485Homomorphism : Matrix group over Finite Field of size 5 with 1 generators (486[1 3]487[0 1]488) --> Matrix group over Finite Field of size 5 with 1 generators (489[1 2]490[0 1]491)492"""493v = Sequence(x)494U = v.universe()495if not is_MatrixGroup(U):496raise TypeError, "u (=%s) must have universe a matrix group."%U497return self.Hom(U)(x)498499500501###################################################################502#503# Matrix group over a ring that GAP understands504#505###################################################################506507class MatrixGroup_gap(GroupMixinLibGAP, MatrixGroup_generic, ParentLibGAP):508509Element = MatrixGroupElement_gap510511def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None):512"""513Base class for matrix groups that implements GAP interface.514515INPUT:516517- ``degree`` -- integer. The degree (matrix size) of the518matrix group.519520- ``base_ring`` -- ring. The base ring of the matrices.521522- ``libgap_group`` -- the defining libgap group.523524- ``ambient`` -- A derived class of :class:`ParentLibGAP` or525``None`` (default). The ambient class if ``libgap_group``526has been defined as a subgroup.527528TESTS::529530sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_gap531sage: MatrixGroup_gap(2, ZZ, libgap.eval('GL(2, Integers)'))532Matrix group over Integer Ring with 3 generators (533[0 1] [-1 0] [1 1]534[1 0], [ 0 1], [0 1]535)536"""537ParentLibGAP.__init__(self, libgap_group, ambient=ambient)538MatrixGroup_generic.__init__(self, degree, base_ring, category=category)539540def _check_matrix(self, x_sage, x_gap):541"""542Check whether the matrix ``x`` defines a group element.543544This is used by the element constructor (if you pass545``check=True``, the default) that the defining matrix is valid546for this parent. Derived classes must override this to verify547that the matrix is, for example, orthogonal or symplectic.548549INPUT:550551- ``x_sage`` -- a Sage matrix in the correct matrix space (degree552and base ring).553554- ``x_gap`` -- the corresponding LibGAP matrix.555556OUTPUT:557558A ``TypeError`` must be raised if ``x`` is invalid.559560EXAMPLES::561562sage: m1 = matrix(GF(11), [(0, -1), (1, 0)])563sage: m2 = matrix(GF(11), [(0, -1), (1, -1)])564sage: G = MatrixGroup([m1, m2])565sage: G([1,2,0,1])566[1 2]567[0 1]568sage: G([1,1,1,0])569Traceback (most recent call last):570...571TypeError: matrix is not in the finitely generated group572"""573from sage.libs.gap.libgap import libgap574libgap_contains = libgap.eval('\in')575is_contained = libgap_contains(x_gap, self.gap())576if not is_contained.sage():577raise TypeError('matrix is not in the finitely generated group')578579def _subgroup_constructor(self, libgap_subgroup):580"""581Return a finitely generated subgroup.582583See584:meth:`sage.groups.libgap_wrapper.ParentLibGAP._subgroup_constructor`585for details.586587TESTS::588589sage: SL2Z = SL(2,ZZ)590sage: S, T = SL2Z.gens()591sage: G = SL2Z.subgroup([T^2]); G # indirect doctest592Matrix group over Integer Ring with 1 generators (593[1 2]594[0 1]595)596sage: G.ambient() is SL2Z597True598"""599from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap600return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(),601libgap_subgroup, ambient=self)602603def __iter__(self):604"""605Iterate over the elements of the group.606607This method overrides the matrix group enumerator in GAP which608is very slow, see http://tracker.gap-system.org/issues/369.609610EXAMPLES::611612sage: i = iter(GL(6,5))613sage: [ i.next() for j in range(8) ]614[615[1 0 0 0 0 0] [4 0 0 0 0 1] [0 4 0 0 0 0] [0 4 0 0 0 0]616[0 1 0 0 0 0] [4 0 0 0 0 0] [0 0 4 0 0 0] [0 0 4 0 0 0]617[0 0 1 0 0 0] [0 4 0 0 0 0] [0 0 0 4 0 0] [0 0 0 4 0 0]618[0 0 0 1 0 0] [0 0 4 0 0 0] [0 0 0 0 4 0] [0 0 0 0 4 0]619[0 0 0 0 1 0] [0 0 0 4 0 0] [0 0 0 0 0 4] [0 0 0 0 0 4]620[0 0 0 0 0 1], [0 0 0 0 4 0], [1 4 0 0 0 0], [2 4 0 0 0 0],621<BLANKLINE>622[3 0 0 0 0 1] [4 0 0 1 3 3] [0 0 0 2 0 0] [1 0 0 0 4 4]623[3 0 0 0 0 0] [4 0 0 0 3 3] [0 0 0 0 4 0] [1 0 0 0 0 4]624[0 4 0 0 0 0] [3 0 0 0 0 1] [2 2 0 0 0 2] [1 0 0 0 0 0]625[0 0 4 0 0 0] [3 0 0 0 0 0] [1 4 0 0 0 0] [0 1 0 0 0 0]626[0 0 0 4 0 0] [0 4 0 0 0 0] [0 2 4 0 0 0] [0 0 1 0 0 0]627[4 0 0 0 2 3], [2 0 3 4 4 4], [0 0 1 4 0 0], [0 0 0 1 0 0]628]629630This is the direct computation in GAP, which will just run631(almost) forever. If you find that this works then the632``MatrixGroup_gap.__iter__`` and ``MatrixGroup_gap.list``633methods can be removed::634635sage: G = GL(6,5).gap()636sage: G.Enumerator() # not tested637sage: G.Iterator() # not tested638"""639if not self.is_finite():640# use implementation from category framework641for g in super(Group, self).__iter__():642yield g643return644# Use the standard GAP iterator for small groups645if self.cardinality() < 1000:646for g in super(MatrixGroup_gap, self).__iter__():647yield g648return649# Override for large but finite groups650iso = self.gap().IsomorphismPermGroup()651P = iso.Image()652iterator = P.Iterator()653while not iterator.IsDoneIterator().sage():654p = iterator.NextIterator()655g = iso.PreImageElm(p)656yield self(g, check=False)657658@cached_method659def list(self):660"""661List all elements of this group.662663This method overrides the matrix group enumerator in GAP which664is very slow, see http://tracker.gap-system.org/issues/369.665666OUTPUT:667668A tuple containing all group elements in a random but fixed669order.670671EXAMPLES::672673sage: F = GF(3)674sage: gens = [matrix(F,2, [1,0, -1,1]), matrix(F, 2, [1,1,0,1])]675sage: G = MatrixGroup(gens)676sage: G.cardinality()67724678sage: v = G.list()679sage: len(v)68024681sage: v[:5]682(683[0 1] [0 1] [0 1] [0 2] [0 2]684[2 0], [2 1], [2 2], [1 0], [1 1]685)686sage: all(g in G for g in G.list())687True688689An example over a ring (see trac 5241)::690691sage: M1 = matrix(ZZ,2,[[-1,0],[0,1]])692sage: M2 = matrix(ZZ,2,[[1,0],[0,-1]])693sage: M3 = matrix(ZZ,2,[[-1,0],[0,-1]])694sage: MG = MatrixGroup([M1, M2, M3])695sage: MG.list()696(697[-1 0] [-1 0] [ 1 0] [1 0]698[ 0 -1], [ 0 1], [ 0 -1], [0 1]699)700sage: MG.list()[1]701[-1 0]702[ 0 1]703sage: MG.list()[1].parent()704Matrix group over Integer Ring with 3 generators (705[-1 0] [ 1 0] [-1 0]706[ 0 1], [ 0 -1], [ 0 -1]707)708709An example over a field (see trac 10515)::710711sage: gens = [matrix(QQ,2,[1,0,0,1])]712sage: MatrixGroup(gens).list()713(714[1 0]715[0 1]716)717718Another example over a ring (see trac 9437)::719720sage: len(SL(2, Zmod(4)).list())72148722723An error is raised if the group is not finite::724725sage: GL(2,ZZ).list()726Traceback (most recent call last):727...728NotImplementedError: group must be finite729"""730if not self.is_finite():731raise NotImplementedError('group must be finite')732return tuple(iter(self))733734735