############################################################################# ## #W crossed.gi The Wedderga package Osnel Broche Cristo #W Olexandr Konovalov #W Aurora Olivieri #W Gabriela Olteanu #W Ángel del Río ## #############################################################################
############################################################################# ## #R IsCrossedProductObjDefaultRep( <obj> ) ## ## The default representation of an element object is a list of length 2, ## at first position the zero coefficient, at second position a list with ## the coefficients at the even positions, and the magma elements at the ## odd positions, with the ordering as defined for the magma elements. ## ## It is assumed that the arithmetic operations of $G$ produce only ## normalized elements. ##
DeclareRepresentation( "IsCrossedProductObjDefaultRep",
IsPositionalObjectRep,
[ 1, 2 ] );
############################################################################# ## #M ElementOfCrossedProduct( <Fam>, <zerocoeff>, <coeffs>, <words> ) ## ## check whether <coeffs> and <words> lie in the correct domains, ## and remove zeroes. ##
InstallMethod( ElementOfCrossedProduct, "for family, ring element, and two homogeneous lists",
[ IsFamily, IsRingElement, IsHomogeneousList, IsHomogeneousList ], function( Fam, zerocoeff, coeffs, words )
local rep, i, j;
# Check that the data is admissible. if not IsBound( Fam!.defaultType ) then
TryNextMethod(); elif IsEmpty( coeffs ) and IsEmpty( words ) then
return Objectify( Fam!.defaultType, [ zerocoeff, [] ] ); elif not IsIdenticalObj( FamilyObj( coeffs ), Fam!.familyRing ) then
Error( "<coeffs> are not all in the correct domain" ); elif not IsIdenticalObj( FamilyObj( words ), Fam!.familyMagma ) then
Error( "<words> are not all in the correct domain" ); elif Length( coeffs ) <> Length( words ) then
Error( "<coeffs> and <words> must have same length" ); fi;
# Make sure that the list of words is strictly sorted. if not IsSSortedList( words ) then
words:= ShallowCopy( words );
coeffs:= ShallowCopy( coeffs );
SortParallel( words, coeffs ); if not IsSSortedList( words ) then
j:= 1; for i in [ 2 .. Length( coeffs ) ] do if words[i] = words[j] then
coeffs[j]:= coeffs[j] + coeffs[i]; else
j:= j+1;
words[j]:= words[i];
coeffs[j]:= coeffs[i]; fi;
od; for i in [ j+1 .. Length( coeffs ) ] do
Unbind( words[i] );
Unbind( coeffs[i] );
od; fi; fi;
# Create the default representation, and remove zeros.
rep:= [];
j:= 1; for i in [ 1 .. Length( coeffs ) ] do if coeffs[i] <> zerocoeff then
rep[ j ]:= words[i];
rep[ j+1 ]:= coeffs[i];
j:= j+2; fi;
od;
# Return the result
return Objectify( Fam!.defaultType, [ zerocoeff, rep ] ); end );
############################################################################# ## #M ZeroCoefficient( <elm> ) ##
InstallMethod( ZeroCoefficient, "for crossed product element in default repr.",
[ IsElementOfCrossedProduct and IsCrossedProductObjDefaultRep ],
elm -> FamilyObj( elm )!.zeroRing );
############################################################################# ## #M CoefficientsAndMagmaElements( <elm> ) ##
InstallMethod( CoefficientsAndMagmaElements, "for crossed product element in default repr.",
[ IsElementOfCrossedProduct and IsCrossedProductObjDefaultRep ],
elm -> elm![2] );
############################################################################# ## #M PrintObj( <elm> ) . . . . . for crossed product element in default repr. ##
InstallMethod( PrintObj, "for crossed product element",
[ IsElementOfCrossedProduct ], function( elm )
local coeffs_and_words,
i;
coeffs_and_words:= CoefficientsAndMagmaElements( elm ); for i in [ 1, 3 .. Length( coeffs_and_words ) - 3 ] do
Print( "(", coeffs_and_words[i], ")*(", coeffs_and_words[i+1], ")+" );
od;
i:= Length( coeffs_and_words ); if i = 0then
Print( "<zero> of ..." ); else
Print( "(", coeffs_and_words[i-1], ")*(", coeffs_and_words[i], ")" ); fi; end );
############################################################################# ## #M \=( <x>, <y> ) . . . . for two crossed product elements in default repr. ##
InstallMethod( \=, "for two crossed product elements",
IsIdenticalObj,
[ IsElementOfCrossedProduct,
IsElementOfCrossedProduct ], function( x, y )
return CoefficientsAndMagmaElements( x )
= CoefficientsAndMagmaElements( y ); end );
############################################################################# ## #M \<( <x>, <y> ) . . . . for two crossed product elements in default repr. ##
InstallMethod( \<, "for two crossed product elements",
IsIdenticalObj,
[ IsElementOfCrossedProduct,
IsElementOfCrossedProduct ], function( x, y )
local i;
x:= CoefficientsAndMagmaElements( x );
y:= CoefficientsAndMagmaElements( y ); for i in [ 1 .. Minimum( Length( x ), Length( y ) ) ] do if x[i] < y[i] then
return true; elif y[i] < x[i] then
return false; fi;
od;
return Length( x ) < Length( y ); end );
############################################################################# ## #M \+( <x>, <y> ) . . . . for two crossed product elements in default repr. ##
InstallMethod( \+, "for two crossed product elements",
IsIdenticalObj,
[ IsElementOfCrossedProduct,
IsElementOfCrossedProduct ], function( x, y )
local F, sum, z;
F := FamilyObj( x );
z := ZeroCoefficient( x );
x := CoefficientsAndMagmaElements( x );
y := CoefficientsAndMagmaElements( y );
sum:= ZippedSum( x, y, z, [ \<, \+ ] );
return Objectify( F!.defaultType, [ z, sum ] ); end );
############################################################################# ## #M AdditiveInverseOp( <x> ) . . for crossed product element in default repr. ##
InstallMethod( AdditiveInverseOp, "for crossed product element",
[ IsElementOfCrossedProduct ], function( x )
local ext, i;
ext:= ShallowCopy( CoefficientsAndMagmaElements( x ) ); for i in [ 2, 4 .. Length( ext ) ] do
ext[i]:= AdditiveInverse( ext[i] );
od;
return Objectify( FamilyObj( x )!.defaultType, [ ZeroCoefficient(x), ext] ); end );
############################################################################# ## #M \*( <x>, <y> ) . . . . for two crossed product elements in default repr. ##
InstallMethod( \*, "for two crossed product elements",
IsIdenticalObj,
[ IsElementOfCrossedProduct,
IsElementOfCrossedProduct ], function( x, y )
local F, prod, z, mons, cofs, i, j, c, Twisting, Action, R;
F := FamilyObj( x );
Twisting := F!.twisting;
Action := F!.action;
R := F!.crossedProduct;
z := ZeroCoefficient( x );
x := CoefficientsAndMagmaElements( x );
y := CoefficientsAndMagmaElements( y );
# fold the product
mons := [];
cofs := []; for i in [ 1, 3 .. Length(x)-1 ] do for j in [ 1, 3 .. Length(y)-1 ] do # we compute product of the coefficients as follows # (x * a1) * (y * a2) = (x) * (y) * a1^action(y) * a2 = # (x * y) * twisting(x,y) *a1^action(y) * a2
c := Twisting(R,x[i],y[j]) * ( x[i+1]^Action(R,y[j]) * y[j+1] ); if c <> z then ## add the product of the monomials
Add( mons, x[i] * y[j] ); ## and the coefficient
Add( cofs, c ); fi;
od;
od;
# sort monomials
SortParallel( mons, cofs );
# sum coeffs
prod := [];
i := 1; while i <= Length(mons) do
c := cofs[i]; while i < Length(mons) and mons[i] = mons[i+1] do
i := i+1;
c := c + cofs[i]; ## add coefficients
od; if c <> z then ## add the term to the product
Add( prod, mons[i] );
Add( prod, c ); fi;
i := i+1;
od;
return Objectify( F!.defaultType, [ z, prod ] ); end );
############################################################################# ## #M OneOp( <elm> ) ##
InstallMethod( OneOp, "for crossed product element",
[ IsElementOfCrossedProduct ], function( elm )
local F, z;
F:= FamilyObj( elm ); if not IsBound( F!.oneGroup ) then
return fail; fi;
z:= ZeroCoefficient( elm );
return Objectify( F!.defaultType, [ z, [ F!.oneGroup, One( z ) ] ] ); end );
############################################################################# ## #M \*( x, r ) . . . . . . . . . for crossed product element and coefficient #M \*( x, r ) . . . . . . . . . . for crossed product element and rational ## ## We multiply an element of crossed product on the ring element from ## the right, so action is not involved in this multiplication. Note that ## multiplication with zero or zero divisors may cause zero coefficients ## in the result, so we use FMRRemoveZero( <coeffs_and_words>, <zero> ) ## from lib/mgmring.gi. It removes all pairs from <coeffs_and_words> in ## which the coefficient is <zero>, where <coeffs_and_words> is assumed ## to be sorted. ##
CrossedElmTimesRingElm := function( x, y )
local F, i, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
x:= ShallowCopy( CoefficientsAndMagmaElements( x ) ); for i in [ 2, 4 .. Length(x) ] do
x[i]:= x[i] * y;
od;
return Objectify( F!.defaultType, [ z, FMRRemoveZero( x, z ) ] ); end;
############################################################################# ## #M \*( <r>, <x> ) . . . . . . for coefficient and crossed product element #M \*( <r>, <x> ) . . . . . . . . for rational and crossed product element ##
RingElmTimesCrossedElm := function( x, y )
local F, i, z, Action, R;
F:= FamilyObj( y );
Action := F!.action;
R := F!.crossedProduct;
z:= ZeroCoefficient( y );
y:= ShallowCopy( CoefficientsAndMagmaElements( y ) ); # if x is rational, it will be fixed by action if IsRat( x ) then for i in [ 2, 4 .. Length(y) ] do
y[i]:= x * y[i];
od; else for i in [ 2, 4 .. Length(y) ] do
y[i]:= x^Action(R,y[i-1]) * y[i];
od; fi;
return Objectify( F!.defaultType, [ z, FMRRemoveZero( y, z ) ] ); end;
############################################################################# ## #M \*( <m>, <x> ) . . . . . . for group element and crossed product element #M \*( <x>, <m> ) . . . . . . for crossed product element and group element ##
InstallMethod( \*, "for group element and crossed product element", function( FamM, FamRM )
return IsBound( FamRM!.familyMagma ) and
IsIdenticalObj( ElementsFamily( FamRM!.familyMagma ), FamM ); end,
[ IsMultiplicativeElement, IsElementOfCrossedProduct ], function( m, x )
local F, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
return Objectify( F!.defaultType, [ z, [ m, One(z) ] ] ) * x; end );
InstallMethod( \*, "for crossed product element and group element", function( FamRM, FamM )
return IsBound( FamRM!.familyMagma ) and
IsIdenticalObj( ElementsFamily( FamRM!.familyMagma ), FamM ); end,
[ IsElementOfCrossedProduct, IsMultiplicativeElement ], function( x, m )
local F, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
return x * Objectify( F!.defaultType, [ z, [ m, One(z) ] ] ); end );
############################################################################# ## #M \+( <m>, <x> ) . . . . . . for group element and crossed product element #M \+( <x>, <m> ) . . . . . . for crossed product element and group element ##
InstallOtherMethod( \+, "for group element and crossed product element", function( FamM, FamRM )
return IsBound( FamRM!.familyMagma ) and
IsIdenticalObj( ElementsFamily( FamRM!.familyMagma ), FamM ); end,
[ IsMultiplicativeElement, IsElementOfCrossedProduct ], function( m, x )
local F, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
x:= ZippedSum( [ m, One( z ) ],
CoefficientsAndMagmaElements( x ),
z, [ \<, \+ ] );
return Objectify( F!.defaultType, [ z, x ] ); end );
InstallOtherMethod( \+, "for crossed product element and group element", function( FamRM, FamM )
return IsBound( FamRM!.familyMagma ) and
IsIdenticalObj( ElementsFamily( FamRM!.familyMagma ), FamM ); end,
[ IsElementOfCrossedProduct, IsMultiplicativeElement ], function( x, m )
local F, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
x:= ZippedSum( CoefficientsAndMagmaElements( x ),
[ m, One( z ) ],
z, [ \<, \+ ] );
return Objectify( F!.defaultType, [ z, x ] ); end );
############################################################################# ## #M \-( <x>, <m> ) . . . . . . for crossed product element and group element #M \-( <m>, <x> ) . . . . . . for group element and crossed product element ##
InstallOtherMethod( \-, "for crossed product element and group element", function( FamRM, FamM )
return IsBound( FamRM!.familyMagma ) and
IsIdenticalObj( ElementsFamily( FamRM!.familyMagma ), FamM ); end,
[ IsElementOfCrossedProduct, IsMultiplicativeElement ], function( x, m )
local F, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
return x - ElementOfCrossedProduct( F, z, [ One( z ) ], [ m ] ); end );
InstallOtherMethod( \-, "for group element and crossed product element", function( FamM, FamRM )
return IsBound( FamRM!.familyMagma ) and
IsIdenticalObj( ElementsFamily( FamRM!.familyMagma ), FamM ); end,
[ IsMultiplicativeElement, IsElementOfCrossedProduct ], function( m, x )
local F, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
return ElementOfCrossedProduct( F, z, [ One( z ) ], [ m ] ) - x; end );
############################################################################# ## #M \/( x, r ) . . . . . . . . . for crossed product element and coefficient ##
CrossedElmDivRingElm := function( x, y )
local F, i, z;
F:= FamilyObj( x );
z:= ZeroCoefficient( x );
x:= ShallowCopy( CoefficientsAndMagmaElements( x ) ); for i in [ 2, 4 .. Length(x) ] do
x[i]:= x[i] / y;
od;
return Objectify( F!.defaultType, [ z, x ] ); end;
############################################################################# ## #F CrossedProduct( <R>, <G>, act, twist ) ## ## An example of trivial action and twisting for the crossed product RG: ## action should return a mapping R->R that can be applied via "^" operation ## ## function( RG, a ) ## return IdentityMapping( LeftActingDomain( RG ) ); ## end, ## ## twisting should return an (invertible) element of R ## ## function( RG, g, h ) ## return One( LeftActingDomain( RG ) ); ## end ); ## ## to be used in the following way: ## ## g * h = g * h * twisting(g,h) for g,h in G ## a * g = g * a^action(g) for a in R and g in G ##
InstallGlobalFunction( CrossedProduct, function( R, G, act, twist )
local filter, # implied filter of all elements in the new domain
F, # family of crossed product elements
one, # identity of `R'
zero, # zero of `R'
m, # one element of `G'
RG, # free magma ring, result
gens; # generators of the magma ring
# Check the arguments. if not IsRing( R ) or One( R ) = fail then
Error( "<R> must be a ring with identity" ); fi;
if not IsGroup( G ) then
Error( "<G> must be a group" ); fi;
F:= NewFamily( "CrossedProductObjFamily",
IsElementOfCrossedProduct,
IsMultiplicativeElementWithInverse and
IsAssociativeElement );
one:= One( R );
zero:= Zero( R );
F!.defaultType := NewType( F, IsCrossedProductObjDefaultRep );
F!.familyRing := FamilyObj( R );
F!.familyMagma := FamilyObj( G );
F!.zeroRing := zero;
F!.oneGroup := One( G );
F!.action := act;
F!.twisting := twist;
# Set the characteristic. if HasCharacteristic( R ) or HasCharacteristic( FamilyObj( R ) ) then
SetCharacteristic( F, Characteristic( R ) ); fi;
RG:= Objectify( NewType( CollectionsFamily( F ),
IsCrossedProduct and IsAttributeStoringRep ),
rec() );
# Store RG in the family of its elements to make it possible # to extract from RG the data for action and twisting, stored # in OperationRecord( RG )
F!.crossedProduct := RG;
# Set the necessary attributes.
SetLeftActingDomain( RG, R );
SetUnderlyingMagma( RG, G );
SetIsAssociative( RG, true );
# Deduce other useful information. if HasIsFinite( G ) then
SetIsFiniteDimensional( RG, IsFinite( G ) ); fi;
if HasIsWholeFamily( R ) and HasIsWholeFamily( G ) then
SetIsWholeFamily( RG, IsWholeFamily( R ) and IsWholeFamily( G ) ); fi;
# Construct the generators. To get meaningful generators, # we have to handle the case that the groups is trivial.
gens:= GeneratorsOfGroup( G ); if IsEmpty( gens ) then
SetGeneratorsOfLeftOperatorRingWithOne( RG,
[ ElementOfCrossedProduct( F, zero, [ one ], [ One( G ) ] ) ] ); else
SetGeneratorsOfLeftOperatorRingWithOne( RG,
List( gens,
x -> ElementOfCrossedProduct( F, zero, [ one ], [ x ] ) ) ); fi;
# Return the crossed product
return RG; end );
############################################################################# ## #M ViewObj( <RG> ) . . . . . . . . . . . . . . . . . . for a crossed product ##
InstallMethod( ViewObj, "for a crossed product",
[ IsCrossedProduct ], 10, function( RG ) if HasCenterOfCrossedProduct(RG) then
Print( "<crossed product with center ", CenterOfCrossedProduct(RG), " over ", LeftActingDomain( RG ), " of a group of size ", Size(UnderlyingMagma(RG)), ">" ); else
Print( "<crossed product over ", LeftActingDomain( RG ), " of a group of size ", Size(UnderlyingMagma(RG)), ">" ); fi; end );
############################################################################# ## #M Coefficients( <B>, <v> ) . . . . . . for canon. basis of crossed product ##
InstallMethod( Coefficients, "for canon. basis of a crossed product, and an element of a crossed product",
IsCollsElms,
[ IsCanonicalBasisCrossedProductRep, IsElementOfCrossedProduct ], function( B, v )
local coeffs,
data,
elms,
i;
data:= CoefficientsAndMagmaElements( v );
coeffs:= ShallowCopy( B!.zerovector );
elms:= EnumeratorSorted( UnderlyingMagma( UnderlyingLeftModule( B ) ) ); for i in [ 1, 3 .. Length( data )-1 ] do
coeffs[ Position( elms, data[i] ) ]:= data[i+1];
od;
return coeffs; end );
############################################################################# ## #R IsEmbeddingRingCrossedProduct( <R>, <RM> ) ##
DeclareRepresentation( "IsEmbeddingRingCrossedProduct",
IsSPGeneralMapping
and IsMapping
and IsInjective
and RespectsAddition
and RespectsZero
and IsAttributeStoringRep,
[] );
############################################################################# ## #M Embedding( <R>, <RM> ) . . . . . . . . . . for ring and crossed product ##
InstallMethod( Embedding, "for ring and crossed product",
IsRingCollsMagmaRingColls,
[ IsRing, IsCrossedProduct ], function( R, RM )
local emb;
# Check that this is the right method. if Parent( R ) <> LeftActingDomain( RM ) then
TryNextMethod(); elif One( UnderlyingMagma( RM ) ) = fail then
return fail; fi;
# Make the mapping object.
emb := Objectify( TypeOfDefaultGeneralMapping( R, RM,
IsEmbeddingRingCrossedProduct ),
rec() );
# Return the embedding.
return emb; end );
InstallMethod( ImagesElm, "for embedding of ring into crossed product, and ring element",
FamSourceEqFamElm,
[ IsEmbeddingRingCrossedProduct, IsRingElement ], function ( emb, elm )
local F;
F:= ElementsFamily( FamilyObj( Range( emb ) ) );
return [ ElementOfCrossedProduct( F, Zero( elm ), [ elm ],
[ One( UnderlyingMagma( Range( emb ) ) ) ] ) ]; end );
InstallMethod( ImagesRepresentative, "for embedding of ring into crossed product, and ring element",
FamSourceEqFamElm,
[ IsEmbeddingRingCrossedProduct, IsRingElement ], function ( emb, elm )
local F;
F:= ElementsFamily( FamilyObj( Range( emb ) ) );
return ElementOfCrossedProduct( F, Zero( elm ), [ elm ],
[ One( UnderlyingMagma( Range( emb ) ) ) ] ); end );
InstallMethod( PreImagesElmNC, "for embedding of ring into crossed product, and crossed product element",
FamRangeEqFamElm,
[ IsEmbeddingRingCrossedProduct, IsElementOfCrossedProduct ], function ( emb, elm )
local R, extrep;
R:= Range( emb );
extrep:= CoefficientsAndMagmaElements( elm ); if Length( extrep ) = 2
and extrep[1] = One( UnderlyingMagma( R ) ) then
return [ extrep[2] ]; else
return []; fi; end );
InstallMethod( PreImagesRepresentativeNC, "for embedding of ring into crossed product, and crossed product element",
FamRangeEqFamElm,
[ IsEmbeddingRingCrossedProduct, IsElementOfCrossedProduct ], function ( emb, elm )
local R, extrep;
R:= Range( emb );
extrep:= CoefficientsAndMagmaElements( elm ); if Length( extrep ) = 2
and extrep[1] = One( UnderlyingMagma( R ) ) then
return extrep[2]; else
return fail; fi; end );
############################################################################# ## #R IsEmbeddingMagmaCrossedProduct( <M>, <RM> ) ##
DeclareRepresentation( "IsEmbeddingMagmaCrossedProduct",
IsSPGeneralMapping
and IsMapping
and IsInjective
and IsAttributeStoringRep,
[] );
############################################################################# ## #F Embedding( <M>, <RM> ) . . . . . . . . . . for magma and crossed product ##
InstallMethod( Embedding, "for magma and crossed product",
IsMagmaCollsMagmaRingColls,
[ IsMagma, IsCrossedProduct ], function( M, RM )
local emb;
# Check that this is the right method. if not IsSubset( UnderlyingMagma( RM ), M ) then
TryNextMethod(); fi;
# Make the mapping object.
emb := Objectify( TypeOfDefaultGeneralMapping( M, RM,
IsEmbeddingMagmaCrossedProduct ),
rec() );
if IsMagmaWithInverses( M ) then
SetRespectsInverses( emb, true ); elif IsMagmaWithOne( M ) then
SetRespectsOne( emb, true ); fi;
# Return the embedding.
return emb; end );
InstallMethod( ImagesElm, "for embedding of magma into crossed product, and mult. element",
FamSourceEqFamElm,
[ IsEmbeddingMagmaCrossedProduct, IsMultiplicativeElement ], function ( emb, elm )
local R, F;
R:= Range( emb );
F:= ElementsFamily( FamilyObj( R ) );
return [ ElementOfCrossedProduct( F, Zero( LeftActingDomain( R ) ),
[ One( LeftActingDomain( R ) ) ], [ elm ] ) ]; end );
InstallMethod( ImagesRepresentative, "for embedding of magma into crossed product, and mult. element",
FamSourceEqFamElm,
[ IsEmbeddingMagmaCrossedProduct, IsMultiplicativeElement ], function ( emb, elm )
local R, F;
R:= Range( emb );
F:= ElementsFamily( FamilyObj( R ) );
return ElementOfCrossedProduct( F, Zero( LeftActingDomain( R ) ),
[ One( LeftActingDomain( R ) ) ], [ elm ] ); end );
InstallMethod( PreImagesElmNC, "for embedding of magma into crossed product, and crossed product element",
FamRangeEqFamElm,
[ IsEmbeddingMagmaCrossedProduct, IsElementOfCrossedProduct ], function ( emb, elm )
local R, extrep;
R:= Range( emb );
extrep:= CoefficientsAndMagmaElements( elm ); if Length( extrep ) = 2
and extrep[2] = One( LeftActingDomain( R ) ) then
return [ extrep[1] ]; else
return []; fi; end );
InstallMethod( PreImagesRepresentativeNC, "for embedding of magma into crossed product, and crossed product element",
FamRangeEqFamElm,
[ IsEmbeddingMagmaCrossedProduct, IsElementOfCrossedProduct ], function ( emb, elm )
local R, extrep;
R:= Range( emb );
extrep:= CoefficientsAndMagmaElements( elm ); if Length( extrep ) = 2
and extrep[2] = One( LeftActingDomain( R ) ) then
return extrep[1]; else
return fail; fi; end );