Path: blob/master/src/sage/groups/affine_gps/group_element.py
8815 views
"""1Elements of Affine Groups23The class in this module is used to represent the elements of4:func:`~sage.groups.affine_gps.affine_group.AffineGroup` and its5subgroups.67EXAMPLES::89sage: F = AffineGroup(3, QQ)10sage: F([1,2,3,4,5,6,7,8,0], [10,11,12])11[1 2 3] [10]12x |-> [4 5 6] x + [11]13[7 8 0] [12]1415sage: G = AffineGroup(2, ZZ)16sage: g = G([[1,1],[0,1]], [1,0])17sage: h = G([[1,2],[0,1]], [0,1])18sage: g*h19[1 3] [2]20x |-> [0 1] x + [1]21sage: h*g22[1 3] [1]23x |-> [0 1] x + [1]24sage: g*h != h*g25True2627AUTHORS:2829- Volker Braun30"""3132#*****************************************************************************33# Copyright (C) 2006 David Joyner and William Stein <[email protected]>34#35# Distributed under the terms of the GNU General Public License (GPL)36#37# http://www.gnu.org/licenses/38#*****************************************************************************3940from sage.matrix.matrix import is_Matrix41from sage.misc.cachefunc import cached_method42from sage.groups.matrix_gps.group_element import MatrixGroupElement_base4344class AffineGroupElement(MatrixGroupElement_base):45"""46An affine group element.4748INPUT:4950- ``A`` -- an invertible matrix, or something defining a51matrix if ``convert==True``.5253- ``b``-- a vector, or something defining a vector if54``convert==True`` (default: ``0``, defining the zero55vector).5657- ``parent`` -- the parent affine group.5859- ``convert`` - bool (default: ``True``). Whether to convert60``A`` into the correct matrix space and ``b`` into the61correct vector space.6263- ``check`` - bool (default: ``True``). Whether to do some64checks or just accept the input as valid.6566As a special case, ``A`` can be a matrix obtained from67:meth:`matrix`, that is, one row and one column larger. In68that case, the group element defining that matrix is69reconstructed.7071OUTPUT:7273The affine group element `x \mapsto Ax + b`7475EXAMPLES::7677sage: G = AffineGroup(2, GF(3))78sage: g = G.random_element()79sage: type(g)80<class 'sage.groups.affine_gps.group_element.AffineGroup_with_category.element_class'>81sage: G(g.matrix()) == g82True83sage: G(2)84[2 0] [0]85x |-> [0 2] x + [0]86"""87def __init__(self, parent, A, b=0, convert=True, check=True):88r"""89Create element of an affine group.9091TESTS::9293sage: G = AffineGroup(4, GF(5))94sage: g = G.random_element()95sage: TestSuite(g).run()96"""97if is_Matrix(A) and A.nrows() == A.ncols() == parent.degree()+1:98g = A99A = g.submatrix(0,0,2,2)100d = parent.degree()101b = [ g[i,d] for i in range(d) ]102convert = True103if convert:104A = parent.matrix_space()(A)105b = parent.vector_space()(b)106if check:107# Note: the coercion framework expects that we raise TypeError for invalid input108if not is_Matrix(A):109raise TypeError('A must be a matrix')110if not (A.parent() is parent.matrix_space()):111raise TypeError('A must be an element of '+str(parent.matrix_space()))112if not (b.parent() is parent.vector_space()):113raise TypeError('b must be an element of '+str(parent.vector_space()))114parent._element_constructor_check(A, b)115super(AffineGroupElement, self).__init__(parent)116self._A = A117self._b = b118119def A(self):120"""121Return the general linear part of an affine group element.122123OUTPUT:124125The matrix `A` of the affine group element `Ax + b`.126127EXAMPLES::128129sage: G = AffineGroup(3, QQ)130sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])131sage: g.A()132[1 2 3]133[4 5 6]134[7 8 0]135"""136return self._A137138def b(self):139"""140Return the translation part of an affine group element.141142OUTPUT:143144The vector `b` of the affine group element `Ax + b`.145146EXAMPLES::147148sage: G = AffineGroup(3, QQ)149sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])150sage: g.b()151(10, 11, 12)152"""153return self._b154155@cached_method156def matrix(self):157"""158Return the standard matrix representation of ``self``.159160.. SEEALSO::161162- :meth:`AffineGroup.linear_space()`163164EXAMPLES::165166sage: G = AffineGroup(3, GF(7))167sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])168sage: g169[1 2 3] [3]170x |-> [4 5 6] x + [4]171[0 1 0] [5]172sage: g.matrix()173[1 2 3|3]174[4 5 6|4]175[0 1 0|5]176[-----+-]177[0 0 0|1]178sage: parent(g.matrix())179Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 7180sage: g.matrix() == matrix(g)181True182183Composition of affine group elements equals multiplication of184the matrices::185186sage: g1 = G.random_element()187sage: g2 = G.random_element()188sage: g1.matrix() * g2.matrix() == (g1*g2).matrix()189True190"""191A = self._A192b = self._b193parent = self.parent()194d = parent.degree()195from sage.matrix.constructor import matrix, zero_matrix, block_matrix196zero = zero_matrix(parent.base_ring(), 1, d)197one = matrix(parent.base_ring(), [[1]])198m = block_matrix(2,2, [A, b.column(), zero, one])199m.set_immutable()200return m201202_matrix_ = matrix203204def _repr_(self):205"""206Return a string representation of ``self``.207208EXAMPLES::209210sage: G = AffineGroup(2, QQ)211sage: g = G([[1, 1], [0, 1]], [3,4])212sage: g213[1 1] [3]214x |-> [0 1] x + [4]215"""216A = str(self._A)217b = str(self._b.column())218deg = self.parent().degree()219indices = range(deg)220s = []221for Ai, bi, i in zip(A.splitlines(), b.splitlines(), indices):222if i == deg//2:223s.append('x |-> '+Ai+' x + '+bi)224else:225s.append(' '+Ai+' '+bi)226return '\n'.join(s)227228def _latex_(self):229r"""230Return a LaTeX representation of ``self``.231232EXAMPLES::233234sage: G = AffineGroup(2, QQ)235sage: g = G([[1, 1], [0, 1]], [3,4])236sage: latex(g)237\vec{x}\mapsto \left(\begin{array}{rr}2381 & 1 \\2390 & 1240\end{array}\right)\vec{x} + \left(\begin{array}{r}2413 \\2424243\end{array}\right)244sage: g._latex_()245'\\vec{x}\\mapsto \\left(\\begin{array}{rr}\n1 & 1 \\\\\n0 &2461\n\\end{array}\\right)\\vec{x} + \\left(\\begin{array}{r}\n3247\\\\\n4\n\\end{array}\\right)'248"""249return r'\vec{x}\mapsto '+self.A()._latex_()+r'\vec{x} + '+self.b().column()._latex_()250251def _mul_(self, other):252"""253Return the composition of ``self`` and ``other``.254255INPUT:256257- ``other`` -- another element of the same affine group.258259OUTPUT:260261The product of the affine group elements ``self`` and262``other`` defined by the composition of the two affine263transformations.264265EXAMPLES::266267sage: G = AffineGroup(2, GF(3))268sage: g = G([1,1, 0,1], [0,1])269sage: h = G([1,1, 0,1], [1,2])270sage: g*h271[1 2] [0]272x |-> [0 1] x + [0]273sage: g.matrix() * h.matrix() == (g*h).matrix()274True275"""276parent = self.parent()277A = self._A * other._A278b = self._b + self._A * other._b279return parent.element_class(parent, A, b, check=False)280281def __call__(self, v):282"""283Apply the affine transformation to ``v``.284285INPUT:286287- ``v`` -- a multivariate polynomial, a vector, or anything288that can be converted into a vector.289290OUTPUT:291292The image of ``v`` under the affine group element.293294EXAMPLES::295296sage: G = AffineGroup(2, QQ)297sage: g = G([0,1,-1,0],[2,3]); g298[ 0 1] [2]299x |-> [-1 0] x + [3]300sage: v = vector([4,5])301sage: g(v)302(7, -1)303304sage: R.<x,y> = QQ[]305sage: g(x), g(y)306(y + 2, -x + 3)307sage: p = x^2 + 2*x*y + y + 1308sage: g(p)309-2*x*y + y^2 - 5*x + 10*y + 20310311The action on polynomials is such that it intertwines with312evaluation. That is::313314sage: p(*g(v)) == g(p)(*v)315True316317Test that the univariate polynomial ring is covered::318319sage: H = AffineGroup(1, QQ)320sage: h = H([2],[3]); h321x |-> [2] x + [3]322sage: R.<z> = QQ[]323sage: h(z+1)3243*z + 2325"""326from sage.rings.polynomial.polynomial_element import is_Polynomial327from sage.rings.polynomial.multi_polynomial import is_MPolynomial328parent = self.parent()329if is_Polynomial(v) and parent.degree() == 1:330ring = v.parent()331return ring([self._A[0,0], self._b[0]])332if is_MPolynomial(v) and parent.degree() == v.parent().ngens():333ring = v.parent()334from sage.modules.all import vector335image_coords = self._A * vector(ring, ring.gens()) + self._b336return v(*image_coords)337v = parent.vector_space()(v)338return self._A*v + self._b339340def _act_on_(self, x, self_on_left):341"""342Define the multiplicative action of the affine group elements.343344EXAMPLES::345346sage: G = AffineGroup(2, GF(3))347sage: g = G([1,2,3,4], [5,6])348sage: g349[1 2] [2]350x |-> [0 1] x + [0]351sage: v = vector(GF(3), [1,-1]); v352(1, 2)353sage: g*v354(1, 2)355sage: g*v == g.A() * v + g.b()356True357"""358if self_on_left:359return self.__call__(x)360361def inverse(self):362"""363Return the inverse group element.364365OUTPUT:366367Another affine group element.368369EXAMPLES::370371sage: G = AffineGroup(2, GF(3))372sage: g = G([1,2,3,4], [5,6])373sage: g374[1 2] [2]375x |-> [0 1] x + [0]376sage: ~g377[1 1] [1]378x |-> [0 1] x + [0]379sage: g * g.inverse()380[1 0] [0]381x |-> [0 1] x + [0]382sage: g * g.inverse() == g.inverse() * g == G(1)383True384"""385parent = self.parent()386A = parent.matrix_space()(self._A.inverse())387b = -A*self.b()388return parent.element_class(parent, A, b, check=False)389390__invert__ = inverse391392def __cmp__(self, other):393"""394Compare ``self`` with ``other``.395396OUTPUT:397398-1, 0, or +1.399400EXAMPLES::401402sage: F = AffineGroup(3, QQ)403sage: g = F([1,2,3,4,5,6,7,8,0], [10,11,12])404sage: h = F([1,2,3,4,5,6,7,8,0], [10,11,0])405sage: g == h406False407sage: g == g408True409sage: abs(cmp(g, 'anything'))4101411"""412assert self.parent() is other.parent()413c = cmp(self._A, other._A)414if (c != 0):415return c416return cmp(self._b, other._b)417418419420