mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 09:40:21 +00:00
652 lines
19 KiB
Plaintext
652 lines
19 KiB
Plaintext
#############################################################################
|
|
##
|
|
#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( <extL>, <D> )
|
|
##
|
|
## check whether the left acting domain <D> of the external left set <extL>
|
|
## 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( <M> )
|
|
##
|
|
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( <F>, <gens>[, <zero>][, "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( <F>, <gens>[, <zero>][, \"basis\"] )" );
|
|
fi;
|
|
return CallFuncList( FreeLeftModule, arg );
|
|
end );
|
|
|
|
|
|
#############################################################################
|
|
##
|
|
#M AsSubspace( <V>, <C> ) . . . . . . . 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( <F>, <V> ) . . . . . . for division ring and vector space
|
|
##
|
|
## View the vector space <V> as a vector space over the division ring <F>.
|
|
##
|
|
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( <V> ) . . . . . . . . . . . . . . . . . . . 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( "<vector space over ", LeftActingDomain( V ), ", with ",
|
|
Length( GeneratorsOfLeftModule( V ) ), " generators>" );
|
|
end );
|
|
|
|
InstallMethod( ViewObj,
|
|
"for vector space with known dimension",
|
|
[ IsVectorSpace and HasDimension ],
|
|
1, # override method for known generators
|
|
function( V )
|
|
Print( "<vector space of dimension ", Dimension( V ),
|
|
" over ", LeftActingDomain( V ), ">" );
|
|
end );
|
|
|
|
InstallMethod( ViewObj,
|
|
"for vector space",
|
|
[ IsVectorSpace ],
|
|
function( V )
|
|
Print( "<vector space over ", LeftActingDomain( V ), ">" );
|
|
end );
|
|
|
|
|
|
#############################################################################
|
|
##
|
|
#M PrintObj( <V> ) . . . . . . . . . . . . . . . . . . . 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 \/( <V>, <W> ) . . . . . . . . . factor of a vector space by a subspace
|
|
#M \/( <V>, <vectors> ) . . . . . . 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( <AsStruct>, <Substruct>, <Struct> )
|
|
##
|
|
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( <V>, <W> ) . . . . . . . . . . . . . for two vector spaces
|
|
##
|
|
InstallMethod( Intersection2,
|
|
"method for two vector spaces",
|
|
IsIdenticalObj,
|
|
[ IsVectorSpace, IsVectorSpace ],
|
|
Intersection2Spaces( AsLeftModule, SubspaceNC, VectorSpace ) );
|
|
|
|
|
|
#############################################################################
|
|
##
|
|
#M ClosureLeftModule( <V>, <a> ) . . . . . . . . . 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( <D> )
|
|
##
|
|
## is the representation of domains of subspaces of a vector space <V>,
|
|
## with the components 'structure' (with value <V>) 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 <V>).
|
|
##
|
|
DeclareRepresentation(
|
|
"IsSubspacesVectorSpaceDefaultRep",
|
|
IsComponentObjectRep,
|
|
[ "dimension", "structure" ] );
|
|
#T not IsAttributeStoringRep?
|
|
|
|
|
|
#############################################################################
|
|
##
|
|
#M PrintObj( <D> ) . . . . . . . . . . . . . . . . . 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( <D> ) . . . . . . . . . . . . . . . . . . . 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( <D> ) . . . . . . . . . . . . . . . . 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( <D> ) . . . . . . . . . . . . . . . . . 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( <V>, <dim> )
|
|
##
|
|
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( <V> )
|
|
##
|
|
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( <V>, <U> ) . . . . . . . . . . . . . . . . . check <U> <= <V>
|
|
##
|
|
InstallGlobalFunction( IsSubspace, function( V, U )
|
|
return IsVectorSpace( U ) and IsSubset( V, U );
|
|
end );
|
|
|
|
|
|
#############################################################################
|
|
##
|
|
#M IsVectorSpaceHomomorphism( <map> )
|
|
##
|
|
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
|
|
|