&FG;-module homomorphisms
The FpGModuleHomomorphismGF datatype

Linear homomorphisms between free &FG;-modules (as FpGModuleGF objects - see Chapter ) are represented in &HAPprime; using the FpGModuleHomomorphismGF datatype. This represents module homomorphisms in a similar manner to \mathbb{F}G-modules, using a set of generating vectors, in this case vectors that generate the images in the target module of the generators of the source module.

Three items need to be passed to the constructor function : source the source FpGModuleGF module for the homomorphism target the target FpGModuleGF module for the homomorphism gens a list of vectors that are the images (in target) under the homomorphisms of each of the generators stored in source
Calculating the kernel of a &FG;-module homorphism by splitting into two homomorphisms

&HAPprime; represents a homomorphism between two &FG;-modules as a list of generators for the image of the homomorphism. Each generator is given as an element in the target module, represented as a vector in the same manner as used in the FpGModuleGF datatype (see Chapter ). Given a set of such generating vectors, an &FF;-generating set for the image of the homomorphism (as elements of the target module's vector space) is given by taking all G-multiples of the generators. Writing the vectors in this expanded set as a matrix, the kernel of the boundary homomorphism is the (left) null-space of this matrix. As with FpGModuleGFs, the block structure of the generating vectors (see Section ) allows this null-space to be calculated without necessarily expanding the whole matrix.

This basic algorithm is implemented in the &HAPprime; function . The generating vectors for a module homomorphism H are divided in half, with the homomorphism generated by the first half of the generating vectors being called U and that by the second half being called V. Given this partition the kernel of H can be defined as ker(H) = preim_U(I) \cap [-preim_V(I)] ker(H) = intersection of preim_U(I) with [-preim_V(I)] where I = im(U) \cap im(V) is the intersection of the images of the two homomorphisms U and V preim_U(I) the set of all preimages of I under U preim_V(I) the set of all preimages of I under V Rather than computing the complete set of preimages, instead the implementation takes a preimage representative of each generator for I and adds the kernel of the homomorphisms U and V. The means that instead of calculating the null-space of the full expanded matrix, we can compute the answer by calculating the kernels of two homomorphisms with fewer generators, as well as the intersection of two modules, and some preimage representatives. Each of these operations takes less memory than the naive null-space calculation. The intersection of two &FG;-modules can be compactly calculated using the generators' block structure (see Section ), while the kernels of U and V can be computed recursively using these same algorithm. The block structure can also help in calculating the preimage, but at a considerable cost in time, so this is not done. However, since U and V have fewer generators than the original homomorphism H, a space saving is still made.

In the case where the problem is seperable, i.e. a U and V can be found for which there is no intersection, this approach can give a large saving. The separable components of the homomorphism can be readily identified from the block structure of the generators (they are the rows which share no blocks or heads with other rows), and the kernels of these can be calculated independently, with no intersection to worry about. This is implemented in the alternative algorithm .
Calculating the kernel of a &FG;-module homorphism by column reduction and partitioning

The list of generators of the image of a &FG;-module homomorphism can be interpreted as the rows of a matrix A with elements in &FG;, and it is the kernel of this matrix which must be found (i.e. the solutions to xA=0. If column reduction is performed on this matrix (by adding &FG;-multiples of other columns to a column), the kernel is left unchanged, and this process can be performed to enable the kernel to be found by a recursive algorithm similar to standard back substitution methods.

Given the matrix A = (a_{ij}), take the &FG;-module generated by the first row (a_{1j}) and find a minimal (or small) subset of elements \{a_{1j}\}_{j \in J} that generate this module. Without altering the kernel, we can permute the columns of A such that J = \{1 \ldots t\}. Taking &FF; and &G;-multiples of these columns from the remaining columns, the first row of these columns can be reduced to zero, giving a new matrix A'. This matrix can be partitioned as follows: \begin{pmatrix} B & 0 \\ C & D \end{pmatrix} [ B 0 ] [ C D ] where B is 1\times t, C is (m-1)\times t and D is (m-1)\times (n-t). It is assumed that B and C are `small' and operations on these can can be easily handled in memory using standard linear algebra, while D may still be large.

Taking the &FG;-module generated by the t columns which form the BC partition of the matrix, we compute E, a set of minimal generators for the submodule of this which is zero in the first row. These are added as columns at the end of A', giving a matrix \begin{pmatrix} B & 0 & 0\\ C & D & E\end{pmatrix} [ B 0 0 ] [ C D E ]

The kernel of this matrix can be shown to be \begin{pmatrix} \ker B & 0\\ L & \ker (DE)\end{pmatrix} [ ker(B) 0 ] [ L ker(DE) ] where L = preim_B((\ker (DE)) C) The augmentation of D with E guarantees that this preimage always exists. Since B and C are small, both \ker B and L are easy to compute using linear algebra, while \ker (DE) can be computed by recursion.

Unfortunately, E can be large, and the accumulated increase of size of the matrix over many recursions negates the time and memory saving that this algorithm might be expected to give. Testing indicates that it is currently no faster than the method, and does not save much memory over the full expansion using linear algebra. An improved version of this algorithm would reduce E by D before augmentation, thus adding a smaller set of generators and restricting the explosion in size. If D were already in echelon form, this would also be time-efficient.

Construction functions
<#Include Label="FpGModuleHomomorphismGF_DTmanFpGModuleHom_Con">

Example: Constructing a FpGModuleHomomorphismGF
In this example we construct the module homomorphism \phi: (\mathbb{F}G)^2 \to \mathbb{F}G which maps both generators of (\mathbb{F}G)^2 to the generator of &FG; gap> G := SmallGroup(8, 4);; gap> im := [1,0,0,0,0,0,0,0]*One(GF(2)); [ Z(2)^0, 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2), 0*Z(2) ] gap> phi := FpGModuleHomomorphismGF( > FpGModuleGF(G, 2), > FpGModuleGF(G, 1), > [im, im]); <Module homomorphism>
Data access functions
<#Include Label="SourceModule_DTmanFpGModuleHom_Dat"> <#Include Label="TargetModule_DTmanFpGModuleHom_Dat"> <#Include Label="ModuleHomomorphismGeneratorMatrix_DTmanFpGModuleHom_Dat"> <#Include Label="DisplayBlocks_DTmanFpGModuleHom_Dat"> <#Include Label="DisplayModuleHomomorphismGeneratorMatrix_DTmanFpGModuleHom_Dat"> <#Include Label="DisplayModuleHomomorphismGeneratorMatrixBlocks_DTmanFpGModuleHom_Dat">

Example: Accessing data about a FpGModuleHomomorphismGF

A free &FG; resolution is a chain complex of &FG;-modules and homomorphisms, and the homomorphisms in a HAPResolution (see Chapter ) can be extracted as a FpGModuleHomomorphismGF using the function . We construct a resolution R and then examine the third resolution in the chain complex, which is a &FG;-module homomorphism d_3 : (\mathbb{F}G)^7 \to (\mathbb{F}G)^5. gap> R := ResolutionPrimePowerGroupRadical(SmallGroup(64, 141), 3);; #I Dimension 2: rank 5 #I Dimension 3: rank 7 gap> d3 := BoundaryFpGModuleHomomorphismGF(R, 3);; gap> SourceModule(d3); Full canonical module FG^7 over the group ring of <pc group of size 64 with 6 generators> in characteristic 2 gap> TargetModule(d3); Full canonical module FG^5 over the group ring of <pc group of size 64 with 6 generators> in characteristic 2 gap> ModuleHomomorphismGeneratorMatrix(d3); <an immutable 7x320 matrix over GF2> gap> DisplayBlocks(d3); Module homomorphism with source: Full canonical module FG^7 over the group ring of Group( [ f1, f2, f3, f4, f5, f6 ] ) in characteristic 2 and target: Full canonical module FG^5 over the group ring of Group( [ f1, f2, f3, f4, f5, f6 ] ) in characteristic 2 and generator matrix: [*.*.*] [*****] [.**..] [.**..] [..**.] [...**] [...*.]

Note that the module homomorphism generating vectors in a resolution calculated using &HAPprime; are in block-echelon form (see Section ). This makes it efficient to compute the kernel of this homomorphism using , as described in Section , since there is only a small intersection between the images generated by the top and bottom halves of the generating vectors.
Image and kernel functions
<#Include Label="ImageOfModuleHomomorphism_DTmanFpGModuleHom_Ima"> <#Include Label="PreImageRepresentativeOfModuleHomomorphism_DTmanFpGModuleHom_Ima"> <#Include Label="KernelOfModuleHomomorphism_DTmanFpGModuleHom_Ima">

Example: Kernel and Image of a FpGModuleHomomorphismGF

A free &FG;-resolution of a module is an exact sequence of module homomorphisms. In this example we use the functions and to check that one of the sequences in a resolution is exact, i.e. that in the sequence M_3 \to M_2 \to M_1 M_3 -> M_2 -> M_1 the image of the first homomorphism d_3: M_3 \to M_2 is the kernel of the second homomorphism d_2: M_2 \to M_1

We also demonstrate that we can find the image and preimage of module elements under our module homomorphisms. We take an element e of M_2, in this case by taking the first generating element of the kernel of d_2, and map it up to M_3 and back.

Finally, we compute the kernel using the other available methods, and check that the results are the same. gap> R := ResolutionPrimePowerGroupRadical(SmallGroup(8, 3), 3);; gap> d2 := BoundaryFpGModuleHomomorphismGF(R, 2);; gap> d3 := BoundaryFpGModuleHomomorphismGF(R, 3);; gap> # gap> I := ImageOfModuleHomomorphism(d3); Module over the group ring of <pc group of size 8 with 3 generators> in characteristic 2 with 4 generators in FG^3. gap> K := KernelOfModuleHomomorphism(d2); Module over the group ring of <pc group of size 8 with 3 generators> in characteristic 2 with 15 generators in FG^3. gap> I = K; true gap> # gap> e := ModuleGenerators(K)[1];; gap> PreImageRepresentativeOfModuleHomomorphism(d3, e); <a GF2 vector of length 32> gap> f := PreImageRepresentativeOfModuleHomomorphism(d3, e); <a GF2 vector of length 32> gap> ImageOfModuleHomomorphism(d3, f); <a GF2 vector of length 24> gap> last = e; true gap> # gap> L := KernelOfModuleHomomorphismSplit(d2); Module over the group ring of <pc group of size 8 with 3 generators> in characteristic 2 with 5 generators in FG^3. gap> K = L; true gap> M := KernelOfModuleHomomorphismGF(d2); Module over the group ring of <pc group of size 8 with 3 generators> in characteristic 2 with 4 generators in FG^ 3. Generators are minimal. gap> K = M; true