############################################################################# ## #W vspc.gi GAP library Thomas Breuer ## ## #Y Copyright (C) 1997, Lehrstuhl D für Mathematik, RWTH Aachen, Germany #Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland #Y Copyright (C) 2002 The GAP Group ## ## This file contains generic methods for vector spaces. ## ############################################################################# ## #M SetLeftActingDomain( , ) ## ## check whether the left acting domain of the external left set ## knows that it is a division ring. ## This is used, e.g., to tell a free module over a division ring ## that it is a vector space. ## InstallOtherMethod( SetLeftActingDomain, "method to set also 'IsLeftActedOnByDivisionRing'", [ IsAttributeStoringRep and IsLeftActedOnByRing, IsObject ],0, function( extL, D ) if HasIsDivisionRing( D ) and IsDivisionRing( D ) then SetIsLeftActedOnByDivisionRing( extL, true ); fi; TryNextMethod(); end ); ############################################################################# ## #M IsLeftActedOnByDivisionRing( ) ## InstallMethod( IsLeftActedOnByDivisionRing, "method for external left set that is left acted on by a ring", [ IsExtLSet and IsLeftActedOnByRing ], function( M ) if IsIdenticalObj( M, LeftActingDomain( M ) ) then TryNextMethod(); else return IsDivisionRing( LeftActingDomain( M ) ); fi; end ); ############################################################################# ## #F VectorSpace( , [, ][, "basis"] ) ## ## The only difference between `VectorSpace' and `FreeLeftModule' shall be ## that the left acting domain of a vector space must be a division ring. ## InstallGlobalFunction( VectorSpace, function( arg ) if Length( arg ) = 0 or not IsDivisionRing( arg[1] ) then Error( "usage: VectorSpace( , [, ][, \"basis\"] )" ); fi; return CallFuncList( FreeLeftModule, arg ); end ); ############################################################################# ## #M AsSubspace( , ) . . . . . . . for a vector space and a collection ## InstallMethod( AsSubspace, "for a vector space and a collection", [ IsVectorSpace, IsCollection ], function( V, C ) local newC; if not IsSubset( V, C ) then return fail; fi; newC:= AsVectorSpace( LeftActingDomain( V ), C ); if newC = fail then return fail; fi; SetParent( newC, V ); UseIsomorphismRelation( C, newC ); UseSubsetRelation( C, newC ); return newC; end ); ############################################################################# ## #M AsLeftModule( , ) . . . . . . for division ring and vector space ## ## View the vector space as a vector space over the division ring . ## InstallMethod( AsLeftModule, "method for a division ring and a vector space", [ IsDivisionRing, IsVectorSpace ], function( F, V ) local W, # the space, result base, # basis vectors of field extension gen, # loop over generators of 'V' b, # loop over 'base' gens, # generators of 'V' newgens; # extended list of generators if Characteristic( F ) <> Characteristic( LeftActingDomain( V ) ) then # This is impossible. return fail; elif F = LeftActingDomain( V ) then # No change of the left acting domain is necessary. return V; elif IsSubset( F, LeftActingDomain( V ) ) then # Check whether 'V' is really a space over the bigger field, # that is, whether the set of elements does not change. base:= BasisVectors( Basis( AsField( LeftActingDomain( V ), F ) ) ); for gen in GeneratorsOfLeftModule( V ) do for b in base do if not b * gen in V then # The field extension would change the set of elements. return fail; fi; od; od; # Construct the space. W:= LeftModuleByGenerators( F, GeneratorsOfLeftModule(V), Zero(V) ); elif IsSubset( LeftActingDomain( V ), F ) then # View 'V' as a space over a smaller field. # For that, the list of generators must be extended. gens:= GeneratorsOfLeftModule( V ); if IsEmpty( gens ) then W:= LeftModuleByGenerators( F, [], Zero( V ) ); else base:= BasisVectors( Basis( AsField( F, LeftActingDomain( V ) ) ) ); newgens:= []; for b in base do for gen in gens do Add( newgens, b * gen ); od; od; W:= LeftModuleByGenerators( F, newgens ); fi; else # View 'V' first as space over the intersection of fields, # and then over the desired field. return AsLeftModule( F, AsLeftModule( Intersection( F, LeftActingDomain( V ) ), V ) ); fi; UseIsomorphismRelation( V, W ); UseSubsetRelation( V, W ); return W; end ); ############################################################################# ## #M ViewObj( ) . . . . . . . . . . . . . . . . . . . view a vector space ## ## print left acting domain, if known also dimension or no. of generators ## InstallMethod( ViewObj, "for vector space with known generators", [ IsVectorSpace and HasGeneratorsOfLeftModule ], function( V ) Print( "" ); end ); InstallMethod( ViewObj, "for vector space with known dimension", [ IsVectorSpace and HasDimension ], 1, # override method for known generators function( V ) Print( "" ); end ); InstallMethod( ViewObj, "for vector space", [ IsVectorSpace ], function( V ) Print( "" ); end ); ############################################################################# ## #M PrintObj( ) . . . . . . . . . . . . . . . . . . . for a vector space ## InstallMethod( PrintObj, "method for vector space with left module generators", [ IsVectorSpace and HasGeneratorsOfLeftModule ], function( V ) Print( "VectorSpace( ", LeftActingDomain( V ), ", ", GeneratorsOfLeftModule( V ) ); if IsEmpty( GeneratorsOfLeftModule( V ) ) and HasZero( V ) then Print( ", ", Zero( V ), " )" ); else Print( " )" ); fi; end ); InstallMethod( PrintObj, "method for vector space", [ IsVectorSpace ], function( V ) Print( "VectorSpace( ", LeftActingDomain( V ), ", ... )" ); end ); ############################################################################# ## #M \/( , ) . . . . . . . . . factor of a vector space by a subspace #M \/( , ) . . . . . . factor of a vector space by a subspace ## InstallOtherMethod( \/, "method for vector space and collection", IsIdenticalObj, [ IsVectorSpace, IsCollection ], function( V, vectors ) if IsVectorSpace( vectors ) then TryNextMethod(); else return V / Subspace( V, vectors ); fi; end ); InstallOtherMethod( \/, "generic method for two vector spaces", IsIdenticalObj, [ IsVectorSpace, IsVectorSpace ], function( V, W ) return ImagesSource( NaturalHomomorphismBySubspace( V, W ) ); end ); ############################################################################# ## #M Intersection2Spaces( , , ) ## InstallGlobalFunction( Intersection2Spaces, function( AsStructure, Substructure, Structure ) return function( V, W ) local inters, # intersection, result F, # coefficients field gensV, # list of generators of 'V' gensW, # list of generators of 'W' VW, # sum of 'V' and 'W' B; # basis of 'VW' if LeftActingDomain( V ) <> LeftActingDomain( W ) then # Compute the intersection as vector space over the intersection # of the coefficients fields. # (Note that the characteristic is the same.) F:= Intersection2( LeftActingDomain( V ), LeftActingDomain( W ) ); return Intersection2( AsStructure( F, V ), AsStructure( F, W ) ); elif IsFiniteDimensional( V ) and IsFiniteDimensional( W ) then # Compute the intersection of two spaces over the same field. gensV:= GeneratorsOfLeftModule( V ); gensW:= GeneratorsOfLeftModule( W ); if IsEmpty( gensV ) then if Zero( V ) in W then inters:= V; else inters:= []; fi; elif IsEmpty( gensW ) then if Zero( V ) in W then inters:= W; else inters:= []; fi; else # Compute a common coefficient space. VW:= LeftModuleByGenerators( LeftActingDomain( V ), Concatenation( gensV, gensW ) ); B:= Basis( VW ); # Construct the coefficient subspaces corresponding to 'V' and 'W'. gensV:= List( gensV, x -> Coefficients( B, x ) ); gensW:= List( gensW, x -> Coefficients( B, x ) ); # Construct the intersection of row spaces, and carry back to VW. inters:= List( SumIntersectionMat( gensV, gensW )[2], x -> LinearCombination( B, x ) ); # Construct the intersection space, if possible with a parent. if HasParent( V ) and HasParent( W ) and IsIdenticalObj( Parent( V ), Parent( W ) ) then inters:= Substructure( Parent( V ), inters, "basis" ); elif IsEmpty( inters ) then inters:= Substructure( V, inters, "basis" ); SetIsTrivial( inters, true ); else inters:= Structure( LeftActingDomain( V ), inters, "basis" ); fi; # Run implications by the subset relation. UseSubsetRelation( V, inters ); UseSubsetRelation( W, inters ); fi; # Return the result. return inters; else TryNextMethod(); fi; end; end ); ############################################################################# ## #M Intersection2( , ) . . . . . . . . . . . . . for two vector spaces ## InstallMethod( Intersection2, "method for two vector spaces", IsIdenticalObj, [ IsVectorSpace, IsVectorSpace ], Intersection2Spaces( AsLeftModule, SubspaceNC, VectorSpace ) ); ############################################################################# ## #M ClosureLeftModule( , ) . . . . . . . . . closure of a vector space ## InstallMethod( ClosureLeftModule, "method for a vector space with basis, and a vector", IsCollsElms, [ IsVectorSpace and HasBasis, IsVector ], function( V, w ) local B; # basis of 'V' # We can test membership easily. B:= Basis( V ); #T why easily? if Coefficients( B, w ) = fail then # In the case of a vector space, we know a basis of the closure. B:= Concatenation( BasisVectors( B ), [ w ] ); V:= LeftModuleByGenerators( LeftActingDomain( V ), B ); UseBasis( V, B ); fi; return V; end ); ############################################################################# ## ## Methods for collections of subspaces of a vector space ## ############################################################################# ## #R IsSubspacesVectorSpaceDefaultRep( ) ## ## is the representation of domains of subspaces of a vector space , ## with the components 'structure' (with value ) and 'dimension' ## (with value either the dimension of the subspaces in the domain ## or the string '\"all\"', which means that the domain contains all ## subspaces of ). ## DeclareRepresentation( "IsSubspacesVectorSpaceDefaultRep", IsComponentObjectRep, [ "dimension", "structure" ] ); #T not IsAttributeStoringRep? ############################################################################# ## #M PrintObj( ) . . . . . . . . . . . . . . . . . for a subspaces domain ## InstallMethod( PrintObj, "method for a subspaces domain", [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], function( D ) if IsInt( D!.dimension ) then Print( "Subspaces( ", D!.structure, ", ", D!.dimension, " )" ); else Print( "Subspaces( ", D!.structure, " )" ); fi; end ); ############################################################################# ## #M Size( ) . . . . . . . . . . . . . . . . . . . for a subspaces domain ## ## The number of $k$-dimensional subspaces in a $n$-dimensional space over ## the field with $q$ elements is ## $$ ## a(n,k) = \prod_{i=0}^{k-1} \frac{q^n-q^i}{q^k-q^i} = ## \prod_{i=0}^{k-1} \frac{q^{n-i}-1}{q^{k-i}-1}. ## $$ ## We have the recursion ## $$ ## a(n,k+1) = a(n,k) \frac{q^{n-i}-1}{q^{i+1}-1}. ## $$ ## ## (The number of all subspaces is $\sum_{k=0}^n a(n,k)$.) ## InstallMethod( Size, "method for a subspaces domain", [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], function( D ) local k, n, q, size, qn, qd, ank, i; if D!.dimension = "all" then # all subspaces of the space n:= Dimension( D!.structure ); q:= Size( LeftActingDomain( D!.structure ) ); size:= 1; qn:= q^n; qd:= q; # $a(n,0)$ ank:= 1; for k in [ 1 .. Int( (n-1)/2 ) ] do # Compute $a(n,k)$. ank:= ank * ( qn - 1 ) / ( qd - 1 ); qn:= qn / q; qd:= qd * q; size:= size + ank; od; size:= 2 * size; if n mod 2 = 0 then # Add the number of spaces of dimension $n/2$. size:= size + ank * ( qn - 1 ) / ( qd - 1 ); fi; else # number of spaces of dimension 'k' only n:= Dimension( D!.structure ); if D!.dimension < 0 or n < D!.dimension then return 0; elif n / 2 < D!.dimension then k:= n - D!.dimension; else k:= D!.dimension; fi; q:= Size( LeftActingDomain( D!.structure ) ); size:= 1; qn:= q^n; qd:= q; for i in [ 1 .. k ] do size:= size * ( qn - 1 ) / ( qd - 1 ); qn:= qn / q; qd:= qd * q; od; fi; # Return the result. return size; end ); ############################################################################# ## #M Enumerator( ) . . . . . . . . . . . . . . . . for a subspaces domain ## ## Use the iterator to compute the elements list. #T This is not allowed! ## InstallMethod( Enumerator, "method for a subspaces domain", [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], function( D ) local iter, # iterator for 'D' elms; # elements list, result iter:= Iterator( D ); elms:= []; while not IsDoneIterator( iter ) do Add( elms, NextIterator( iter ) ); od; return elms; end ); #T necessary? ############################################################################# ## #M Iterator( ) . . . . . . . . . . . . . . . . . for a subspaces domain ## ## uses the subspaces iterator for full row spaces and the mechanism of ## associated row spaces. ## BindGlobal( "IsDoneIterator_Subspaces", iter -> IsDoneIterator( iter!.associatedIterator ) ); BindGlobal( "NextIterator_Subspaces", function( iter ) local next; next:= NextIterator( iter!.associatedIterator ); next:= List( GeneratorsOfLeftModule( next ), x -> LinearCombination( iter!.basis, x ) ); return Subspace( iter!.structure, next, "basis" ); end ); BindGlobal( "ShallowCopy_Subspaces", iter -> rec( structure := iter!.structure, basis := iter!.basis, associatedIterator := ShallowCopy( iter!.associatedIterator ) ) ); InstallMethod( Iterator, "for a subspaces domain", [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], function( D ) local V; # the vector space V:= D!.structure; return IteratorByFunctions( rec( IsDoneIterator := IsDoneIterator_Subspaces, NextIterator := NextIterator_Subspaces, ShallowCopy := ShallowCopy_Subspaces, structure := V, basis := Basis( V ), associatedIterator := Iterator( Subspaces( FullRowSpace( LeftActingDomain( V ), Dimension( V ) ), D!.dimension ) ) ) ); end ); ############################################################################# ## #M Subspaces( , ) ## InstallMethod( Subspaces, "for a vector space, and an integer", [ IsVectorSpace, IsInt ], function( V, dim ) if IsFinite( V ) then return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ), rec( structure := V, dimension := dim ) ); else TryNextMethod(); fi; end ); ############################################################################# ## #M Subspaces( ) ## InstallMethod( Subspaces, "for a vector space", [ IsVectorSpace ], function( V ) if IsFinite( V ) then return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ), rec( structure := V, dimension := "all" ) ); else TryNextMethod(); fi; end ); ############################################################################# ## #F IsSubspace( , ) . . . . . . . . . . . . . . . . . check <= ## InstallGlobalFunction( IsSubspace, function( V, U ) return IsVectorSpace( U ) and IsSubset( V, U ); end ); ############################################################################# ## #M IsVectorSpaceHomomorphism( ) ## InstallMethod( IsVectorSpaceHomomorphism, [ IsGeneralMapping ], function( map ) local S, R, F; S:= Source( map ); if not IsVectorSpace( S ) then return false; fi; R:= Range( map ); if not IsVectorSpace( R ) then return false; fi; F:= LeftActingDomain( S ); return ( F = LeftActingDomain( R ) ) and IsLinearMapping( F, map ); end ); ############################################################################# ## #E