Path: blob/master/sage/modules/vector_space_morphism.py
4036 views
r"""1Vector Space Morphisms (aka Linear Transformations)23AUTHOR:45- Rob Beezer: (2011-06-29)67A vector space morphism is a homomorphism between vector spaces, better known8as a linear transformation. These are a specialization of Sage's free module9homomorphisms. (A free module is like a vector space, but with scalars from a10ring that may not be a field.) So references to free modules in the11documentation or error messages should be understood as simply reflectng a12more general situation.1314Creation15--------1617The constructor :func:`linear_transformation` is designed to accept a18variety of inputs that can define a linear transformation. See the19documentation of the function for all the possibilities. Here we give two.2021First a matrix representation. By default input matrices are understood22to act on vectors placed to left of the matrix. Optionally, an input23matrix can be described as acting on vectors placed to the right. ::2425sage: A = matrix(QQ, [[-1, 2, 3], [4, 2, 0]])26sage: phi = linear_transformation(A)27sage: phi28Vector space morphism represented by the matrix:29[-1 2 3]30[ 4 2 0]31Domain: Vector space of dimension 2 over Rational Field32Codomain: Vector space of dimension 3 over Rational Field33sage: phi([2, -3])34(-14, -2, 6)3536A symbolic function can be used to specify the "rule" for a37linear transformation, along with explicit descriptions of the38domain and codomain. ::3940sage: F = Integers(13)41sage: D = F^342sage: C = F^243sage: x, y, z = var('x y z')44sage: f(x, y, z) = [2*x + 3*y + 5*z, x + z]45sage: rho = linear_transformation(D, C, f)46sage: f(1, 2, 3)47(23, 4)48sage: rho([1, 2, 3])49(10, 4)5051A "vector space homspace" is the set of all linear transformations52between two vector spaces. Various input can be coerced into a53homspace to create a linear transformation. See54:mod:`sage.modules.vector_space_homspace` for more. ::5556sage: D = QQ^457sage: C = QQ^258sage: hom_space = Hom(D, C)59sage: images = [[1, 3], [2, -1], [4, 0], [3, 7]]60sage: zeta = hom_space(images)61sage: zeta62Vector space morphism represented by the matrix:63[ 1 3]64[ 2 -1]65[ 4 0]66[ 3 7]67Domain: Vector space of dimension 4 over Rational Field68Codomain: Vector space of dimension 2 over Rational Field6970A homomorphism may also be created via a method on the domain. ::7172sage: F = QQ[sqrt(3)]73sage: a = F.gen(0)74sage: D = F^275sage: C = F^276sage: A = matrix(F, [[a, 1], [2*a, 2]])77sage: psi = D.hom(A, C)78sage: psi79Vector space morphism represented by the matrix:80[ sqrt3 1]81[2*sqrt3 2]82Domain: Vector space of dimension 2 over Number Field in sqrt3 with defining polynomial x^2 - 383Codomain: Vector space of dimension 2 over Number Field in sqrt3 with defining polynomial x^2 - 384sage: psi([1, 4])85(9*sqrt3, 9)8687Properties88----------8990Many natural properties of a linear transformation can be computed.91Some of these are more general methods of objects in the classes92:class:`sage.modules.free_module_morphism.FreeModuleMorphism` and93:class:`sage.modules.matrix_morphism.MatrixMorphism`.9495Values are computed in a natural way, an inverse image of an96element can be computed with the ``lift()`` method, when the inverse97image actually exists. ::9899sage: A = matrix(QQ, [[1,2], [2,4], [3,6]])100sage: phi = linear_transformation(A)101sage: phi([1,2,0])102(5, 10)103sage: phi.lift([10, 20])104(10, 0, 0)105sage: phi.lift([100, 100])106Traceback (most recent call last):107...108ValueError: element is not in the image109110Images and pre-images can be computed as vector spaces. ::111112sage: A = matrix(QQ, [[1,2], [2,4], [3,6]])113sage: phi = linear_transformation(A)114sage: phi.image()115Vector space of degree 2 and dimension 1 over Rational Field116Basis matrix:117[1 2]118119sage: phi.inverse_image( (QQ^2).span([[1,2]]) )120Vector space of degree 3 and dimension 3 over Rational Field121Basis matrix:122[1 0 0]123[0 1 0]124[0 0 1]125126sage: phi.inverse_image( (QQ^2).span([[1,1]]) )127Vector space of degree 3 and dimension 2 over Rational Field128Basis matrix:129[ 1 0 -1/3]130[ 0 1 -2/3]131132Injectivity and surjectivity can be checked. ::133134sage: A = matrix(QQ, [[1,2], [2,4], [3,6]])135sage: phi = linear_transformation(A)136sage: phi.is_injective()137False138sage: phi.is_surjective()139False140141Restrictions and Representations142--------------------------------143144It is possible to restrict the domain and codomain of a linear145transformation to make a new linear transformation. We will use146those commands to replace the domain and codomain by equal vector147spaces, but with alternate bases. The point here is that the148matrix representation used to represent linear transformations are149relative to the bases of both the domain and codomain. ::150151sage: A = graphs.PetersenGraph().adjacency_matrix()152sage: V = QQ^10153sage: phi = linear_transformation(V, V, A)154sage: phi155Vector space morphism represented by the matrix:156[0 1 0 0 1 1 0 0 0 0]157[1 0 1 0 0 0 1 0 0 0]158[0 1 0 1 0 0 0 1 0 0]159[0 0 1 0 1 0 0 0 1 0]160[1 0 0 1 0 0 0 0 0 1]161[1 0 0 0 0 0 0 1 1 0]162[0 1 0 0 0 0 0 0 1 1]163[0 0 1 0 0 1 0 0 0 1]164[0 0 0 1 0 1 1 0 0 0]165[0 0 0 0 1 0 1 1 0 0]166Domain: Vector space of dimension 10 over Rational Field167Codomain: Vector space of dimension 10 over Rational Field168169sage: B1 = [V.gen(i) + V.gen(i+1) for i in range(9)] + [V.gen(9)]170sage: B2 = [V.gen(0)] + [-V.gen(i-1) + V.gen(i) for i in range(1,10)]171sage: D = V.subspace_with_basis(B1)172sage: C = V.subspace_with_basis(B2)173sage: rho = phi.restrict_codomain(C)174sage: zeta = rho.restrict_domain(D)175sage: zeta176Vector space morphism represented by the matrix:177[6 5 4 3 3 2 1 0 0 0]178[6 5 4 3 2 2 2 1 0 0]179[6 6 5 4 3 2 2 2 1 0]180[6 5 5 4 3 2 2 2 2 1]181[6 4 4 4 3 3 3 3 2 1]182[6 5 4 4 4 4 4 4 3 1]183[6 6 5 4 4 4 3 3 3 2]184[6 6 6 5 4 4 2 1 1 1]185[6 6 6 6 5 4 3 1 0 0]186[3 3 3 3 3 2 2 1 0 0]187Domain: Vector space of degree 10 and dimension 10 over Rational Field188User basis matrix:189[1 1 0 0 0 0 0 0 0 0]190[0 1 1 0 0 0 0 0 0 0]191[0 0 1 1 0 0 0 0 0 0]192[0 0 0 1 1 0 0 0 0 0]193[0 0 0 0 1 1 0 0 0 0]194[0 0 0 0 0 1 1 0 0 0]195[0 0 0 0 0 0 1 1 0 0]196[0 0 0 0 0 0 0 1 1 0]197[0 0 0 0 0 0 0 0 1 1]198[0 0 0 0 0 0 0 0 0 1]199Codomain: Vector space of degree 10 and dimension 10 over Rational Field200User basis matrix:201[ 1 0 0 0 0 0 0 0 0 0]202[-1 1 0 0 0 0 0 0 0 0]203[ 0 -1 1 0 0 0 0 0 0 0]204[ 0 0 -1 1 0 0 0 0 0 0]205[ 0 0 0 -1 1 0 0 0 0 0]206[ 0 0 0 0 -1 1 0 0 0 0]207[ 0 0 0 0 0 -1 1 0 0 0]208[ 0 0 0 0 0 0 -1 1 0 0]209[ 0 0 0 0 0 0 0 -1 1 0]210[ 0 0 0 0 0 0 0 0 -1 1]211212An endomorphism is a linear transformation with an equal domain and codomain,213and here each needs to have the same basis. We are using a214matrix that has well-behaved eigenvalues, as part of showing that these215do not change as the representation changes. ::216217sage: A = graphs.PetersenGraph().adjacency_matrix()218sage: V = QQ^10219sage: phi = linear_transformation(V, V, A)220sage: phi.eigenvalues()221[3, -2, -2, -2, -2, 1, 1, 1, 1, 1]222223sage: B1 = [V.gen(i) + V.gen(i+1) for i in range(9)] + [V.gen(9)]224sage: C = V.subspace_with_basis(B1)225sage: zeta = phi.restrict(C)226sage: zeta227Vector space morphism represented by the matrix:228[ 1 0 1 -1 2 -1 2 -2 2 -2]229[ 1 0 1 0 0 0 1 0 0 0]230[ 0 1 0 1 0 0 0 1 0 0]231[ 1 -1 2 -1 2 -2 2 -2 3 -2]232[ 2 -2 2 -1 1 -1 1 0 1 0]233[ 1 0 0 0 0 0 0 1 1 0]234[ 0 1 0 0 0 1 -1 1 0 2]235[ 0 0 1 0 0 2 -1 1 -1 2]236[ 0 0 0 1 0 1 1 0 0 0]237[ 0 0 0 0 1 -1 2 -1 1 -1]238Domain: Vector space of degree 10 and dimension 10 over Rational Field239User basis matrix:240[1 1 0 0 0 0 0 0 0 0]241[0 1 1 0 0 0 0 0 0 0]242[0 0 1 1 0 0 0 0 0 0]243[0 0 0 1 1 0 0 0 0 0]244[0 0 0 0 1 1 0 0 0 0]245[0 0 0 0 0 1 1 0 0 0]246[0 0 0 0 0 0 1 1 0 0]247[0 0 0 0 0 0 0 1 1 0]248[0 0 0 0 0 0 0 0 1 1]249[0 0 0 0 0 0 0 0 0 1]250Codomain: Vector space of degree 10 and dimension 10 over Rational Field251User basis matrix:252[1 1 0 0 0 0 0 0 0 0]253[0 1 1 0 0 0 0 0 0 0]254[0 0 1 1 0 0 0 0 0 0]255[0 0 0 1 1 0 0 0 0 0]256[0 0 0 0 1 1 0 0 0 0]257[0 0 0 0 0 1 1 0 0 0]258[0 0 0 0 0 0 1 1 0 0]259[0 0 0 0 0 0 0 1 1 0]260[0 0 0 0 0 0 0 0 1 1]261[0 0 0 0 0 0 0 0 0 1]262263sage: zeta.eigenvalues()264[3, -2, -2, -2, -2, 1, 1, 1, 1, 1]265266Equality267--------268269Equality of linear transformations is a bit nuanced. The equality operator270``==`` tests if two linear transformations have equal matrix representations,271while we determine if two linear transformations are the same function with the272``.is_equal_function()`` method. Notice in this example that the function273never changes, just the representations. ::274275sage: f = lambda x: vector(QQ, [x[1], x[0]+x[1], x[0]])276sage: H = Hom(QQ^2, QQ^3)277sage: phi = H(f)278279sage: rho = linear_transformation(QQ^2, QQ^3, matrix(QQ,2, 3, [[0,1,1], [1,1,0]]))280281sage: phi == rho282True283284sage: U = (QQ^2).subspace_with_basis([[1, 2], [-3, 1]])285sage: V = (QQ^3).subspace_with_basis([[0, 1, 0], [2, 3, 1], [-1, 1, 6]])286sage: K = Hom(U, V)287sage: zeta = K(f)288289sage: zeta == phi290False291sage: zeta.is_equal_function(phi)292True293sage: zeta.is_equal_function(rho)294True295296TESTS::297298sage: V = QQ^2299sage: H = Hom(V, V)300sage: f = H([V.1,-2*V.0])301sage: loads(dumps(f))302Vector space morphism represented by the matrix:303[ 0 1]304[-2 0]305Domain: Vector space of dimension 2 over Rational Field306Codomain: Vector space of dimension 2 over Rational Field307sage: loads(dumps(f)) == f308True309"""310311####################################################################################312# Copyright (C) 2011 Rob Beezer <[email protected]>313#314# Distributed under the terms of the GNU General Public License (GPL)315#316# This code is distributed in the hope that it will be useful,317# but WITHOUT ANY WARRANTY; without even the implied warranty of318# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU319# General Public License for more details.320#321# The full text of the GPL is available at:322#323# http://www.gnu.org/licenses/324####################################################################################325326327import sage.modules.matrix_morphism as matrix_morphism328import sage.modules.free_module_morphism as free_module_morphism329import vector_space_homspace330from sage.matrix.matrix import is_Matrix331332def linear_transformation(arg0, arg1=None, arg2=None, side='left'):333r"""334Create a linear transformation from a variety of possible inputs.335336FORMATS:337338In the following, ``D`` and ``C`` are vector spaces over339the same field that are the domain and codomain340(respectively) of the linear transformation.341342``side`` is a keyword that is either 'left' or 'right'.343When a matrix is used to specify a linear transformation,344as in the first two call formats below, you may specify345if the function is given by matrix multiplication with346the vector on the left, or the vector on the right.347The default is 'left'. Internally representations are348always carried as the 'left' version, and the default349text representation is this version. However, the matrix350representation may be obtained as either version, no matter351how it is created.352353- ``linear_transformation(A, side='left')``354355Where ``A`` is a matrix. The domain and codomain are inferred356from the dimension of the matrix and the base ring of the matrix.357The base ring must be a field, or have its fraction field implemented358in Sage.359360- ``linear_transformation(D, C, A, side='left')``361362``A`` is a matrix that behaves as above. However, now the domain363and codomain are given explicitly. The matrix is checked for364compatibility with the domain and codomain. Additionally, the365domain and codomain may be supplied with alternate ("user") bases366and the matrix is interpreted as being a representation relative367to those bases.368369- ``linear_transformation(D, C, f)``370371``f`` is any function that can be applied to the basis elements of the372domain and that produces elements of the codomain. The linear373transformation returned is the unique linear transformation that374extends this mapping on the basis elements. ``f`` may come from a375function defined by a Python ``def`` statement, or may be defined as a376``lambda`` function.377378Alternatively, ``f`` may be specified by a callable symbolic function,379see the examples below for a demonstration.380381- ``linear_transformation(D, C, images)``382383``images`` is a list, or tuple, of codomain elements, equal in number384to the size of the basis of the domain. Each basis element of the domain385is mapped to the corresponding element of the ``images`` list, and the386linear transformation returned is the unique linear transfromation that387extends this mapping.388389OUTPUT:390391A linear transformation described by the input. This is a392"vector space morphism", an object of the class393:class:`sage.modules.vector_space_morphism`.394395EXAMPLES:396397We can define a linear transformation with just a matrix, understood to398act on a vector placed on one side or the other. The field for the399vector spaces used as domain and codomain is obtained from the base400ring of the matrix, possibly promoting to a fraction field. ::401402sage: A = matrix(ZZ, [[1, -1, 4], [2, 0, 5]])403sage: phi = linear_transformation(A)404sage: phi405Vector space morphism represented by the matrix:406[ 1 -1 4]407[ 2 0 5]408Domain: Vector space of dimension 2 over Rational Field409Codomain: Vector space of dimension 3 over Rational Field410sage: phi([1/2, 5])411(21/2, -1/2, 27)412413sage: B = matrix(Integers(7), [[1, 2, 1], [3, 5, 6]])414sage: rho = linear_transformation(B, side='right')415sage: rho416Vector space morphism represented by the matrix:417[1 3]418[2 5]419[1 6]420Domain: Vector space of dimension 3 over Ring of integers modulo 7421Codomain: Vector space of dimension 2 over Ring of integers modulo 7422sage: rho([2, 4, 6])423(2, 6)424425We can define a linear transformation with a matrix, while explicitly426giving the domain and codomain. Matrix entries will be coerced into the427common field of scalars for the vector spaces. ::428429sage: D = QQ^3430sage: C = QQ^2431sage: A = matrix([[1, 7], [2, -1], [0, 5]])432sage: A.parent()433Full MatrixSpace of 3 by 2 dense matrices over Integer Ring434sage: zeta = linear_transformation(D, C, A)435sage: zeta.matrix().parent()436Full MatrixSpace of 3 by 2 dense matrices over Rational Field437sage: zeta438Vector space morphism represented by the matrix:439[ 1 7]440[ 2 -1]441[ 0 5]442Domain: Vector space of dimension 3 over Rational Field443Codomain: Vector space of dimension 2 over Rational Field444445Matrix representations are relative to the bases for the domain446and codomain. ::447448sage: u = vector(QQ, [1, -1])449sage: v = vector(QQ, [2, 3])450sage: D = (QQ^2).subspace_with_basis([u, v])451sage: x = vector(QQ, [2, 1])452sage: y = vector(QQ, [-1, 4])453sage: C = (QQ^2).subspace_with_basis([x, y])454sage: A = matrix(QQ, [[2, 5], [3, 7]])455sage: psi = linear_transformation(D, C, A)456sage: psi457Vector space morphism represented by the matrix:458[2 5]459[3 7]460Domain: Vector space of degree 2 and dimension 2 over Rational Field461User basis matrix:462[ 1 -1]463[ 2 3]464Codomain: Vector space of degree 2 and dimension 2 over Rational Field465User basis matrix:466[ 2 1]467[-1 4]468sage: psi(u) == 2*x + 5*y469True470sage: psi(v) == 3*x + 7*y471True472473Functions that act on the domain may be used to compute images of474the domain's basis elements, and this mapping can be extended to475a unique linear transformation. The function may be a Python476function (via ``def`` or ``lambda``) or a Sage symbolic function. ::477478sage: def g(x):479... return vector(QQ, [2*x[0]+x[2], 5*x[1]])480...481sage: phi = linear_transformation(QQ^3, QQ^2, g)482sage: phi483Vector space morphism represented by the matrix:484[2 0]485[0 5]486[1 0]487Domain: Vector space of dimension 3 over Rational Field488Codomain: Vector space of dimension 2 over Rational Field489490sage: f = lambda x: vector(QQ, [2*x[0]+x[2], 5*x[1]])491sage: rho = linear_transformation(QQ^3, QQ^2, f)492sage: rho493Vector space morphism represented by the matrix:494[2 0]495[0 5]496[1 0]497Domain: Vector space of dimension 3 over Rational Field498Codomain: Vector space of dimension 2 over Rational Field499500sage: x, y, z = var('x y z')501sage: h(x, y, z) = [2*x + z, 5*y]502sage: zeta = linear_transformation(QQ^3, QQ^2, h)503sage: zeta504Vector space morphism represented by the matrix:505[2 0]506[0 5]507[1 0]508Domain: Vector space of dimension 3 over Rational Field509Codomain: Vector space of dimension 2 over Rational Field510511sage: phi == rho512True513sage: rho == zeta514True515516517We create a linear transformation relative to non-standard bases,518and capture its representation relative to standard bases. With this, we519can build functions that create the same linear transformation relative520to the nonstandard bases. ::521522sage: u = vector(QQ, [1, -1])523sage: v = vector(QQ, [2, 3])524sage: D = (QQ^2).subspace_with_basis([u, v])525sage: x = vector(QQ, [2, 1])526sage: y = vector(QQ, [-1, 4])527sage: C = (QQ^2).subspace_with_basis([x, y])528sage: A = matrix(QQ, [[2, 5], [3, 7]])529sage: psi = linear_transformation(D, C, A)530sage: rho = psi.restrict_codomain(QQ^2).restrict_domain(QQ^2)531sage: rho.matrix()532[ -4/5 97/5]533[ 1/5 -13/5]534535sage: f = lambda x: vector(QQ, [(-4/5)*x[0] + (1/5)*x[1], (97/5)*x[0] + (-13/5)*x[1]])536sage: psi = linear_transformation(D, C, f)537sage: psi.matrix()538[2 5]539[3 7]540541sage: s, t = var('s t')542sage: h(s, t) = [(-4/5)*s + (1/5)*t, (97/5)*s + (-13/5)*t]543sage: zeta = linear_transformation(D, C, h)544sage: zeta.matrix()545[2 5]546[3 7]547548Finally, we can give an explicit list of images for the basis549elements of the domain. ::550551sage: x = polygen(QQ)552sage: F.<a> = NumberField(x^3+x+1)553sage: u = vector(F, [1, a, a^2])554sage: v = vector(F, [a, a^2, 2])555sage: w = u + v556sage: D = F^3557sage: C = F^3558sage: rho = linear_transformation(D, C, [u, v, w])559sage: rho.matrix()560[ 1 a a^2]561[ a a^2 2]562[ a + 1 a^2 + a a^2 + 2]563sage: C = (F^3).subspace_with_basis([u, v])564sage: D = (F^3).subspace_with_basis([u, v])565sage: psi = linear_transformation(C, D, [u+v, u-v])566sage: psi.matrix()567[ 1 1]568[ 1 -1]569570TESTS:571572We test some bad inputs. First, the wrong things in the wrong places. ::573574sage: linear_transformation('junk')575Traceback (most recent call last):576...577TypeError: first argument must be a matrix or a vector space, not junk578579sage: linear_transformation(QQ^2, QQ^3, 'stuff')580Traceback (most recent call last):581...582TypeError: third argument must be a matrix, function, or list of images, not stuff583584sage: linear_transformation(QQ^2, 'garbage')585Traceback (most recent call last):586...587TypeError: if first argument is a vector space, then second argument must be a vector space, not garbage588589sage: linear_transformation(QQ^2, Integers(7)^2)590Traceback (most recent call last):591...592TypeError: vector spaces must have the same field of scalars, not Rational Field and Ring of integers modulo 7593594Matrices must be over a field (or a ring that can be promoted to a field),595and of the right size. ::596597sage: linear_transformation(matrix(Integers(6), [[2, 3],[4, 5]]))598Traceback (most recent call last):599...600TypeError: matrix must have entries from a field, or a ring with a fraction field, not Ring of integers modulo 6601602sage: A = matrix(QQ, 3, 4, range(12))603sage: linear_transformation(QQ^4, QQ^4, A)604Traceback (most recent call last):605...606TypeError: domain dimension is incompatible with matrix size607608sage: linear_transformation(QQ^3, QQ^3, A, side='right')609Traceback (most recent call last):610...611TypeError: domain dimension is incompatible with matrix size612613sage: linear_transformation(QQ^3, QQ^3, A)614Traceback (most recent call last):615...616TypeError: codomain dimension is incompatible with matrix size617618sage: linear_transformation(QQ^4, QQ^4, A, side='right')619Traceback (most recent call last):620...621TypeError: codomain dimension is incompatible with matrix size622623Lists of images can be of the wrong number, or not really624elements of the codomain. ::625626sage: linear_transformation(QQ^3, QQ^2, [vector(QQ, [1,2])])627Traceback (most recent call last):628...629ValueError: number of images should equal the size of the domain's basis (=3), not 1630631sage: C = (QQ^2).subspace_with_basis([vector(QQ, [1,1])])632sage: linear_transformation(QQ^1, C, [vector(QQ, [1,2])])633Traceback (most recent call last):634...635ArithmeticError: some proposed image is not in the codomain, because636element (= [1, 2]) is not in free module637638639Functions may not apply properly to domain elements,640or return values outside the codomain. ::641642sage: f = lambda x: vector(QQ, [x[0], x[4]])643sage: linear_transformation(QQ^3, QQ^2, f)644Traceback (most recent call last):645...646ValueError: function cannot be applied properly to some basis element because647index out of range648649sage: f = lambda x: vector(QQ, [x[0], x[1]])650sage: C = (QQ^2).span([vector(QQ, [1, 1])])651sage: linear_transformation(QQ^2, C, f)652Traceback (most recent call last):653...654ArithmeticError: some image of the function is not in the codomain, because655element (= [1, 0]) is not in free module656657A Sage symbolic function can come in a variety of forms that are658not representative of a linear transformation. ::659660sage: x, y = var('x, y')661sage: f(x, y) = [y, x, y]662sage: linear_transformation(QQ^3, QQ^3, f)663Traceback (most recent call last):664...665ValueError: symbolic function has the wrong number of inputs for domain666667sage: linear_transformation(QQ^2, QQ^2, f)668Traceback (most recent call last):669...670ValueError: symbolic function has the wrong number of outputs for codomain671672sage: x, y = var('x y')673sage: f(x, y) = [y, x*y]674sage: linear_transformation(QQ^2, QQ^2, f)675Traceback (most recent call last):676...677ValueError: symbolic function must be linear in all the inputs:678unable to convert y to a rational679680sage: x, y = var('x y')681sage: f(x, y) = [x, 2*y]682sage: C = (QQ^2).span([vector(QQ, [1, 1])])683sage: linear_transformation(QQ^2, C, f)684Traceback (most recent call last):685...686ArithmeticError: some image of the function is not in the codomain, because687element (= [1, 0]) is not in free module688"""689from sage.matrix.constructor import matrix690from sage.modules.module import is_VectorSpace691from sage.modules.free_module import VectorSpace692from sage.categories.homset import Hom693from sage.symbolic.ring import SymbolicRing694from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense695from inspect import isfunction696697if not side in ['left', 'right']:698raise ValueError("side must be 'left' or 'right', not {0}".format(side))699if not (is_Matrix(arg0) or is_VectorSpace(arg0)):700raise TypeError('first argument must be a matrix or a vector space, not {0}'.format(arg0))701if is_Matrix(arg0):702R = arg0.base_ring()703if not R.is_field():704try:705R = R.fraction_field()706except (NotImplementedError, TypeError):707msg = 'matrix must have entries from a field, or a ring with a fraction field, not {0}'708raise TypeError(msg.format(R))709if side == 'right':710arg0 = arg0.transpose()711side = 'left'712arg2 = arg0713arg0 = VectorSpace(R, arg2.nrows())714arg1 = VectorSpace(R, arg2.ncols())715elif is_VectorSpace(arg0):716if not is_VectorSpace(arg1):717msg = 'if first argument is a vector space, then second argument must be a vector space, not {0}'718raise TypeError(msg.format(arg1))719if arg0.base_ring() != arg1.base_ring():720msg = 'vector spaces must have the same field of scalars, not {0} and {1}'721raise TypeError(msg.format(arg0.base_ring(), arg1.base_ring()))722723# Now arg0 = domain D, arg1 = codomain C, and724# both are vector spaces with common field of scalars725# use these to make a VectorSpaceHomSpace726# arg2 might be a matrix that began in arg0727D = arg0728C = arg1729H = Hom(D, C, category=None)730731# Examine arg2 as the "rule" for the linear transformation732# Pass on matrices, Python functions and lists to homspace call733# Convert symbolic function here, to a matrix734if is_Matrix(arg2):735if side == 'right':736arg2 = arg2.transpose()737elif isinstance(arg2, (list, tuple)):738pass739elif isfunction(arg2):740pass741elif isinstance(arg2, Vector_callable_symbolic_dense):742args = arg2.parent().base_ring()._arguments743exprs = arg2.change_ring(SymbolicRing())744m = len(args)745n = len(exprs)746if m != D.degree():747raise ValueError('symbolic function has the wrong number of inputs for domain')748if n != C.degree():749raise ValueError('symbolic function has the wrong number of outputs for codomain')750arg2 = [[e.coeff(a) for e in exprs] for a in args]751try:752arg2 = matrix(D.base_ring(), m, n, arg2)753except TypeError, e:754msg = 'symbolic function must be linear in all the inputs:\n' + e.args[0]755raise ValueError(msg)756# have matrix with respect to standard bases, now consider user bases757images = [v*arg2 for v in D.basis()]758try:759arg2 = matrix([C.coordinates(C(a)) for a in images])760except (ArithmeticError, TypeError), e:761msg = 'some image of the function is not in the codomain, because\n' + e.args[0]762raise ArithmeticError(msg)763else:764msg = 'third argument must be a matrix, function, or list of images, not {0}'765raise TypeError(msg.format(arg2))766767# arg2 now compatible with homspace H call method768# __init__ will check matrix sizes versus domain/codomain dimensions769return H(arg2)770771def is_VectorSpaceMorphism(x):772r"""773Returns ``True`` if ``x`` is a vector space morphism (a linear transformation).774775INPUT:776777``x`` - anything778779OUTPUT:780781``True`` only if ``x`` is an instance of a vector space morphism,782which are also known as linear transformations.783784EXAMPLES::785786sage: V = QQ^2; f = V.hom([V.1,-2*V.0])787sage: sage.modules.vector_space_morphism.is_VectorSpaceMorphism(f)788True789sage: sage.modules.vector_space_morphism.is_VectorSpaceMorphism('junk')790False791"""792return isinstance(x, VectorSpaceMorphism)793794795class VectorSpaceMorphism(free_module_morphism.FreeModuleMorphism):796797def __init__(self, homspace, A):798r"""799Create a linear transformation, a morphism between vector spaces.800801INPUT:802803- ``homspace`` - a homspace (of vector spaces) to serve804as a parent for the linear transformation and a home for805the domain and codomain of the morphism806- ``A`` - a matrix representing the linear transformation,807which will act on vectors placed to the left of the matrix808809EXAMPLES:810811Nominally, we require a homspace to hold the domain812and codomain and a matrix representation of the morphism813(linear transformation). ::814815sage: from sage.modules.vector_space_homspace import VectorSpaceHomspace816sage: from sage.modules.vector_space_morphism import VectorSpaceMorphism817sage: H = VectorSpaceHomspace(QQ^3, QQ^2)818sage: A = matrix(QQ, 3, 2, range(6))819sage: zeta = VectorSpaceMorphism(H, A)820sage: zeta821Vector space morphism represented by the matrix:822[0 1]823[2 3]824[4 5]825Domain: Vector space of dimension 3 over Rational Field826Codomain: Vector space of dimension 2 over Rational Field827828See the constructor,829:func:`sage.modules.vector_space_morphism.linear_transformation`830for another way to create linear transformations.831832The ``.hom()`` method of a vector space will create a vector833space morphism. ::834835sage: V = QQ^3; W = V.subspace_with_basis([[1,2,3], [-1,2,5/3], [0,1,-1]])836sage: phi = V.hom(matrix(QQ, 3, range(9)), codomain=W) # indirect doctest837sage: type(phi)838<class 'sage.modules.vector_space_morphism.VectorSpaceMorphism'>839840A matrix may be coerced into a vector space homspace to841create a vector space morphism. ::842843sage: from sage.modules.vector_space_homspace import VectorSpaceHomspace844sage: H = VectorSpaceHomspace(QQ^3, QQ^2)845sage: A = matrix(QQ, 3, 2, range(6))846sage: rho = H(A) # indirect doctest847sage: type(rho)848<class 'sage.modules.vector_space_morphism.VectorSpaceMorphism'>849"""850if not vector_space_homspace.is_VectorSpaceHomspace(homspace):851raise TypeError, 'homspace must be a vector space hom space, not {0}'.format(homspace)852if isinstance(A, matrix_morphism.MatrixMorphism):853A = A.matrix()854if not is_Matrix(A):855msg = 'input must be a matrix representation or another matrix morphism, not {0}'856raise TypeError(msg.format(A))857# now have a vector space homspace, and a matrix, check compatibility858859if homspace.domain().dimension() != A.nrows():860raise TypeError('domain dimension is incompatible with matrix size')861if homspace.codomain().dimension() != A.ncols():862raise TypeError('codomain dimension is incompatible with matrix size')863864A = homspace._matrix_space()(A)865free_module_morphism.FreeModuleMorphism.__init__(self, homspace, A)866867def is_invertible(self):868r"""869Determines if the vector space morphism has an inverse.870871OUTPUT:872873``True`` if the vector space morphism is invertible, otherwise874``False``.875876EXAMPLES:877878If the dimension of the domain does not match the dimension879of the codomain, then the morphism cannot be invertible. ::880881sage: V = QQ^3882sage: U = V.subspace_with_basis([V.0 + V.1, 2*V.1 + 3*V.2])883sage: phi = V.hom([U.0, U.0 + U.1, U.0 - U.1], U)884sage: phi.is_invertible()885False886887An invertible linear transformation. ::888889sage: A = matrix(QQ, 3, [[-3, 5, -5], [4, -7, 7], [6, -8, 10]])890sage: A.determinant()8912892sage: H = Hom(QQ^3, QQ^3)893sage: rho = H(A)894sage: rho.is_invertible()895True896897A non-invertible linear transformation, an endomorphism of898a vector space over a finite field. ::899900sage: F.<a> = GF(11^2)901sage: A = matrix(F, [[6*a + 3, 8*a + 2, 10*a + 3],902... [2*a + 7, 4*a + 3, 2*a + 3],903... [9*a + 2, 10*a + 10, 3*a + 3]])904sage: A.nullity()9051906sage: E = End(F^3)907sage: zeta = E(A)908sage: zeta.is_invertible()909False910"""911# endomorphism or not, this is equivalent to invertibility of912# the matrix representation, so any test of this will suffice913m = self.matrix()914if not m.is_square():915return False916return m.rank() == m.ncols()917918def _latex_(self):919r"""920A LaTeX representation of this vector space morphism.921922EXAMPLE::923924sage: H = Hom(QQ^3, QQ^2)925sage: f = H(matrix(3, 2, range(6)))926sage: f._latex_().split(' ')927['\\texttt{vector', 'space', 'morphism', 'from',928'}\n\\Bold{Q}^{3}\\texttt{', 'to', '}\n\\Bold{Q}^{2}\\texttt{',929'represented', 'by', 'the', 'matrix',930'}\n\\left(\\begin{array}{rr}\n0', '&', '1',931'\\\\\n2', '&', '3', '\\\\\n4', '&', '5\n\\end{array}\\right)']932"""933from sage.misc.latex import latex934s = ('\\texttt{vector space morphism from }\n', self.domain()._latex_(),935'\\texttt{ to }\n', self.codomain()._latex_(),936'\\texttt{ represented by the matrix }\n', self.matrix()._latex_())937return ''.join(s)938939def _repr_(self):940r"""941A text representation of this vector space morphism.942943EXAMPLE::944945sage: H = Hom(QQ^3, QQ^2)946sage: f = H(matrix(3, 2, range(6)))947sage: f._repr_().split(' ')948['Vector', 'space', 'morphism', 'represented', 'by',949'the', 'matrix:\n[0', '1]\n[2', '3]\n[4', '5]\nDomain:',950'Vector', 'space', 'of', 'dimension', '3', 'over',951'Rational', 'Field\nCodomain:', 'Vector', 'space', 'of',952'dimension', '2', 'over', 'Rational', 'Field']953"""954m = self.matrix()955msg = ("Vector space morphism represented by the matrix:\n",956"{0}\n",957"Domain: {1}\n",958"Codomain: {2}")959return ''.join(msg).format(m, self.domain(), self.codomain())960961962