Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346############################################################################# ## #W basis.gi GAP library Thomas Breuer ## ## #Y Copyright (C) 1996, 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 bases. ## ############################################################################# ## #M IsSmallList( <B> ) . . . . . . . . . . . . . . . . . . . . for any basis ## #T preliminary fix: #T Set `IsSmallList' whenever a `BasisVectors' value is entered that knows #T whether it is in `IsSmallList', and whenever a `UnderlyingLeftModule' is #T entered that knows its dimension. #T (This is not sufficient, since immediate methods may be switched off, #T but I do not like the idea to add this kind of code in each method that #T creates a basis object.) ## InstallImmediateMethod( IsSmallList, IsBasis and HasBasisVectors and IsAttributeStoringRep, 0, function( B ) B:= BasisVectors( B ); if HasIsSmallList( B ) then return IsSmallList( B ); fi; TryNextMethod(); end ); InstallImmediateMethod( IsSmallList, IsBasis and HasUnderlyingLeftModule and IsAttributeStoringRep, 0, function( B ) B:= UnderlyingLeftModule( B ); if HasDimension( B ) then return Dimension( B ) <= MAX_SIZE_LIST_INTERNAL; fi; TryNextMethod(); end ); ############################################################################# ## #M IsCanonicalBasis( <B> ) . . . . . . . . . . . . . . . . . . for any basis ## ## Note that we run into an error if no canonical basis is defined for the ## underlying left module of <B>. ## InstallMethod( IsCanonicalBasis, "for a basis", [ IsBasis ], B -> B = CanonicalBasis( UnderlyingLeftModule( B ) ) ); ############################################################################# ## #M \[\]( <B>, <i> ) #M Position( <B>, <v> ) #M Length( <B> ) ## ## Bases are immutable homogeneous lists. ## InstallMethod( \[\], "for a basis and a positive integer", [ IsBasis, IsPosInt ], function( B, i ) return BasisVectors( B )[i]; end ); InstallMethod( Position, "for a basis, an object, and a nonnegative integer", [ IsBasis, IsObject, IsInt ], function( B, v, from ) return Position( BasisVectors( B ), v, from ); end ); InstallMethod( Length, "for a basis", [ IsBasis ], B -> Length( BasisVectors( B ) ) ); ############################################################################# ## #R IsRelativeBasisDefaultRep( <obj> ) ## ## A relative basis <B> is a basis of the free left module <V> ## that delegates the computation of coefficients etc. to another basis <C> ## of <V> via a basechange matrix. ## ## Relative bases in the representation `IsRelativeBasisDefaultRep' need the ## components `basis' (with value <C>) and ## `basechangeMatrix' (with value the base change from <C> to <B>). ## Relative bases in this representation are allowed only for finite ## dimensional modules. ## ## (Also the attribute `BasisVectors' is always present, since relative ## bases are always constructed with explicitly given basis vectors.) ## DeclareRepresentation( "IsRelativeBasisDefaultRep", IsAttributeStoringRep, [ "basis", "basechangeMatrix" ] ); InstallTrueMethod( IsFinite, IsBasis and IsRelativeBasisDefaultRep ); ############################################################################# ## #M RelativeBasis( <B>, <vectors> ) ## InstallMethod( RelativeBasis, "for a basis and a homogeneous list", IsIdenticalObj, [ IsBasis, IsHomogeneousList ], function( B, vectors ) local M, # basechange matrix V, # underlying module of `B' R; # the relative basis, result # Check that the module is finite dimensional. if not IsFinite( vectors ) or not IsFinite( B ) then Error( "<B> and <vectors> must be finite" ); fi; # Compute the basechange matrix. M:= List( vectors, x -> Coefficients( B, x ) ); if not IsEmpty( vectors ) then if fail in M or Length( vectors ) <> Length( M[1] ) then return fail; fi; M:= M^-1; if M = fail then return fail; fi; fi; # If the module is not a vector space, # check that the base change is well-defined for the coefficients ring. V:= UnderlyingLeftModule( B ); if not IsVectorSpace( V ) then R:= LeftActingDomain( V ); if ForAny( M, row -> not IsSubset( R, row ) ) then return fail; fi; fi; # Construct the relative basis. R:= Objectify( NewType( FamilyObj( vectors ), IsFiniteBasisDefault and IsRelativeBasisDefaultRep ), rec() ); SetUnderlyingLeftModule( R, V ); SetBasisVectors( R, AsList( vectors ) ); R!.basis := B; R!.basechangeMatrix := Immutable( M ); # Return the relative basis. return R; end ); ############################################################################# ## #M RelativeBasisNC( <B>, <vectors> ) ## InstallMethod( RelativeBasisNC, "for a basis and a homogeneous list", IsIdenticalObj, [ IsBasis, IsHomogeneousList ], function( B, vectors ) local M, # basechange matrix R; # the relative basis, result # Compute the basechange matrix. if IsEmpty( vectors ) then M:= []; else M:= List( vectors, x -> Coefficients( B, x ) )^-1; fi; # Construct the relative basis. R:= Objectify( NewType( FamilyObj( vectors ), IsFiniteBasisDefault and IsRelativeBasisDefaultRep ), rec() ); SetUnderlyingLeftModule( R, UnderlyingLeftModule( B ) ); SetBasisVectors( R, AsList( vectors ) ); R!.basis := B; R!.basechangeMatrix := Immutable( M ); # Return the relative basis. return R; end ); ############################################################################# ## #M PrintObj( <B> ) . . . . . . . . . . . . . . . . . . . . . . print a basis ## ## print whether the basis is known to be semi-echelonized, ## print the basis vectors if they are known. ## InstallMethod( PrintObj, "for a basis with basis vectors", [ IsBasis and HasBasisVectors ], function( B ) Print( "Basis( ", UnderlyingLeftModule( B ), ", ", BasisVectors( B ), " )" ); end ); InstallMethod( PrintObj, "for a basis", [ IsBasis ], function( B ) Print( "Basis( ", UnderlyingLeftModule( B ), ", ... )" ); end ); #T install better method for quotient spaces, in order to print #T representatives only ? InstallMethod( PrintObj, "for a semi-echelonized basis with basis vectors", [ IsBasis and HasBasisVectors and IsSemiEchelonized ], function( B ) Print( "SemiEchelonBasis( ", UnderlyingLeftModule( B ), ", ", BasisVectors( B ), " )" ); end ); InstallMethod( PrintObj, "for a semi-echelonized basis", [ IsBasis and IsSemiEchelonized ], function( B ) Print( "SemiEchelonBasis( ", UnderlyingLeftModule( B ), ", ... )" ); end ); InstallMethod( PrintObj, "for a canonical basis", [ IsBasis and IsCanonicalBasis ], SUM_FLAGS, function( B ) Print( "CanonicalBasis( ", UnderlyingLeftModule( B ), " )" ); end ); ############################################################################# ## #M ViewObj( <B> ) . . . . . . . . . . . . . . . . . . . . . . view a basis ## ## print whether the basis is known to be semi-echelonized, ## instead of the basis vectors tell the dimension. ## InstallMethod( ViewObj, "for a basis with basis vectors", [ IsBasis and HasBasisVectors ], function( B ) Print( "Basis( " ); View( UnderlyingLeftModule( B ) ); Print( ", " ); View( BasisVectors( B ) ); Print( " )" ); end ); InstallMethod( ViewObj, "for a basis", [ IsBasis ], function( B ) Print( "Basis( " ); View( UnderlyingLeftModule( B ) ); Print( ", ... )" ); end ); InstallMethod( ViewObj, "for a semi-echelonized basis with basis vectors", [ IsBasis and HasBasisVectors and IsSemiEchelonized ], function( B ) Print( "SemiEchelonBasis( " ); View( UnderlyingLeftModule( B ) ); Print( ", " ); View( BasisVectors( B ) ); Print( " )" ); end ); InstallMethod( ViewObj, "for a semi-echelonized basis", [ IsBasis and IsSemiEchelonized ], function( B ) Print( "SemiEchelonBasis( " ); View( UnderlyingLeftModule( B ) ); Print( ", ... )" ); end ); InstallMethod( ViewObj, "for a canonical basis", [ IsBasis and IsCanonicalBasis ], SUM_FLAGS, function( B ) Print( "CanonicalBasis( " ); View( UnderlyingLeftModule( B ) ); Print( " )" ); end ); ############################################################################# ## #M Basis( <D> ) ## InstallImmediateMethod( Basis, IsFreeLeftModule and HasCanonicalBasis and IsAttributeStoringRep, 0, CanonicalBasis ); ############################################################################# ## #M CanonicalBasis( <D> ) . . . . . . . . . . . . . . default, return `fail' ## InstallMethod( CanonicalBasis, "default method, return `fail'", [ IsFreeLeftModule ], ReturnFail ); ############################################################################# ## #M LinearCombination( <B>, <coeff> ) . . . . . . . . lin. comb. w.r.t. basis ## InstallMethod( LinearCombination, "for a basis and a homogeneous list", [ IsBasis, IsHomogeneousList ], function( B, coeff ) local vec, # list of basis vectors of `B' zero, # zero coefficient v, # linear combination, result i; # loop over the basis vectors vec:= BasisVectors( B ); v:= Zero( UnderlyingLeftModule( B ) ); zero:= Zero( LeftActingDomain( UnderlyingLeftModule( B ) ) ); for i in [ 1 .. Length( coeff ) ] do if coeff[i] <> zero then v:= v + coeff[i] * vec[i]; fi; od; return v; end ); InstallOtherMethod( LinearCombination, "for two lists", [ IsList, IsList ], function( B, coeff ) local lincomb, i; if Length( B ) > 0 and Length( B ) = Length( coeff ) then lincomb:= coeff[1] * B[1]; for i in [ 2 .. Length( B ) ] do lincomb:= lincomb + coeff[i] * B[i]; od; return lincomb; else Error( "sorry, can't compute linear combination w.r. to <B>" ); fi; end ); # why not PROD_LIST_LIST_DEFAULT or PROD_LIST_LIST_TRY ?? # (cf. method in fieldfin.gi) # note that coeff and B may be empty, then the zero vector is returned! # (document this for the operation!) ############################################################################# ## #M EnumeratorByBasis( <B> ) . . . . . . . . . . . enumerator w.r.t. a basis ## ## An enumerator w.r.t. a basis <B> that is *not* (known to be) the ## canonical basis of a full row space delegates the task to an enumerator ## <E> for the canonical basis of the corresponding coefficient space; ## a special method is installed for this case. ## ## For this purpose, the following components are provided. ## `coeffspaceenum': ## (with value <E>) ## `basis': ## (with value <B>) ## BindGlobal( "ElementNumber_Basis", function( enum, n ) if Length( enum!.coeffspaceenum ) < n then Error( "<enum>[", n, "] must have an assigned value" ); fi; return LinearCombination( enum!.basis, enum!.coeffspaceenum[ n ] ); end ); BindGlobal( "NumberElement_Basis", function( enum, elm ) elm:= Coefficients( enum!.basis, elm ); if elm <> fail then elm:= Position( enum!.coeffspaceenum, elm ); fi; return elm; end ); InstallMethod( EnumeratorByBasis, "for basis of a finite dimensional left module", [ IsBasis ], function( B ) local V; V:= UnderlyingLeftModule( B ); if not IsFiniteDimensional( V ) then TryNextMethod(); fi; # Return the enumerator. return EnumeratorByFunctions( V, rec( ElementNumber := ElementNumber_Basis, NumberElement := NumberElement_Basis, basis := B, coeffspaceenum := EnumeratorByBasis( CanonicalBasis( FullRowModule( LeftActingDomain(V), Dimension(V) ) ) ) ) ); end ); ############################################################################# ## #M IteratorByBasis( <B> ) . . . . . . . . . . . . . iterator w.r.t. a basis ## ## An iterator of a free left module w.r.t. a basis <B> that is *not* ## (known to be) the basis of a full row space delegates the task to an ## iterator <E> for the corresponding coefficient space; ## a special method is installed for this case. ## ## For this purpose, the following components are provided. ## `coeffspaceiter': ## (with value <E>) ## `basis': ## (with value <B>) ## BindGlobal( "IsDoneIterator_Basis", iter -> IsDoneIterator( iter!.coeffspaceiter ) ); BindGlobal( "NextIterator_Basis", iter -> LinearCombination( iter!.basis, NextIterator( iter!.coeffspaceiter ) ) ); BindGlobal( "ShallowCopy_Basis", iter -> rec( basis := iter!.basis, coeffspaceiter := ShallowCopy( iter!.coeffspaceiter ) ) ); InstallMethod( IteratorByBasis, "for basis of a finite dimensional left module", [ IsBasis ], function( B ) local V; # We delegate to the canonical basis of a full row module, # in order to avoid infinite recursion, we must guarantee # that `B' is not itself such a basis. if ( not HasIsCanonicalBasisFullRowModule( B ) ) and IsCanonicalBasisFullRowModule( B ) and HasIsCanonicalBasisFullRowModule( B ) then return IteratorByBasis( B ); fi; V:= UnderlyingLeftModule( B ); if not IsFiniteDimensional( V ) then TryNextMethod(); fi; return IteratorByFunctions( rec( IsDoneIterator := IsDoneIterator_Basis, NextIterator := NextIterator_Basis, ShallowCopy := ShallowCopy_Basis, basis := B, coeffspaceiter := IteratorByBasis( CanonicalBasis( FullRowModule( LeftActingDomain( V ), Dimension( V ) ) ) ) ) ); end ); ############################################################################# ## #M StructureConstantsTable( <B> ) ## InstallMethod( StructureConstantsTable, "for a basis", [ IsBasis ], function( B ) local A, # underlying algebra vectors, # basis vectors of `A' dim, # dimension (length of basis) zero, # zero of the field sctable, # structure constants table, result empty, # zero product, this entry is shared in the table symmetry, # symmetry flag calc_val, # local function triv, # is the multiplication trivial? i, j; # loop variables A:= UnderlyingLeftModule( B ); vectors:= BasisVectors( B ); dim:= Length( vectors ); zero:= Zero( LeftActingDomain( A ) ); if HasIsZeroMultiplicationRing( A ) and IsZeroMultiplicationRing( A ) then return EmptySCTable( dim, zero, "symmetric" ); fi; sctable:= []; empty:= Immutable( [ [], [] ] ); # Obtain (anti)symmetry information. if HasIsCommutative( A ) and IsCommutative( A ) then symmetry:= 1; elif HasIsAnticommutative( A ) and IsAnticommutative( A ) then symmetry:= -1; else symmetry:= 0; fi; calc_val:= function ( i, j ) local prod, pos; prod:= vectors[i] * vectors[j]; prod:= Coefficients( B, prod ); if prod = fail then Error( "the module of the basis <B> must be closed ", "under multiplication" ); fi; pos:= Filtered( [ 1 .. dim ], x -> prod[x] <> zero ); if IsEmpty( pos ) then sctable[i][j]:= empty; return true; else sctable[i][j]:= Immutable( [ pos, prod{ pos } ] ); return false; fi; end; # Compute the table entries above the diagonal. triv:= true; for i in [ 1 .. dim ] do sctable[i]:= []; for j in [ i+1 .. dim ] do triv:= calc_val( i, j ) and triv; od; od; # Compute the table entries on the diagonal if necessary. if HasIsZeroSquaredRing( A ) and IsZeroSquaredRing( A ) then #T or (characteristic <> 2 and anticommutative)! for i in [ 1 .. dim ] do sctable[i][i] := empty; od; else for i in [ 1 .. dim ] do triv:= calc_val( i, i ) and triv; od; fi; # Compute/set the table entries below the diagonal. if symmetry = 1 then for i in [ 1 .. dim ] do for j in [ 1 .. i-1 ] do sctable[i][j]:= sctable[j][i]; od; od; elif symmetry = -1 then for i in [ 1 .. dim ] do for j in [ 1 .. i-1 ] do sctable[i][j]:= Immutable( [ sctable[j][i][1], -sctable[j][i][2] ] ); od; od; else for i in [ 1 .. dim ] do for j in [ 1 .. i-1 ] do triv:= calc_val( i, j ) and triv; od; od; fi; # If the multiplication is trivial then the table is symmetric. if triv then SetIsZeroMultiplicationRing( A, true ); symmetry:= 1; fi; # Add the identification entries (symmetry flag and zero). sctable[ dim+1 ]:= symmetry; sctable[ dim+2 ]:= zero; # Return the table. MakeImmutable( sctable ); return sctable; end ); ############################################################################# ## ## Default methods for relative bases ## ############################################################################# ## #M Coefficients( <B>, <v> ) . . . . . . . . . . . . . . for relative basis ## InstallMethod( Coefficients, "for relative basis and vector", IsCollsElms, [ IsBasis and IsRelativeBasisDefaultRep, IsVector ], function( B, v ) v:= Coefficients( B!.basis, v ); if v <> fail then v:= v * B!.basechangeMatrix; fi; return v; end ); ############################################################################# ## #M Basis( <V>, <gens> ) #M BasisNC( <V>, <gens> ) ## ## The default for this is a relative basis. ## InstallMethod( Basis, "method returning a relative basis", IsIdenticalObj, [ IsFreeLeftModule, IsHomogeneousList ], function( V, gens ) return RelativeBasis( Basis( V ), gens ); end ); InstallMethod( BasisNC, "method returning a relative basis", IsIdenticalObj, [ IsFreeLeftModule, IsHomogeneousList ], function( V, gens ) UseBasis( V, gens ); return RelativeBasisNC( Basis( V ), gens ); end ); ############################################################################# ## ## Default methods for bases handled by nice bases ## ############################################################################# ## #F InstallHandlingByNiceBasis( <name>, <record> ) ## InstallGlobalFunction( "InstallHandlingByNiceBasis", function( name, record ) local filter, entry; # Check the arguments. if not IsString( name ) then Error( "<name> must be a string" ); elif not IsSubset( RecNames( record ), [ "detect", "NiceFreeLeftModuleInfo", "NiceVector", "UglyVector" ] ) then Error( "<record> has not all necessary components" ); fi; # Get the filter. filter:= ValueGlobal( name ); # Install the detection of the filter. entry:= First( NiceBasisFiltersInfo, x -> IsIdenticalObj( filter, x[1] ) ); Add( entry, record.detect ); InstallTrueMethod( IsHandledByNiceBasis, filter ); filter:= IsFreeLeftModule and filter; # Install the methods. InstallMethod( NiceFreeLeftModuleInfo, Concatenation( "for left module in `", name, "'" ), [ filter ], record.NiceFreeLeftModuleInfo ); InstallMethod( NiceVector, Concatenation( "for left module in `", name, "', and object" ), [ filter, IsObject ], record.NiceVector ); InstallMethod( UglyVector, Concatenation( "for left module in `", name, "', and object" ), [ filter, IsObject ], record.UglyVector ); end ); ############################################################################# ## #F CheckForHandlingByNiceBasis( <F>, <gens>, <V>, <zero> ) ## InstallGlobalFunction( "CheckForHandlingByNiceBasis", function( F, gens, V, zero ) local triple, value; if not IsHandledByNiceBasis( V ) then for triple in NiceBasisFiltersInfo do value:= triple[3]( F, gens, V, zero ); if value = true then SetFilterObj( V, triple[1] ); return; elif value = fail then return; fi; od; fi; end ); ############################################################################# ## #F NiceFreeLeftModuleInfo( <V> ) #F NiceVector( <V>, <v> ) #F UglyVector( <V>, <r> ) ## ## A finite vector space can be handled via the mechanism of nice bases. ## We exclude the situation that all given generators are zero (and thus the ## vector space is trivial) because such a space should be handled be the ## mechanism that deals with nontrivial spaces caontaining it, ## for example in order to admit a consistent ordering of spaces via `\<'. ## InstallHandlingByNiceBasis( "IsGenericFiniteSpace", rec( detect:= function( R, gens, V, zero ) return not IsMagma( V ) and IsFinite( R ) and IsFinite( gens ); end, NiceFreeLeftModuleInfo:= function( V ) local elms, # set of elements, result base, # list of basis vectors fieldelms, # elements set of the coefficients field of `V' gen, # loop over generators i, # loop over field elements new, # intermediate elements list numbers, # list of positions of elements w.r. to construction B; # basis record, result elms := [ Zero( V ) ]; base := []; fieldelms:= Enumerator( LeftActingDomain( V ) ); # Form all linear combinations of the generators. for gen in GeneratorsOfLeftModule( V ) do if not gen in elms then # Form the closure with `gen' Add( base, gen ); new:= []; for i in fieldelms do Append( new, List( elms, x -> x + i * gen ) ); od; elms:= new; fi; od; # Compute the coefficients information. numbers:= [ 1 .. Length( elms ) ]; SortParallel( elms, numbers ); return rec( elements := elms, numbers := numbers, q := Length( fieldelms ), fieldelements := fieldelms, base := base ); end, NiceVector:= function( V, v ) local info, pos, n, coeffs, q, i; info:= NiceFreeLeftModuleInfo( V ); # Compute the $q$-adic expression. pos:= Position( info.elements, v ); if pos = fail then return fail; fi; n:= info.numbers[ pos ] - 1; coeffs:= []; q:= info.q; for i in [ 1 .. Length( info.base ) ] do Add( coeffs, RemInt( n, q ) + 1 ); n:= QuoInt( n, q ); od; # Compute and return the coefficients vector itself. return info.fieldelements{ coeffs }; end, UglyVector:= function( V, r ) local vectors; vectors:= NiceFreeLeftModuleInfo( V ).base; if Length( vectors ) = Length( r ) then return LinearCombination( r, vectors ); else return fail; fi; end ) ); ############################################################################# ## #M NiceFreeLeftModule( <V> ) ## ## This is the rare case where the `NiceFreeLeftModule' value is a full row ## space. ## InstallMethod( NiceFreeLeftModule, "for generic finite space (use that this is a full row module)", [ IsFreeLeftModule and IsGenericFiniteSpace ], V -> FullRowSpace( LeftActingDomain( V ), Length( NiceFreeLeftModuleInfo( V ).base ) ) ); ############################################################################# ## #M NiceFreeLeftModuleInfo( <V> ) #M NiceVector( <V>, <v> ) #M UglyVector( <V>, <r> ) ## ## A finite dimensional vector space of rational functions is handled via ## the mechanism of nice bases. ## InstallHandlingByNiceBasis( "IsSpaceOfRationalFunctions", rec( detect := function( F, gens, V, zero ) return IsRationalFunctionCollection( V ) and ( not IsFLMLOR( V ) or ( HasGeneratorsOfFLMLOR( V ) and ForAll( GeneratorsOfFLMLOR( V ), IsConstantRationalFunction ) ) ); end, NiceFreeLeftModuleInfo := function( V ) local gens, nums, dens, denom, monomials, gen, list, i, zero, info; gens:= GeneratorsOfLeftModule( V ); # Compute the product of denominators. nums:= List( gens, NumeratorOfRationalFunction ); dens:= List( gens, DenominatorOfRationalFunction ); denom:= Product( dens, One( Zero( V ) ) ); monomials:= []; for gen in gens do list:= ExtRepPolynomialRatFun( gen * denom ); UniteSet( monomials, list{ [ 1, 3 .. Length( list ) - 1 ] } ); od; zero:= Zero( LeftActingDomain( V ) ); info:= rec( monomials := monomials, denom := denom, zerocoeff := zero, family := ElementsFamily( FamilyObj( V ) ) ); # For the zero row vector, catch the case of empty `monomials' list. if IsEmpty( monomials ) then info.zerovector := [ zero ]; else info.zerovector := ListWithIdenticalEntries( Length( monomials ), zero ); fi; return info; end, NiceVector := function( V, v ) local info, c, monomials, i, pos; info:= NiceFreeLeftModuleInfo( V ); c:= ShallowCopy( info.zerovector ); v:= v * info.denom; if not IsPolynomial( v ) then return fail; fi; v:= ExtRepPolynomialRatFun( v ); monomials:= info.monomials; for i in [ 2, 4 .. Length( v ) ] do pos:= Position( monomials, v[ i-1 ] ); if pos = fail then return fail; fi; c[ pos ]:= v[i]; od; return c; end, UglyVector := function( V, r ) local info, list, i; info:= NiceFreeLeftModuleInfo( V ); if Length( r ) <> Length( info.zerovector ) then return fail; elif IsEmpty( info.monomials ) then if IsZero( r ) then return Zero( V ); else return fail; fi; fi; list:= []; for i in [ 1 .. Length( r ) ] do if r[i] <> info.zerocoeff then Add( list, info.monomials[i] ); Add( list, r[i] ); fi; od; return PolynomialByExtRep( info.family, list ) / info.denom; end ) ); ############################################################################# ## #M NiceBasis( <B> ) ## InstallMethod( NiceBasis, "for basis by nice basis", [ IsBasisByNiceBasis ], function( B ) local V; V:= UnderlyingLeftModule( B ); if HasBasisVectors( B ) then return Basis( NiceFreeLeftModule( V ), List( BasisVectors( B ), v -> NiceVector( V, v ) ) ); else return Basis( NiceFreeLeftModule( V ) ); fi; end ); ############################################################################# ## #M NiceBasisNC( <B> ) ## InstallMethod( NiceBasisNC, "for basis by nice basis with precomputed basis", [ IsBasisByNiceBasis and HasNiceBasis ], NiceBasis ); InstallMethod( NiceBasisNC, "for basis by nice basis", [ IsBasisByNiceBasis ], function( B ) local A, V; V:= UnderlyingLeftModule( B ); if HasBasisVectors( B ) then A:= BasisNC( NiceFreeLeftModule( V ), List( BasisVectors( B ), v -> NiceVector( V, v ) ) ); else A:= Basis( NiceFreeLeftModule( V ) ); fi; SetNiceBasis( B, A ); return A; end ); #T is this operation meaningful at all?? ############################################################################# ## #M BasisVectors( <B> ) ## InstallMethod( BasisVectors, "for basis by nice basis", [ IsBasisByNiceBasis ], function( B ) local V; V:= UnderlyingLeftModule( B ); return List( BasisVectors( NiceBasis( B ) ), v -> UglyVector( V, v ) ); end ); ############################################################################# ## #M Coefficients( <B>, <v> ) . . . . . . . . for basis handled by nice basis ## ## delegates this task to the associated basis of the nice free left module. ## InstallMethod( Coefficients, "for basis handled by nice basis, and vector", IsCollsElms, [ IsBasisByNiceBasis, IsVector ], function( B, v ) local n; n:= NiceVector( UnderlyingLeftModule( B ), v ); if n = fail then return fail; fi; n:= Coefficients( NiceBasisNC( B ), n ); if n = fail then return fail; fi; if LinearCombination( B, n ) = v then return n; else return fail; fi; end ); ############################################################################# ## #M CanonicalBasis( <V> ) . . . . . . . for free module handled by nice basis ## ## For a free left module that is handled via nice bases, the canonical ## basis is defined as the preimage of the canonical basis of the ## nice free left module. ## InstallMethod( CanonicalBasis, "for free module that is handled by a nice basis", [ IsFreeLeftModule and IsHandledByNiceBasis ], function( V ) local N, # associated nice space of `V' B; # canonical basis of `V', result N:= NiceFreeLeftModule( V ); B:= BasisNC( V, List( BasisVectors( CanonicalBasis( N ) ), v -> UglyVector( V, v ) ) ); SetIsCanonicalBasis( B, true ); return B; end ); ############################################################################# ## #M IsCanonicalBasis( <B> ) . . . . . . . . . for basis handled by nice basis ## InstallMethod( IsCanonicalBasis, "for a basis handled by a nice basis", [ IsBasisByNiceBasis ], function( B ) local V; V:= UnderlyingLeftModule( B ); B:= BasisNC( V, List( BasisVectors( B ), v -> NiceVector( V, v ) ) ); return IsCanonicalBasis( B ); end ); ############################################################################# ## #M Basis( <V> ) . . . . . . . . . . . for free module handled by nice basis ## BasisForFreeModuleByNiceBasis:= function( V ) local B; B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsBasisByNiceBasis and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); return B; end; InstallMethod( Basis, "for free module that is handled by a nice basis", [ IsFreeLeftModule and IsHandledByNiceBasis ], BasisForFreeModuleByNiceBasis ); ############################################################################# ## #M Basis( <V>, <vectors> ) #M BasisNC( <V>, <vectors> ) ## InstallMethod( Basis, "for free module that is handled by a nice basis, and hom. list", IsIdenticalObj, [ IsFreeLeftModule and IsHandledByNiceBasis, IsHomogeneousList ], function( V, vectors ) local B; # Create the basis object. B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsBasisByNiceBasis and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); SetBasisVectors( B, vectors ); # Check whether the vectors in fact form a basis. if NiceBasis( B ) = fail then return fail; fi; # Use the basis information. UseBasis( V, vectors ); # Return the result. return B; end ); InstallMethod( BasisNC, "for free module that is handled by a nice basis, and hom. list", IsIdenticalObj, [ IsFreeLeftModule and IsHandledByNiceBasis, IsHomogeneousList ], function( V, vectors ) local B; # Create the basis object. B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsBasisByNiceBasis and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); SetBasisVectors( B, vectors ); # Use the basis information. UseBasis( V, vectors ); # Return the result. return B; end ); ############################################################################# ## #M NiceFreeLeftModule( <V> ) ## ## There are two default methods. ## ## The first is available if left module generators for <V> are known; ## it returns the free left module generated by the nice vectors ## of the left module generators of <V>. ## ## The second is available if <V> is a FLMLOR for which left operator ## ring(-with-one) generators are known; ## it computes left module generators of <V> via the process of ## closing a basis under multiplications. ## InstallMethod( NiceFreeLeftModule, "for free module that is handled by a nice basis", [ IsFreeLeftModule and HasGeneratorsOfLeftModule and IsHandledByNiceBasis ], function( V ) local gens; gens:= GeneratorsOfLeftModule( V ); if IsEmpty( gens ) or ForAll( gens, IsZero ) then return LeftModuleByGenerators( LeftActingDomain( V ), [], NiceVector( V, Zero( V ) ) ); else return LeftModuleByGenerators( LeftActingDomain( V ), List( gens, v -> NiceVector( V, v ) ) ); fi; end ); BindGlobal( "NiceFreeLeftModuleForFLMLOR", function( A, side ) local Agens, # algebra generators of `A' F, # left acting domain of `A' MB, # mutable basis, result Vgens, # left module generators v; # loop variable # No closure under action is necessary if module generators are known. if HasGeneratorsOfLeftModule( A ) then TryNextMethod(); fi; # Get the algebra generators. Agens:= GeneratorsOfLeftOperatorRing( A ); F:= LeftActingDomain( A ); # Compute a mutable basis for `A'. # If `A' is associative or a Lie algebra then we may use # `MutableBasisOfClosureUnderAction', otherwise we need # `MutableBasisOfNonassociativeAlgebra'. if ( HasIsAssociative( A ) and IsAssociative( A ) ) or ( HasIsLieAlgebra( A ) and IsLieAlgebra( A ) ) then MB:= MutableBasisOfClosureUnderAction( F, Agens, side, Agens, \*, Zero( A ), infinity ); else MB:= MutableBasisOfNonassociativeAlgebra( F, Agens, Zero( A ), infinity ); fi; # Store left module generators. Vgens:= BasisVectors( ImmutableBasis( MB ) ); UseBasis( A, Vgens ); # (Now `A' knows left module generators.) if IsEmpty( Vgens ) then return LeftModuleByGenerators( F, [], NiceVector( A, Zero( A ) ) ); else return LeftModuleByGenerators( F, List( Vgens, v -> NiceVector( A, v ) ) ); fi; end ); InstallMethod( NiceFreeLeftModule, "for FLMLOR that is handled by a nice basis", [ IsFLMLOR and IsHandledByNiceBasis ], A -> NiceFreeLeftModuleForFLMLOR( A, "both" ) ); InstallMethod( NiceFreeLeftModule, "for associative FLMLOR that is handled by a nice basis", [ IsFLMLOR and IsAssociative and IsHandledByNiceBasis ], A -> NiceFreeLeftModuleForFLMLOR( A, "left" ) ); InstallMethod( NiceFreeLeftModule, "for anticommutative FLMLOR that is handled by a nice basis", [ IsFLMLOR and IsAnticommutative and IsHandledByNiceBasis ], A -> NiceFreeLeftModuleForFLMLOR( A, "left" ) ); InstallMethod( NiceFreeLeftModule, "for commutative FLMLOR that is handled by a nice basis", [ IsFLMLOR and IsCommutative and IsHandledByNiceBasis ], A -> NiceFreeLeftModuleForFLMLOR( A, "left" ) ); ############################################################################# ## #M \in( <v>, <V> ) ## InstallMethod( \in, "for vector and free left module that is handled by a nice basis", IsElmsColls, [ IsVector, IsFreeLeftModule and IsHandledByNiceBasis ], function( v, V ) local W, a; W:= NiceFreeLeftModule( V ); a:= NiceVector( V, v ); if a = fail then return false; elif IsZero(a) then return true; else return a in W and v = UglyVector( V, a ); fi; end ); ############################################################################# ## ## Methods for empty bases. ## ## For the construction of empty bases, default methods are sufficient. ## Note that we would need extra methods for each representation of bases ## otherwise, because of the family predicate. ## ## The methods that access empty bases are there mainly to keep this ## special case away from other bases (installation with `SUM_FLAGS'). #T is this allowed? #T (strictly speaking, may other bases assume that these special methods #T will catch the special situation?) ## InstallMethod( Basis, "for trivial free left module", [ IsFreeLeftModule and IsTrivial ], function( V ) local B; B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsEmpty and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); return B; end ); InstallMethod( Basis, "for free left module and empty list", [ IsFreeLeftModule, IsList and IsEmpty ], function( V, empty ) local B; if not IsTrivial( V ) then Error( "<V> is not trivial" ); fi; # Construct an empty basis. B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsEmpty and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); SetBasisVectors( B, empty ); # Return the basis. return B; end ); InstallMethod( BasisNC, "for free left module and empty list", [ IsFreeLeftModule, IsList and IsEmpty ], function( V, empty ) local B; # Construct an empty basis. B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsEmpty and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); SetBasisVectors( B, empty ); # Return the basis. return B; end ); InstallMethod( SemiEchelonBasis, "for free left module and empty list", [ IsFreeLeftModule, IsList and IsEmpty ], function( V, empty ) local B; if not IsTrivial( V ) then Error( "<V> is not trivial" ); fi; # Construct an empty basis. B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsEmpty and IsSemiEchelonized and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); SetBasisVectors( B, empty ); # Return the basis. return B; end ); InstallMethod( SemiEchelonBasisNC, "for free left module and empty list", [ IsFreeLeftModule, IsList and IsEmpty ], function( V, empty ) local B; # Construct an empty basis. B:= Objectify( NewType( FamilyObj( V ), IsFiniteBasisDefault and IsEmpty and IsSemiEchelonized and IsAttributeStoringRep ), rec() ); SetUnderlyingLeftModule( B, V ); SetBasisVectors( B, empty ); # Return the basis. return B; end ); InstallMethod( BasisVectors, "for empty basis", [ IsBasis and IsEmpty ], SUM_FLAGS, B -> [] ); InstallMethod( Coefficients, "for empty basis and vector", IsCollsElms, [ IsBasis and IsEmpty, IsVector ], SUM_FLAGS, function( B, v ) if v = Zero( UnderlyingLeftModule( B ) ) then return []; else return fail; fi; end ); InstallMethod( LinearCombination, "for empty basis and empty list", [ IsBasis and IsEmpty, IsList and IsEmpty ], SUM_FLAGS, function( B, v ) return Zero( UnderlyingLeftModule( B ) ); end ); InstallMethod( SiftedVector, "for empty basis and vector", IsCollsElms, [ IsBasis and IsEmpty, IsVector ], SUM_FLAGS, function( B, v ) return v; end ); ############################################################################# ## #R IsBasisWithReplacedLeftModuleRep( <B> ) ## DeclareRepresentation( "IsBasisWithReplacedLeftModuleRep", IsAttributeStoringRep, [ "basisWithWrongModule" ] ); ############################################################################# ## #F BasisWithReplacedLeftModule( <B>, <V> ) ## InstallGlobalFunction( BasisWithReplacedLeftModule, function( B, V ) local new; new:= Objectify( NewType( FamilyObj( B ), IsFiniteBasisDefault and IsBasisWithReplacedLeftModuleRep ), rec() ); SetUnderlyingLeftModule( new, V ); new!.basisWithWrongModule:= B; return new; end ); ############################################################################# ## #M BasisVectors( <B> ) ## InstallMethod( BasisVectors, "for a basis with replaced left module", [ IsBasis and IsBasisWithReplacedLeftModuleRep ], B -> BasisVectors( B!.basisWithWrongModule ) ); ############################################################################# ## #M Coefficients( <B>, <v> ) ## InstallMethod( Coefficients, "for a basis with replaced left module, and a vector", IsCollsElms, [ IsBasis and IsBasisWithReplacedLeftModuleRep, IsVector ], function( B, v ) return Coefficients( B!.basisWithWrongModule, v ); end ); ############################################################################# ## #M LinearCombination( <B>, <v> ) ## InstallMethod( LinearCombination, "for a basis with replaced left module, and a hom. list", [ IsBasis and IsBasisWithReplacedLeftModuleRep, IsHomogeneousList ], function( B, v ) return LinearCombination( B!.basisWithWrongModule, v ); end ); ############################################################################# ## #M IsCanonicalBasis( <B> ) ## InstallMethod( IsCanonicalBasis, "for a basis with replaced left module, and a vector", [ IsBasis and IsBasisWithReplacedLeftModuleRep ], B -> IsCanonicalBasis( B!.basisWithWrongModule ) ); ############################################################################# ## #E