#############################################################################
##
#W  extensions.gi     Extensions [loops]
##  
#H  @(#)$Id: extensions.gi, v 3.0.0 2015/06/15 gap Exp $
##  
#Y  Copyright (C)  2004,  G. P. Nagy (University of Szeged, Hungary),  
#Y                        P. Vojtechovsky (University of Denver, USA)
##

#############################################################################
##  
#O  LoopByExtension( K, F, phi, theta ) 
##    
##  Let K be an abelian group, F a loop, phi: F --> Aut( K ) a homomorphism,
##  and theta: F x F --> K a map (cocycle) satisfying theta(1,x) = theta(x,1)
##  = 1. Then the function returns the extension K x F with multiplication *
##  defined by (a,x)*(b,y) = (a   phi(x)(b)   theta(x,y),  xy).
##  
##  Note about arguments: 
##      phi is a list of length |F| of permutations of [1, ..., K ],
##      theta is am |F| by |F| matrix of numbers from [1, ..., K].

InstallMethod( LoopByExtension, "for a commutative associative loop and a loop",
    [ IsLoop, IsLoop, IsList, IsMatrix ],
function( K, F, phi, theta )                              
    local nK, nF, ctK, ctF, ct, a, b, x, y, c, z;
    # only some properties of the arguments are checked
    if not IsAssociative( K ) then Error("LOOPS: <1> must be an associative loop."); fi;
    if not IsCommutative( K ) then Error("LOOPS: <1> must be a commutative loop."); fi;
    # sizes
    nK := Size( K );
    nF := Size( F );
    # making sure all is canonical
    ctK := CanonicalCayleyTable( CayleyTable( K ) );
    ctF := CanonicalCayleyTable( CayleyTable( F ) );
    # future Cayley table
    ct := List([1..nK*nF], i -> 0 * [1..nK*nF] );
    # constructing the Cayley table
    for a in [1..nK] do for b in [1..nK] do for x in [1..nF] do for y in [1..nF] do
        c := ctK[ a ][ b^phi[x] ];
        c := ctK[ c ][ theta[ x ][ y ] ];
        z := ctF[ x ][ y ];
        ct[ nK*(x-1) + a ][ nK*(y-1) + b ] := nK*(z-1) + c;
    od; od; od; od;
    return LoopByCayleyTable( ct );
end);

#############################################################################
##  
#O  NuclearExtension( Q, K ) 
##    
##  Let Q be a loop and K an abelian normal subloop of Q contained in the 
##  nucleus of Q. Then Q is an extension of K by Q/K = F via a map 
##  phi: F --> Aut( K ) and a cocycle theta: F x F --> K, as above. 
##  This function returns the for ingredients [ K, F, phi, theta ], 
##  all in a canonical form.

InstallMethod( NuclearExtension, "for a loop and a normal nuclear subloop",
    [ IsLoop, IsLoop ],
function( Q, K )                
    local F, t, phi, theta, i, j, elmK;              
    # checking arguments
    if not IsNormal( Q, K ) then Error("LOOPS: <2> must be a normal subloop of <1>."); fi;
    if not IsCommutative( K ) then Error("LOOPS: <2> must be a commutative loop."); fi;
    if not ForAll( K, k -> k in Nuc( Q ) ) then Error("LOOPS: <2> must be contained in the nucleus of <1>."); fi;
    # partitioning Q nicely into cosets of K (not needed but it aids in visualization)
    Q := IsomorphicCopyByNormalSubloop( Q, K );
    K := Subloop( Q, [1..Size(K)] );
    F := FactorLoop( Q, K );
    t := List( [1..Size(F)], i -> Elements(Q)[(i-1)*Size(K) + 1] ); #transversal
    phi := List( t, x -> RestrictedPerm( MiddleInnerMapping( Q, x ), [1..Size(K)] ) ); #action
    theta := List( [1..Size(F)], i -> [1..Size(F)] ); #cocycle
    for i in [1..Size(F)] do for j in [1..Size(F)] do
        elmK := RightDivision( t[i]*t[j], t[ CayleyTable( F )[ i ][ j ] ] );
        theta[ i ][ j ] := Position( Elements( K ), elmK );
    od; od;
    return [ K, F, phi, theta ];
end);
