Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/fining/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 27.6.2023 mit Größe 101 kB image not shown  

Quelle  group.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

##########################################################################
##
##  group.gi              FinInG package
##                                                              John Bamberg
##                                                              Anton Betten
##                                                              Jan De Beule
##                                                             Philippe Cara
##                                                            Michel Lavrauw
##                                                           Max Neunhoeffer
##
##  Copyright 2018 Colorado State University
##                  Sabancı Üniversitesi
##     Università degli Studi di Padova
##     Universiteit Gent
##     University of St. Andrews
##     University of Western Australia
##                  Vrije Universiteit Brussel
##
##
##  Implementation stuff for our "projective groups"
##
############################################################################

## helping function. came from projectivespace.gi

# CHECKED 5/09/11 jdb
# We are currently CVec'ing everything. I decide to keep this function as is, and
# convert its output where appriopriate to a list of cvecs
# This makes that converting the vectors here to a dirty GAP vector is useless, so I
# uncommented the if q <= 256 statement.
#############################################################################
#F  MakeAllProjectivePoints( f,d )
# Global function to compute all points of a projective space. Not for users.
# <f>: field; <d>: *projective* dimension.
##
InstallGlobalFunction( MakeAllProjectivePoints, 
function(f,d)

  # f is a finite field
  # d an integer >= 1
  # This function is used for computing the permutation representation (NiceMonomorphism)
  # quickly and with the least memory used as possible, for a projective group.
  # Later, we will convert everything here to CVec's, which should give us an
  # improved permutation representation. For example:
  #   gap> pg:=PG(5,5);
  #   ProjectiveSpace(5, 5)
  #   gap> g:=ProjectivityGroup(pg);
  #   PGL(6,5)
  #   gap> hom := NiceMonomorphism(g);
  #   <action isomorphism>
  #   gap> omega:=UnderlyingExternalSet(hom);;
  #   gap> Random(omega);
  #   ## returns a compressed vector


  local els,i,j,l,q,sp,v,vs,w,ww,x;
  els := Elements(f);
  q := Length(els);
  v := CVec([1..d+1]*Zero(f),f); # using cvecs (ml 31/03/13) 
  #v := ListWithIdenticalEntries(d+1,Zero(f));
  #if q <= 256 then ConvertToVectorRep(v,q); fi;
  vs := EmptyPlist(q^d);
  sp := EmptyPlist((q^(d+1)-1)/(q-1));
  for x in els do
    w := ShallowCopy(v);
    w[d+1] := x;
    Add(vs,w);
  od;
  w := ShallowCopy(v);
  w[d+1] := One(f);
  Add(sp,w);
  for i in [d,d-1..1] do
    l := Length(vs);
    for j in [1..l] do
      ww := ShallowCopy(vs[j]);
      ww[i] := One(f);
      Add(sp,ww);
      Add(vs,ww);
    od;
    if i > 1 then
        for x in els do
          if not(IsZero(x)) and not(IsOne(x)) then
            for j in [1..l] do
              ww := ShallowCopy(vs[j]);
              ww[i] := x;
              Add(vs,ww);
            od;
          fi;
        od;
    fi;
  od;
  return Set(sp);
end);


## make this a global function? Definitely (jdb, 6/9/11).

# CHECKED 6/09/11 jdb
#############################################################################
#F  IsFiningScalarMatrix( a)
#returns true if <a> is a scalar matrix.
##
InstallGlobalFunction(IsFiningScalarMatrix,
 function( a )
 local n;
 n := a[1,1];
 if IsZero(n) then 
  return false;
 else
  return IsOne(a/n);
 fi;
 end );


###################################################################
# Construction of "projective elements", that is matrices modulo scalars:
###################################################################

## A lot of the following is now obselete. We should consider
## deleting some of it.

# CHECKED 5/09/11 jdb
# We are in the very big cvec operation and will skip all methods for non frob groups right now. 19/3/2014.
# I am not completely happy with the behaviour of this method, since there might
# be some issue with the field.
# On the other hand, it is not intended for the user and might even be obselete
#############################################################################
#O  ProjEl( <mat> )
# method to construct an object in the category IsProjGrpEl, i.e. projectivities, 
# aka "matrices modulo scalars". This method is not intended for the users. 
# it has no checks built in. It relies on DefaultFieldOfMatrix to determine the 
# field to be used.
##
InstallMethod( ProjEl, 
 "for a ffe matrix",
 [IsMatrix and IsFFECollColl],
 function( m )
  local el, m2, f;
     m2 := ShallowCopy( m );
  f := DefaultFieldOfMatrix(m);
  ConvertToMatrixRepNC( m2, f );
  el := rec( mat := m2, fld := f );
  Objectify( NewType( ProjElsFamily,
       IsProjGrpEl and
       IsProjGrpElRep ), el );
  return el;
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  ProjEls( <mat> )
# method to construct objects in the category IsProjGrpEl, i.e. projectivities, 
# aka "matrices modulo scalars". This method is not intended for the users.
# it has no checks built in, and is almost liek ProjEl.
## 
InstallMethod( ProjEls, "for a list of ffe matrices",
  [IsList],
  function( l )
    local el,fld,ll,m,ty,m2;
    fld := FieldOfMatrixList(l);
    ll := [];
    ty := NewType( ProjElsFamily,
                   IsProjGrpEl and
                   IsProjGrpElRep );
    for m in l do
        m2 := ShallowCopy(m);
  ConvertToMatrixRepNC( m2, fld );
        el := rec( mat := m2, fld := fld );
        Objectify( ty, el );
        Add(ll,el);
    od;
    return ll;
  end );

# CHECKED 5/09/11 jdb # changed ml 8/11/12
# changed 19/3/2014 to cmat.
#############################################################################
#O  Projectivity( <mat>, <gf> )
# method to construct an object in the category IsProjGrpElWithFrob, but with
# field automorphism equal to the identity, i.e. a projectivity, 
# This method is intended for the user, and contains
# a check whether the matrix is non-singular.
## 
InstallMethod( Projectivity, [ IsMatrix and IsFFECollColl, IsField],
    ## A bug was found here, during a nice August afternoon involving pigeons,
    ## where the variable m2 was assigned to the size of the field.
    ## jdb 13/12/08, Giessen, cold saturday afternoon. I still remember the
    ## pigeons, so does my computer. I add some lines now to check whether the
    ## matrix is non singular. 
   function( mat, gf )
  local el, m2, fld, frob, cmat;
  m2 := ShallowCopy(mat);
  #if NrCols(m2) <> NrRows(m2) then
  # Error("<mat> must be a square matrix");
  #fi;
  if Rank(m2) <> Size(m2) then
   Error("<mat> must not be singular");
  fi;
  #ConvertToMatrixRep( m2, gf );
  cmat := NewMatrix( IsCMatRep, gf, Size(m2) , m2);
  el := rec( mat := cmat, fld := gf, frob := FrobeniusAutomorphism(gf)^0 );
  Objectify( ProjElsWithFrobType, el );
  return el;
 end );

# added 19/3/2014 (cmat).
#############################################################################
#O  Projectivity( <mat>, <gf> )
# method to construct an object in the category IsProjGrpElWithFrob,
# as above, with input a cmat and field
## 
InstallMethod( Projectivity, [ IsCMatRep and IsFFECollColl, IsField],
   function( mat, gf )
  local el, m2, fld, frob, cmat;
  m2 := ShallowCopy(mat);
  #if NrCols(m2) <> NrRows(m2) then
  # Error("<mat> must be a square matrix");
  #fi;
  if Rank(m2) <> NrRows(m2) then
   Error("<mat> must not be singular");
  fi;
  #ConvertToMatrixRep( m2, gf );
  el := rec( mat := m2, fld := gf, frob := FrobeniusAutomorphism(gf)^0 );
  Objectify( ProjElsWithFrobType, el );
  return el;
 end );


# Added ml 8/11/2012
#############################################################################
#O  Projectivity( <pg>, <mat> )
# method to construct an object in the category IsProjGrpEl, i.e. a projectivity, 
# This method is intended for the user, and contains
# a check whether the matrix is non-singular.
## 
InstallMethod( Projectivity, [ IsProjectiveSpace, IsMatrix],
#
   function( pg, mat )
  local d,gf,m2;
  d:=Dimension(pg);
  gf:=pg!.basefield;
  if d <> NrRows(mat)-1 then
   Error("The arguments <mat> and <pg> are incompatible");
  fi;
  m2 := ShallowCopy(mat);
  #if NrCols(m2) <> NrRows(m2) then
  # Error("<mat> must be a square matrix");
  #fi;
  if Rank(m2) <> NrRows(m2) then
   Error("<mat> must not be singular");
  fi;
  return Projectivity(mat,gf);
 end );

# Added ml cmat version 19/3/14.
#############################################################################
#O  Projectivity( <pg>, <mat> )
# method to construct an object in the category IsProjGrpEl, i.e. a projectivity, 
# This method is intended for the user, and contains
# a check whether the matrix is non-singular.
## 
InstallMethod( Projectivity, [ IsProjectiveSpace, IsCMatRep],
#
   function( pg, mat )
  local d,gf,m2;
  d:=Dimension(pg);
  gf:=pg!.basefield;
  if d <> NrRows(mat)-1 then
   Error("The arguments <mat> and <pg> are incompatible");
  fi;
  m2 := ShallowCopy(mat);
  #if NrCols(m2) <> NrRows(m2) then
  # Error("<mat> must be a square matrix");
  #fi;
  if Rank(m2) <> NrRows(m2) then
   Error("<mat> must not be singular");
  fi;
  return Projectivity(mat,gf);
 end );


###################################################################
# Tests whether collineation is a projectivity and so on ...
###################################################################

# Added ml 7/11/2012
#############################################################################
#O  IsProjectivity( <g> )
## 
InstallMethod( IsProjectivity, [ IsProjGrpEl ],
  function( g )
 return true;
  end );

# Added ml 7/11/2012
#############################################################################
#O  IsProjectivity( <g> )
# method to check if a given collineation of a projective space is a projectivity, 
# i.e. if the corresponding frobenius automorphism is the identity
## 
InstallMethod( IsProjectivity, [ IsProjGrpElWithFrob ],
  function( g )
    local F,sigma;
  F:=g!.fld;
  sigma:=g!.frob;
  if sigma = FrobeniusAutomorphism(F)^0
  then return true;
  else return false;
  fi;
  end );

# Added ml 8/11/2012 # changed ml 28/11/2012
#############################################################################
#O  IsStrictlySemilinear( <g> )
## 
InstallMethod( IsStrictlySemilinear, [ IsProjGrpEl],
  function( g )
 return false;
  end );

# Added ml 8/11/2012 # changed ml 28/11/2012
#############################################################################
#O  IsStrictlySemilinear( <g> )
# method to check if a given collineation of a projective space is semilinear, 
# i.e. if the corresponding frobenius automorphism is NOT the identity
## 
InstallMethod( IsStrictlySemilinear, [ IsProjGrpElWithFrob],
  function( g )
    local F,sigma;
  F:=g!.fld;
  sigma:=g!.frob;
  if sigma = FrobeniusAutomorphism(F)^0
  then return false;
  else return true;
  fi;
  end );

  
  
# Added ml 8/11/2012
#############################################################################
#O  IsCollineation( <g> )
## 
InstallMethod( IsCollineation, [ IsProjGrpEl],
  function( g )
 return true;
  end );

# Added ml 8/11/2012
#############################################################################
#O  IsCollineation( <g> )
## 
InstallMethod( IsCollineation, [ IsProjGrpElWithFrob],
  function( g )
    return true;
end );


# Added ml 7/11/2012
#############################################################################
#O  IsProjectivityGroup( <G> )
# method to check if a given projective collineation group G is a projectivity group, 
# i.e. if the corresponding frobenius automorphisms of the generators are the identity
## 
InstallMethod( IsProjectivityGroup, [ IsProjectiveGroupWithFrob],
  function( G )
    local gens, F, set, g;
  gens:=GeneratorsOfMagmaWithInverses(G);
  F:=gens[1]!.fld;
  set:=AsSet(List(gens,g->g!.frob));
  if set = AsSet([FrobeniusAutomorphism(F)^0])
  then return true;
  else return false;
  fi;
  end );


# Added ml 8/11/2012
#############################################################################
#O  IsCollineationGroup( <G> )
##
InstallMethod( IsCollineationGroup, [ IsProjectiveGroupWithFrob],
  function( G )
 return true;
  end );

###################################################################
# Construction of "projective collineation maps", that is matrices 
# modulo scalars with frobenius automorphism
###################################################################

# CHECKED 5/09/11 jdb
# cmat changed 19/3/14
#############################################################################
#O  ProjElWithFrob( <mat>, <frob>, <f> )
# method to construct an object in the category IsProjGrpElWithFrob, i.e. projective 
# semilinear maps aka "matrices modulo scalars with frob". This method is not 
# intended for the users, it has no checks built in.
##
InstallMethod( ProjElWithFrob, 
 "for a cmat/ffe matrix and a Frobenius automorphism, and a field",
 [IsCMatRep and IsFFECollColl, #changed 19/3/14 to cmat.
 IsRingHomomorphism and IsMultiplicativeElementWithInverse,
 IsField],
 function( m, frob, f )
  local el, m2;
  m2 := ShallowCopy(m);
  #ConvertToMatrixRep( m2, f );
  el := rec( mat := m2, fld := f, frob := frob );
  Objectify( ProjElsWithFrobType, el );
  return el;
 end );
 
# added 19/03/14
#############################################################################
#O  ProjElWithFrob( <mat>, <frob>, <f> )
# method to construct an object in the category IsProjGrpElWithFrob, i.e. projective 
# semilinear maps aka "matrices modulo scalars with frob". This method is not 
# intended for the users, it has no checks built in.
##
InstallMethod( ProjElWithFrob, 
 "for a ffe matrix and a Frobenius automorphism, and a field",
 [IsMatrix and IsFFECollColl, 
 IsRingHomomorphism and IsMultiplicativeElementWithInverse,
 IsField],
 function( m, frob, f )
  local el, m2, cmat;
  m2 := ShallowCopy(m);
  #ConvertToMatrixRep( m2, f );
  cmat := NewMatrix(IsCMatRep,f,NrCols(m2),m2);
  el := rec( mat := cmat, fld := f, frob := frob );
  Objectify( ProjElsWithFrobType, el );
  return el;
 end );
 

# CHECKED 5/09/11 jdb
# cmat changed 19/3/14
#############################################################################
#O  ProjElWithFrob( <mat>, <frob> )
# method to construct an object in the category IsProjGrpElWithFrob, i.e. projective 
# semilinear maps aka "matrices modulo scalars with frob". This method is not 
# intended for the users, although there are some checks built in. 
# This method relies on DefaultFieldOfMatrix and Range(<frbo>) to determine the field to be used
##
InstallMethod( ProjElWithFrob, 
 "for a cmat/ffe matrix and a Frobenius automorphism",
 [IsCMatRep and IsFFECollColl, #changed 19/3/14. 
 IsRingHomomorphism and IsMultiplicativeElementWithInverse], 
 1, #to set higher priority than the next method.
 function ( m, frob )
  local matrixfield, frobfield, mchar, fchar, dim;
  if IsOne(frob) then
    TryNextMethod();
  fi;
  matrixfield := DefaultFieldOfMatrix(m);
  mchar := Characteristic(matrixfield);
  frobfield := Range(frob);
  fchar := Characteristic(frobfield);
  if mchar <> fchar then
    Error("the matrix and automorphism do not agree on the characteristic");
  fi;
  
  # figure out a field which contains the matrices and admits the
  # automorphisms (nontrivially)
  dim := Lcm(
    LogInt(Size(matrixfield),mchar),
   LogInt(Size(frobfield),fchar)
   );
 return ProjElWithFrob( m, frob, GF(mchar^dim) );
 end);
 
# CHECKED 5/09/11 jdb
# cmat changed 19/3/14
#############################################################################
#O  ProjElWithFrob( <mat>, <frob> )
# method to construct an object in the category IsProjGrpElWithFrob, i.e. projective 
# semilinear maps aka "matrices modulo scalars with frob". This method is not 
# intended for the users; in fact this method is almost the same as the first version.
# This method relies on DefaultFieldOfMatrix to determine the field to be used
# This method should only be called from the above one, if IsOne(frob) is true,
# but we built in a little check to abvoid disasters.
##
InstallMethod( ProjElWithFrob, 
 "for a cmat/ffe matrix and a trivial Frobenius automorphism",
 [IsCMatRep and IsFFECollColl,
 IsRingHomomorphism and IsMultiplicativeElementWithInverse], 
 0, #to set lower priority than the previous method.
 function( m, frob )
  local el, m2;
  if not IsOne(frob) then
    Error("<frob> is not trivial. Something went wrong when calling this method");
  fi;
  m2 := ShallowCopy(m); 
  #ConvertToMatrixRepNC( m2 );
  el := rec( mat := m2, fld := DefaultFieldOfMatrix(m), frob := frob );
  Objectify( ProjElsWithFrobType, el );
  return el;
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  ProjElsWithFrob( <l>, <f> )
# method to construct a list of objects in the category IsProjGrpElWithFrob,
# using a list of pairs of matrix/frobenius automorphism, and a field.
# This method relies of ProjElWithFrob, and is not inteded for the user.
# no checks are built in. This could result in e.g. the use of a field that is 
# not compatible with (some of) the matrices, and result in a non user friendly 
# error
##
InstallMethod( ProjElsWithFrob,
 "for a list of pairs of ffe matrices and frobenius automorphisms, and a field",
 [IsList, IsField],
 function( l, f )
 local objectlist, m;
  objectlist := [];
  for m in l do
   Add(objectlist, ProjElWithFrob(m[1],m[2],f));
  od;
  return objectlist;
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  ProjElsWithFrob( <l> )
# method to construct a list of objects in the category IsProjGrpElWithFrob,
# using a list of pairs of matrix/frobenius automorphism. It is checked if 
# the given matrices/automorphism pairs can be considered over a common field.
# This method relies eventually also on ProjElWithFrob, and is not inteded for the user,
# although the mechanism of fining the suitable field will display an error 
# if this is not possible.
##
InstallMethod( ProjElsWithFrob, 
 "for a list of pairs of cmat/ffe matrices and Frobenius automorphisms",
 [IsList],
 function( l )
    local matrixfield, frobfield, mchar, fchar, oldchar, f, dim, m, objectlist;
    if(IsEmpty(l)) then
  return [];
  fi;
  dim := 1;

  # get the characteristic of the field that we want to work in.
  # it should be the same for every matrix and every automorphism --
  # if not we will raise an error.
  oldchar := Characteristic(l[1][1]);
  for m in l do
    matrixfield := DefaultFieldOfMatrix(m[1]);
    mchar := Characteristic(matrixfield);
    frobfield := Range(m[2]);
    fchar := Characteristic(frobfield);
    if mchar <> fchar or mchar <> oldchar then
      Error("matrices and automorphisms do not agree on the characteristic");
    fi;
  
    # at each step we increase the dimension of the desired field
  # so that it contains all the matrices and admits all the automorphisms
  # (nontrivially.)
  
    dim := Lcm( dim, LogInt(Size(matrixfield),mchar),
     LogInt(Size(frobfield),fchar));
  od;

  f := GF(oldchar ^ dim);
  objectlist := [];
  for m in l do
   Add(objectlist, ProjElWithFrob(m[1],m[2],f));
  od;
  return objectlist;
 end );


# CHECKED 5/09/11 jdb # changed ml 8/11/12
#############################################################################
#O  CollineationOfProjectiveSpace( <mat>, <gf> )
# method to construct an object in the category IsProjGrpElWithFrob, i.e. a 
# collineation of a projective space. 
# This method is intended for the user, and contains
# a check whether the matrix is non-singular. The method relies on ProjElWithFrob,
# which will produce an error if the entries of <mat> do not all belong to <gf>
# the automorphism will be trivial. Mathematically this is a projectivity.
## 
InstallMethod( CollineationOfProjectiveSpace, 
 [ IsMatrix and IsFFECollColl, IsField],
 function( mat, gf )
    if Rank(mat) <> NrRows(mat) then
  Error("<mat> must not be singular");
    fi;
    return ProjElWithFrob( mat, IdentityMapping(gf), gf);
 end );

# Added ml 8/11/2012
#############################################################################
#O  CollineationOfProjectiveSpace( <pg>, <mat> )
# method to construct an collineation of a projective space.
## 
InstallMethod( CollineationOfProjectiveSpace, [ IsProjectiveSpace, IsMatrix],
#
   function( pg, mat )
  local d,gf;
  d:=Dimension(pg);
  gf:=pg!.basefield;
  if d <> NrRows(mat)-1 then
   Error("The arguments <mat> and <pg> are incompatible");
  fi;
  return ProjElWithFrob( mat, IdentityMapping(gf), gf);
 end );

# Added jdb 26/05/2016
# not documented yet
#############################################################################
#O  CollineationOfProjectiveSpace( <pg>, <mat> )
# method to construct an collineation of a projective space with identitymatrix,
# but with user defined field automorphism.
## 
InstallMethod( CollineationOfProjectiveSpace, [ IsProjectiveSpace, IsMapping],
   function( pg, frob )
  local d,gf,mat;
  d:=Dimension(pg);
  gf:=Range(frob);
        if not gf = pg!.basefield then
            Error("basefield of <pg> does not match with range of <frob>");
        fi;
        mat := IdentityMat(d+1,gf);
  return ProjElWithFrob( mat, frob, gf);
 end );


# Added ml 8/11/2012
#############################################################################
#O  CollineationOfProjectiveSpace( <pg>, <mat>, <frob>)
# method to construct an collineation of a projective space.
## 
InstallMethod( CollineationOfProjectiveSpace, [ IsProjectiveSpace, IsMatrix, IsMapping],
#
   function( pg, mat, frob )
  local d,gf;
  d:=Dimension(pg);
  gf:=pg!.basefield;
  if d <> NrRows(mat)-1 then
   Error("The arguments <mat> and <pg> are incompatible");
  fi;
  return ProjElWithFrob( mat, frob, gf);
 end );


# Added ml 8/11/2012
#############################################################################
#O  Collineation( <pg>, <mat> )
# shorter version of the previous method to construct an collineation of a projective space.
## 
InstallMethod( Collineation, [ IsProjectiveSpace, IsMatrix],
#
   function( pg, mat )
  return CollineationOfProjectiveSpace(pg,mat);
 end );


# Added ml 8/11/2012
#############################################################################
#O  Collineation( <pg>, <mat>, <frob> )
# shorter version of the previous method to construct an collineation of a projective space.
## 
InstallMethod( Collineation, [ IsProjectiveSpace, IsMatrix, IsMapping],
#
   function( pg, mat, frob )
  return CollineationOfProjectiveSpace(pg,mat,frob);
 end );


# CHECKED 5/09/11 jdb # changed ml 8/11/12
# 5/09/11 jdb: added a check to see if frob has <gf> as source
#############################################################################
#O  CollineationOfProjectiveSpace( <mat>, <frob>, <gf> )
# method to construct an object in the category IsProjGrpElWithFrob, i.e. a 
# collineation of a projective space, aka a projective collineation map. 
# This method is intended for the user, and contains
# a check whether the matrix is non-singular. The method relies on ProjElWithFrob,
# which will produce an error if the entries of <mat> do not all belong to <gf>
## 
InstallMethod( CollineationOfProjectiveSpace,  
 [ IsMatrix and IsFFECollColl, IsRingHomomorphism and
    IsMultiplicativeElementWithInverse, IsField], 
 function( mat, frob, gf )
    if Rank(mat) <> NrRows(mat) then
  Error("<mat> must not be singular");
    fi;
    if Source(frob) <> gf then
  Error("<frob> must be defined as an automorphis of <gf>");
 fi;
 return ProjElWithFrob( mat, frob, gf);
 end );


# CHECKED 5/09/11 jdb # changed ml 8/11/12
# 5/09/11 jdb: added a check to see if frob has <gf> as source
#############################################################################
#O  ProjectiveSemilinearMap( <mat>, <frob>, <gf> )
# method to construct an object in the category IsProjGrpElWithFrob, i.e. a 
# collineation of a projective space, aka a projective collineation map. 
# This method is intended for the user, and contains
# a check whether the matrix is non-singular. The method relies on ProjElWithFrob,
# which will produce an error if the entries of <mat> do not all belong to <gf>
## 
InstallMethod( ProjectiveSemilinearMap,  
 [ IsMatrix and IsFFECollColl, IsRingHomomorphism and
    IsMultiplicativeElementWithInverse, IsField], 
 function( mat, frob, gf )
  return CollineationOfProjectiveSpace(mat,frob,gf);
 end );


# CHECKED 5/09/11 jdb
#############################################################################
#O  ProjectivityByImageOfStandardFrameNC( <pg>, <image> )
# method to construct a projectivity if the image of a standard frame is given.
# THERE IS NO CHECK TO SEE IF THE GIVEN IMAGE CONSISTS OF N+2 POINTS NO N+1 L.D.
# for this reason, this function is not documented (yet).
# despite its name (projectivity), this function returns a projective semlinear map.
## 
InstallMethod( ProjectivityByImageOfStandardFrameNC, [ IsProjectiveSpace, IsList ],
 function(pg,image)
 # If the dimension of the projective space is n, then
 # given a frame, there is a 
 # unique projectivity mapping the standard frame to this set of points
 # THERE IS NO CHECK TO SEE IF THE GIVEN IMAGE CONSISTS OF N+2 POINTS NO N+1 L.D.
 local d,i,x,vlist,mat,coeffs,mat2;
 if not Length(image)=Dimension(pg)+2 then 
 Error("The argument does not have the required length to be the image of a frame");
 fi;
 d:=Dimension(pg);
 vlist:=List(image,x->x!.obj);
 mat:=List([1..d+1],i->vlist[i]);
 coeffs:=vlist[d+2]*(mat^-1);
 mat2:=List([1..d+1],i->coeffs[i]*mat[i]);
 return CollineationOfProjectiveSpace(mat2,pg!.basefield);
end );

###################################################################
# Some operations for elements (without and with frobenius automorphism
###################################################################

# CHECKED 5/09/11 jdb
#############################################################################
#O  MatrixOfCollineation( <c> )
# returns the underlying matrix of <c> 
##
InstallMethod( MatrixOfCollineation, [ IsProjGrpEl and IsProjGrpElRep],
 c -> c!.mat );

# CHECKED 5/09/11 jdb
#############################################################################
#O  MatrixOfCollineation( <c> )
# returns the underlying matrix of <c> 
##  
InstallMethod( MatrixOfCollineation, [ IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
 c -> c!.mat );
  
# CHECKED 5/09/11 jdb
#############################################################################
#O  FieldAutomorphism( <c> )
# returns the underlying field automorphism of <c> 
##  
InstallMethod( FieldAutomorphism, [ IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
 c -> c!.frob );

# CHECKED 5/09/11 jdb
#############################################################################
#O  Representative( <el> )
# returns the underlying matrix of the projectivity <el> 
##  
InstallOtherMethod( Representative, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  return el!.mat;
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  BaseField( <el> )
# returns the underlying field of <el> 
##  
InstallMethod( BaseField, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  return el!.fld;
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  Representative( <el> )
# returns the underlying matrix and frobenius automorphism of the projective 
# semilinear element <el> 
## 
InstallOtherMethod( Representative, 
 "for a projective group element with Frobenius",
 [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
 function( el )
  return [el!.mat,el!.frob];
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  BaseField( <el> )
# returns the underlying field of <el> 
##  
InstallMethod( BaseField, 
 "for a projective group element with Frobenius",
 [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
 function( el )
  return el!.fld;
 end );

# CHECKED 5/09/11 jdb
###################################################################
# View, print and display methods for elements (without and with Frobenius)
###################################################################

InstallMethod( ViewObj, "for a projective group element",
  [IsProjGrpEl and IsProjGrpElRep],
  function(el)
    Print("<projective element ");
    ViewObj(el!.mat);
    Print(">");
  end);

InstallMethod( Display, "for a projective group element",
  [IsProjGrpEl and IsProjGrpElRep],
  function(el)
    Print("<projective element, underlying matrix:\n");
    Display(el!.mat);
    Print(">\n");
  end );

InstallMethod( PrintObj, "for a projective group element",
  [IsProjGrpEl and IsProjGrpElRep],
  function(el)
    Print("ProjEl(");
    PrintObj(el!.mat);
    Print(")");
  end );
  
InstallMethod( ViewObj, "for a projective group element with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function(el)
    Print("< a collineation: ");
    ViewObj(el!.mat);
    if IsOne(el!.frob) then
        Print(", F^0>");
    else
        Print(", F^",el!.frob!.power,">");
    fi;
  end);

InstallMethod( Display, "for a projective group element with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function(el)
    Print("<a collineation , underlying matrix:\n");
    Display(el!.mat);
    if IsOne(el!.frob) then
        Print(", F^0>\n");
    else
        Print(", F^",el!.frob!.power,">\n");
    fi;
  end );

InstallMethod( PrintObj, "for a projective group element with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function(el)
    Print("ProjElWithFrob(");
    PrintObj(el!.mat);
    Print(",");
    PrintObj(el!.frob);
    Print(")");
  end );

# CHECKED 5/09/11 jdb
###################################################################
# comparing elements (without and with Frobenius automorphism)
###################################################################

InstallMethod( \=, "for two projective group elements",
  [IsProjGrpEl and IsProjGrpElRep, IsProjGrpEl and IsProjGrpElRep],
  function( a, b )
    local aa,bb,p,s,i;
    if a!.fld <> b!.fld then Error("different base fields"); fi;
    aa := a!.mat;
    bb := b!.mat;
    p := PositionNonZero(aa[1]);
    s := bb[1,p] / aa[1,p];
    for i in [1..Length(aa)] do
        if s*aa[i] <> bb[i] then return false; fi;
    od;
    return true;
  end );

InstallMethod(\<,
  [IsProjGrpEl, IsProjGrpEl],
  function(a,b)
    local aa,bb,pa,pb,sa,sb,i,va,vb;
    if a!.fld <> b!.fld then Error("different base fields"); fi;
    aa := a!.mat;
    bb := b!.mat;
    pa := PositionNonZero(aa[1]);
    pb := PositionNonZero(bb[1]);
    if pa > pb then 
        return true;
    elif pa < pb then
        return false;
    fi;
    sa := aa[1,pa]^-1;
    sb := bb[1,pb]^-1;
    for i in [1..Length(aa)] do
        va := sa*aa[i];
        vb := sb*bb[i];
        if va < vb then return true; fi;
        if vb < va then return false; fi;
    od;
    return false;
  end);

InstallMethod( \=, "for two projective group elements with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep,
   IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function( a, b )
    local aa,bb,p,s,i;
    if a!.fld <> b!.fld then Error("different base fields"); fi;
    if a!.frob <> b!.frob then return false; fi;
    aa := a!.mat;
    bb := b!.mat;
    p := PositionNonZero(aa[1]);
    s := bb[1,p] / aa[1,p];
    if s*aa <> bb then return false; fi;
 #for i in [1..Length(aa)] do
        #if s*aa[i] <> bb[i] then return false; fi;
    #od;
    return true;
  end );

InstallMethod(\<,
  [IsProjGrpElWithFrob, IsProjGrpElWithFrob],
  function(a,b)
    local aa,bb,pa,pb,sa,sb,i,va,vb;
    if a!.fld <> b!.fld then Error("different base fields"); fi;
    if a!.frob < b!.frob then
        return true;
    elif b!.frob < a!.frob then
        return false;
    fi;
    aa := a!.mat;
    bb := b!.mat;
    pa := PositionNonZero(aa[1]);
    pb := PositionNonZero(bb[1]);
    if pa > pb then 
        return true;
    elif pa < pb then
        return false;
    fi;
    sa := aa[1,pa]^-1;
    sb := bb[1,pb]^-1;
    for i in [1..Length(aa)] do
        va := sa*aa[i];
        vb := sb*bb[i];
        if va < vb then return true; fi;
        if vb < va then return false; fi;
    od;
    return false; 
  end);

###################################################################
# More operations for elements (without and with frobenius automorphism)
###################################################################

# CHECKED 5/09/11 jdb
#############################################################################
#O  Order( <a> )
# returns the order of <a>. This function relies on ProjectiveOrder.
##  
InstallMethod( Order, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( a )
  return ProjectiveOrder(a!.mat)[1];
 end );

# CHECKED 5/09/11 jdb
# 22/04/12 jb: There was a bug here. I added "and i mod ofrob = 0;"
# 3/6/2015: bug fixed by jb.
#############################################################################
#O  Order( <a> )
# returns the order of <a>.
## 
InstallMethod( Order, 
 "for a projective group element with Frobenius",
 [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],

# This algorithm could be improved by using the ideas of
# Celler and Leedham-Green.

 function( a )
   local b, frob, bfrob, i, ofrob;
 b := a!.mat;
 frob := a!.frob;
 if IsOne(frob) then 
  return ProjectiveOrder(b)[1];
 fi;
 if not IsOne(b) then
  bfrob := b; i := 1;
  ofrob := Order(frob);
  repeat
   bfrob := bfrob^(frob^-1);  ## JB 3/6/2015: Found bug here
   b := b * bfrob;
   i := i + 1;
  until IsFiningScalarMatrix( b ) and i mod ofrob = 0;
  return i;
 else
  return Order(frob);
 fi;
 return 1;
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  IsOne( <a> )
# returns true if <a> is the identity.
## 
InstallMethod( IsOne, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
    local s;
    s := el!.mat[1,1];
    if IsZero(s) then 
  return false; 
 fi;
    s := s^-1;
    return IsOne( s*el!.mat );
 end );

# CHECKED 5/09/11 jdb
#############################################################################
#O  IsOne( <a> )
# returns true if <a> is the identity
## 
InstallMethod( IsOne, 
 "for a projective group element with Frobenius",
 [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
 function( el )
    local s;
    if not(IsOne(el!.frob)) then 
  return false; 
 fi;
    s := el!.mat[1,1];
    if IsZero(s) then return false; fi;
    s := s^-1;
    return IsOne( s*el!.mat );
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  DegreeFFE( <el> )
# for projectivities. returns the degree of the underlying field over its 
# prime field.
## 
InstallOtherMethod( DegreeFFE, 
 "for projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  return DegreeOverPrimeField( el!.fld );
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  DegreeFFE( <el> )
# for projective collineation maps. returns the degree of the underlying 
# field over its prime field.
## 
InstallOtherMethod( DegreeFFE, 
 "for projective group element with Frobenius",
 [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
 function( el )
  return DegreeOverPrimeField( el!.fld );
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  Characteristic( <el> )
# for projectivities. returns the characteristic of the underlying field.
## 
InstallMethod( Characteristic, 
 "for projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  return Characteristic( el!.fld );
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  Characteristic( <el> )
# for projective collineation maps. returns the characteristic of the underlying field.
## 
InstallMethod( Characteristic, 
 "for projective group element with Frobenius",
 [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
 function( el )
  return Characteristic( el!.fld );
 end );

###################################################################
# The things that make it a group :-) (without Frobenius)
###################################################################

# CHECKED 5/09/11 jdb
#############################################################################
#O  \*( <a>, <b> )
# returns a*b, for IsProjGrpEl
## 
InstallMethod( \*, 
 "for two projective group elements",
 [IsProjGrpEl and IsProjGrpElRep, IsProjGrpEl and IsProjGrpElRep],
 function( a, b )
  local el;
  el := rec( mat := a!.mat * b!.mat, fld := a!.fld );
  Objectify( ProjElsType, el );
  return el;
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  InverseSameMutability( <el> )
# returns el^-1, for IsProjGrpEl, keeps mutability.
## 
InstallMethod( InverseSameMutability, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  local m;
  m := rec( mat := InverseSameMutability(el!.mat), fld := el!.fld );
  Objectify( ProjElsType, m );
  return m;
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  InverseMutable( <el> )
# returns el^-1 (mutable) for IsProjGrpEl
## 
InstallMethod( InverseMutable, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  local m;
  m := rec( mat := InverseMutable(el!.mat), fld := el!.fld );
  Objectify( ProjElsType, m );
  return m;
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  OneImmutable( <el> )
# returns immutable one of the group of <el>
## 
InstallMethod( OneImmutable, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  local o;
  o := rec( mat := OneImmutable( el!.mat ), fld := el!.fld );
  Objectify( NewType(FamilyObj(el), IsProjGrpElRep), o );
  return o;
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  OneSameMutability( <el> )
# returns one of the group of <el> with same mutability of <el>.
## 
InstallMethod( OneSameMutability, 
 "for a projective group element",
 [IsProjGrpEl and IsProjGrpElRep],
 function( el )
  local o;
  o := rec( mat := OneImmutable( el!.mat ), fld := el!.fld );
  Objectify( NewType(FamilyObj(el), IsProjGrpElRep), o );
  return o;
 end );

###################################################################
# The things that make it a group :-) (with Frobenius)
###################################################################
# we first need: 
#################################################
# Frobenius automorphisms and groups using them:
#################################################
#12 CHECKED 6/09/11 jdb

InstallOtherMethod( \^, "for a FFE vector and a Frobenius automorphism",
  [ IsVector and IsFFECollection and IsMutable, IsFrobeniusAutomorphism ],
  function( v, f )
    return List(v,x->x^f);
  end );

#cvec version
InstallOtherMethod( \^, "for a cvec/FFE vector and a Frobenius automorphism",
  [ IsCVecRep and IsFFECollection and IsMutable, IsFrobeniusAutomorphism ],
  function( v, f )
    return CVec(List(v,x->x^f),BaseField(v));
  end );

InstallOtherMethod( \^, "for a FFE vector and a Frobenius automorphism",
  [ IsVector and IsFFECollection, IsFrobeniusAutomorphism ],
  function( v, f )
    return MakeImmutable(List(v,x->x^f));
  end );

#cvec version
InstallOtherMethod( \^, "for a cvec/FFE vector and a Frobenius automorphism",
  [ IsCVecRep and IsFFECollection, IsFrobeniusAutomorphism ],
  function( v, f )
    return MakeImmutable(CVec(List(v,x->x^f),BaseField(v)));
  end );

#we think that this method is not needed, worse, should not be used.
#InstallOtherMethod( \^, 
#  "for a mutable FFE vector and a trivial Frobenius automorphism",
#  [ IsVector and IsFFECollection and IsMutable, IsMapping and IsOne ],
#  function( v, f )
#    return v;
#  end );

#cvec version
#InstallOtherMethod( \^, 
#  "for a mutable cvec/FFE vector and a trivial Frobenius automorphism",
#  [ IsCVecRep and IsFFECollection and IsMutable, IsMapping and IsOne ],
#  function( v, f )
#    return v;
#  end );
  
InstallOtherMethod( \^, 
  "for a mutable FFE vector and a trivial Frobenius automorphism",
  [ IsVector and IsFFECollection and IsMutable, IsMapping and IsOne ],
  function( v, f )
    return ShallowCopy(v);
  end );
  
#cvec version
InstallOtherMethod( \^, 
  "for a mutable cvec/FFE vector and a trivial Frobenius automorphism",
  [ IsCVecRep and IsFFECollection and IsMutable, IsMapping and IsOne ],
  function( v, f )
    return ShallowCopy(v);
  end );

#the next operations until the matrix section, the methods will become obsolete as soon as fining is cvec'ed.
  
InstallOtherMethod( \^, 
  "for a compressed GF2 vector and a Frobenius automorphism",
  [ IsVector and IsFFECollection and IsGF2VectorRep, IsFrobeniusAutomorphism ],
  function( v, f )
    local w;
    w := List(v,x->x^f);
    ConvertToVectorRepNC(w,2);
    return MakeImmutable(w);
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed GF2 vector and a Frobenius automorphism",
  [ IsVector and IsFFECollection and IsGF2VectorRep and IsMutable, 
    IsFrobeniusAutomorphism ],
  function( v, f )
    local w;
    w := List(v,x->x^f);
    ConvertToVectorRepNC(w,2);
    return w;
  end );

InstallOtherMethod( \^, 
  "for a compressed GF2 vector and a trivial Frobenius automorphism",
  [ IsVector and IsFFECollection and IsGF2VectorRep, IsMapping and IsOne ],
  function( v, f )
    return v;
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed GF2 vector and a trivial Frobenius automorphism",
  [ IsVector and IsFFECollection and IsGF2VectorRep and IsMutable, 
    IsMapping and IsOne ],
  function( v, f )
    return ShallowCopy(v);
  end );

InstallOtherMethod( \^, 
  "for a compressed 8bit vector and a Frobenius automorphism",
  [ IsVector and IsFFECollection and Is8BitVectorRep, IsFrobeniusAutomorphism ],
  function( v, f )
    local w;
    w := List(v,x->x^f);
    ConvertToVectorRepNC(w,Q_VEC8BIT(v));
    return MakeImmutable(w);
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed 8bit vector and a Frobenius automorphism",
  [ IsVector and IsFFECollection and Is8BitVectorRep and IsMutable, 
    IsFrobeniusAutomorphism ],
  function( v, f )
    local w;
    w := List(v,x->x^f);
    ConvertToVectorRepNC(w,Q_VEC8BIT(v));
    return w;
  end );

InstallOtherMethod( \^, 
  "for a compressed 8bit vector and a trivial Frobenius automorphism",
  [ IsVector and IsFFECollection and Is8BitVectorRep, IsMapping and IsOne ],
  function( v, f )
    return v;
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed 8bit vector and a trivial Frobenius automorphism",
  [ IsVector and IsFFECollection and Is8BitVectorRep and IsMutable, 
    IsMapping and IsOne ],
  function( v, f )
    return ShallowCopy(v);
  end );

#### matrix methods

InstallOtherMethod( \^, "for a FFE matrix and a Frobenius automorphism",
  [ IsMatrix and IsFFECollColl, IsFrobeniusAutomorphism ],
  function( m, f )
    return MakeImmutable(List(m,v->List(v,x->x^f)));
  end );

#cmat
InstallOtherMethod( \^, "for a FFE matrix and a Frobenius automorphism",
  [ IsCMatRep and IsFFECollColl, IsFrobeniusAutomorphism ],
  function( m, f )
    return MakeImmutable(CMat(List(m,v->v^f)));
  end );  
  
#InstallOtherMethod( \^, "for a FFE matrix and a Frobenius automorphism",
#  [ IsMatrix and IsFFECollColl, IsFrobeniusAutomorphism ],
#  function( m, f )
#    return MakeImmutable(List(m,v->List(v,x->x^f)));
#  end );
  
InstallOtherMethod( \^, "for a mutable FFE matrix and a Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and IsMutable, IsFrobeniusAutomorphism ],
  function( m, f )
    return List(m,v->List(v,x->x^f));
  end );

#cmat
InstallOtherMethod( \^, "for a mutable FFE matrix and a Frobenius automorphism",
  [ IsCMatRep and IsFFECollColl and IsMutable, IsFrobeniusAutomorphism ],
  function( m, f )
    return CMat(List(m,v->v^f));
  end );

InstallOtherMethod( \^, "for a FFE matrix and a trivial Frobenius automorphism",
  [ IsMatrix and IsFFECollColl, IsMapping and IsOne ],
  function( m, f )
    return m;
  end );

#cmat
InstallOtherMethod( \^, "for a FFE matrix and a trivial Frobenius automorphism",
  [ IsCMatRep and IsFFECollColl and IsMutable, IsMapping and IsOne ],
  function( m, f )
    return ShallowCopy(m);
  end );

InstallOtherMethod( \^, 
  "for a mutable FFE matrix and a trivial Frobenius automorphism",
  [ IsMatrix and IsFFECollColl, IsMapping and IsOne ],
  function( m, f )
    return MutableCopyMat(m);
  end );

#cmat  
InstallOtherMethod( \^, "for a FFE matrix and a trivial Frobenius automorphism",
  [ IsCMatRep and IsFFECollColl , IsMapping and IsOne ],
  function( m, f )
    return MakeImmutable(ShallowCopy(m));
  end );

#the next matrix methods will become obsolete.

InstallOtherMethod( \^, 
  "for a compressed GF2 matrix and a Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and IsGF2MatrixRep, IsFrobeniusAutomorphism ],
  function( m, f )
    local w,l,i;
    l := [];
    for i in [1..NrRows(m)] do
        w := List(m[i],x->x^f);
        ConvertToVectorRepNC(w,2);
        Add(l,w);
    od;
    ConvertToMatrixRepNC(l,2);
    return MakeImmutable(l);
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed GF2 matrix and a Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and IsGF2MatrixRep and IsMutable, 
    IsFrobeniusAutomorphism ],
  function( m, f )
    local w,l,i;
    l := [];
    for i in [1..NrRows(m)] do
        w := List(m[i],x->x^f);
        ConvertToVectorRepNC(w,2);
        Add(l,w);
    od;
    ConvertToMatrixRepNC(l,2);
    return l;
  end );

InstallOtherMethod( \^, 
  "for a compressed GF2 matrix and a trivial Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and IsGF2MatrixRep, IsMapping and IsOne ],
  function( m, f )
    return m;
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed GF2 matrix and a trivial Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and IsGF2MatrixRep and IsMutable, 
    IsMapping and IsOne ],
  function( m, f )
    return MutableCopyMat(m);
  end );

InstallOtherMethod( \^, 
  "for a compressed 8bit matrix and a Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and Is8BitMatrixRep, IsFrobeniusAutomorphism ],
  function( m, f )
    local w,l,i,q;
    l := [];
    q := Q_VEC8BIT(m[1]);
    for i in [1..NrRows(m)] do
        w := List(m[i],x->x^f);
        ConvertToVectorRepNC(w,q);
        Add(l,w);
    od;
    ConvertToMatrixRepNC(l,q);
    return MakeImmutable(l);
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed 8bit matrix and a Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and Is8BitMatrixRep and IsMutable, 
    IsFrobeniusAutomorphism ],
  function( m, f )
    local w,l,i,q;
    l := [];
    q := Q_VEC8BIT(m[1]);
    for i in [1..NrRows(m)] do
        w := List(m[i],x->x^f);
        ConvertToVectorRepNC(w,q);
        Add(l,w);
    od;
    ConvertToMatrixRepNC(l,q);
    return MakeImmutable(l);
  end );

InstallOtherMethod( \^, 
  "for a compressed 8bit matrix and a trivial Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and Is8BitMatrixRep, IsMapping and IsOne ],
  function( m, f )
    return m;
  end );

InstallOtherMethod( \^, 
  "for a mutable compressed 8bit matrix and a trivial Frobenius automorphism",
  [ IsMatrix and IsFFECollColl and Is8BitMatrixRep and IsMutable, 
    IsMapping and IsOne ],
  function( m, f )
    return MutableCopyMat(m);
  end );


# CHECKED 6/09/11 jdb
#############################################################################
#O  \*( <a>, <b> )
# returns a*b, for IsProjGrpElWithFrob
## 
#made a change, added ^-1 on march 8 2007, J&J
InstallMethod( \*, "for two projective group element with Frobenious",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep,
   IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function( a, b )
    local el;
    el := rec( mat := a!.mat * (b!.mat^(a!.frob^-1)), fld := a!.fld, 
               frob := a!.frob * b!.frob );
    Objectify( ProjElsWithFrobType, el);
    return el;
  end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  InverseSameMutability( <el> )
# returns el^-1, for IsProjGrpElWithFrob, keeps mutability.
## 
#found a bug 23/09/08 in st. andrews.
#J&J feel a great relief.
#C&P too.
#all after Max concluded that there was a big bug.
InstallMethod( InverseSameMutability, 
  "for a projective group element with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function( el )
    local m,f;
    f := el!.frob;
    m := rec( mat := (InverseSameMutability(el!.mat))^f, fld := el!.fld,
              frob := f^-1 );
    Objectify( ProjElsWithFrobType, m );
    return m;
  end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  InverseMutable( <el> )
# returns mutable el^-1, for IsProjGrpElWithFrob
## 
InstallMethod( InverseMutable, 
  "for a projective group element with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function( el )
    local m,f;
    f := el!.frob;
    m := rec( mat := (InverseMutable(el!.mat))^f, fld := el!.fld,
              frob := f^-1 );
    Objectify( ProjElsWithFrobType, m );
    return m;
  end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  OneImmutable( <el> )
# returns immutable one of the group of <el>
## 
InstallMethod( OneImmutable, "for a projective group element with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function( el )
    local o;
    o := rec( mat := OneImmutable( el!.mat ), fld := el!.fld,
              frob := el!.frob^0 );
    Objectify( ProjElsWithFrobType, o);
    return o;
  end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  OneSameMutability( <el> )
# returns one of the group of <el> with same mutability
## 
InstallMethod( OneSameMutability, 
  "for a projective group element with Frobenius",
  [IsProjGrpElWithFrob and IsProjGrpElWithFrobRep],
  function( el )
    local o;
    o := rec( mat := OneImmutable( el!.mat ), fld := el!.fld,
              frob := el!.frob^0 );
    Objectify( ProjElsWithFrobType, o);
    return o;
  end );

###################################################################
# General methods to deal with projective groups.
# Construction of (projective) groups is done in the appropriate files
# that deal with geometries.
###################################################################

# 10 CHECKED 6/09/11 jdb
###################################################################
# View, print and display methods for projective groups 
# (without and with Frobenius)
###################################################################


#InstallMethod( ViewObj, 
# "for a projective group",
# [IsProjectivityGroup],
# function( g )
#  Print("<projective group>");
# end );
#
#InstallMethod( ViewObj, 
# "for a trivial projective group",
# [IsProjectivityGroup and IsTrivial],
# function( g )
#  Print("<trivial projective group>");
# end );
#
#InstallMethod( ViewObj, 
# "for a projective group with gens",
# [IsProjectivityGroup and HasGeneratorsOfGroup],
# function( g )
#  local gens;
#  gens := GeneratorsOfGroup(g);
#  if Length(gens) = 0 then
#   Print("<trivial projective group>");
#  else
#   Print("<projective group with ",Length(gens),
 #             " generators>");
#  fi;
# end );
#
#InstallMethod( ViewObj, 
# "for a projective group with size",
# [IsProjectivityGroup and HasSize],
# function( g )
#  if Size(g) = 1 then
#   Print("<trivial projective group>");
#  else
#   Print("<projective group of size ",Size(g),">");
#  fi;
# end );
#
#InstallMethod( ViewObj, 
# "for a projective group with gens and size",
# [IsProjectivityGroup and HasGeneratorsOfGroup and HasSize],
# function( g )
#  local gens;
#  gens := GeneratorsOfGroup(g);
#  if Length(gens) = 0 then
#   Print("<trivial projective group>");
#  else
#   Print("<projective group of size ",Size(g)," with ",
 #             Length(gens)," generators>");
#  fi;
# end );
 
InstallMethod( ViewObj, 
 "for a projective collineation group",
 [IsProjectiveGroupWithFrob],
 function( g )
  Print("<projective collineation group>");
 end );

InstallMethod( ViewObj, 
 "for a trivial projective collineation group",
 [IsProjectiveGroupWithFrob and IsTrivial],
 function( g )
  Print("<trivial projective collineation group>");
 end );

InstallMethod( ViewObj, 
 "for a projective collineation group with gens",
 [IsProjectiveGroupWithFrob and HasGeneratorsOfGroup],
 function( g )
  local gens;
  gens := GeneratorsOfGroup(g);
  if Length(gens) = 0 then
   Print("<trivial projective collineation group>");
  else
   Print("<projective collineation group with ",Length(gens),
              " generators>");
  fi;
 end );

InstallMethod( ViewObj, 
 "for a projective collineation group with size",
 [IsProjectiveGroupWithFrob and HasSize],
 function( g )
  if Size(g) = 1 then
   Print("<trivial projective collineation group>");
  else
   Print("<projective collineation group of size ",Size(g),">");
  fi;
 end );

InstallMethod( ViewObj, 
 "for a projective collineation group with gens and size",
 [IsProjectiveGroupWithFrob and HasGeneratorsOfGroup and HasSize],
 function( g )
  local gens;
  gens := GeneratorsOfGroup(g);
  if Length(gens) = 0 then
   Print("<trivial projective collineation group>");
  else
   Print("<projective collineation group of size ",Size(g)," with ",
              Length(gens)," generators>");
  fi;
 end );


###################################################################
# Some operations for projective groups (without and with frobenius automorphism)
###################################################################

# CHECKED 6/09/11 jdb
#############################################################################
#O  BaseField( <g> )
# returns the base field of the projective group <g>
## 


# ml 07/11/2012: I have taken out the view, print and display methods
# for projectivity groups, since these are also collineation groups in FinInG
#InstallMethod( BaseField, 
# "for a projective group",
# [IsProjectivityGroup],
# function( g )
#  local f,gens;
#  if IsBound(g!.basefield) then
#   return g!.basefield;
#  fi;
#  if HasParent(g) then
#   f := BaseField(Parent(g));
#   g!.basefield := f;
#   return f;
#  fi;
 #   # Now start to investigate:
#  gens := GeneratorsOfGroup(g);
#  if Length(gens) > 0 then
#   g!.basefield := gens[1]!.fld;
#   return g!.basefield;
#  fi;
 #   # Now we have to give up:
#  Error("base field could not be determined");
# end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  BaseField( <g> )
# returns the base field of the projective collineation group <g>
## 
InstallMethod( BaseField, 
 "for a projective collineation group",
 [IsProjectiveGroupWithFrob],
 function( g )
  local f,gens,P;
  if IsBound(g!.basefield) then
   return g!.basefield;
  fi;
  # This if statement can cause an infinite loop!
  if HasParent(g) then  # JB 22/03/2014
   P := Parent(g);
   if IsBound(P!.basefield) then
    f := P!.basefield;
    g!.basefield := f;
    return f;
   fi;
  fi;
    # Now start to investigate:
  gens := GeneratorsOfGroup(g);
  if Length(gens) > 0 then
   g!.basefield := gens[1]!.fld;
   return g!.basefield;
  elif IsTrivial(g) then    #JB: 22/03/2014: The trivial group with no generators slipped through.
   g!.basefield := One(g)!.fld;
   return g!.basefield;
  fi;
    
    # Now we have to give up:
  Error("base field could not be determined");
 end );
 
# TO DO (22/03/2014): We ought to set the basefield on creating collineation groups.

# CHECKED 6/09/11 jdb
#############################################################################
#O  Dimension( <g> )
# returns the dimension of the projective group <g>. The dimension of this 
# group is defined as the vector space dimension of the projective space  
# of which <g> was defined as a projective group, or, in other words, as the 
# size of the matrices.
## 

# ml 07/11/2012: I have taken out the view, print and display methods
# for projectivity groups, since these are also collineation groups in FinInG

#InstallMethod( Dimension, 
# "for a projective group",
# [IsProjectivityGroup],
# function( g )
#  local gens;
#  if HasParent(g) then
#   return Dimension(Parent(g));
#  fi;
 #   # Now start to investigate:
#  gens := GeneratorsOfGroup(g);
#  if Length(gens) > 0 then
#   return NrRows(gens[1]!.mat);
#  fi;
#  Error("dimension could not be determined");
# end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  Dimension( <g> )
# returns the dimension of the projective collineation group <g>. The dimension of this 
# group is defined as the vector space dimension of the projective space  
# of which <g> was defined as a projective group, or, in other words, as the 
# size of the matrices.
## 
InstallMethod( Dimension, 
 "for a projective collineation group",
 [IsProjectiveGroupWithFrob],
 function( g )
  local gens;
  if HasParent(g) and HasDimension(Parent(g)) then #JB: 22/03/2014: Made sure the parent had a dimension first
   return Dimension(Parent(g));
  fi;
    # Now start to investigate:
  gens := GeneratorsOfGroup(g);
  if Length(gens) > 0 then
   return NrRows(gens[1]!.mat);
  elif IsTrivial(g) then    #JB: 22/03/2014: The trivial group with no generators slipped through.
    return NrRows(One(g)!.mat);
  fi;
  Error("dimension could not be determined");
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  OneImmutable( <g> )
# returns an immutable one of the projectivity group <g>
## 
# ml 07/11/2012: I have taken out the view, print and display methods
# for projectivity groups, since these are also collineation groups in FinInG

#InstallMethod( OneImmutable, 
# "for a projective group",
# # was: [IsGroup and IsProjectivityGroup], I think might be
# [IsProjectivityGroup],
# function( g )
#  local gens, o;
#  gens := GeneratorsOfGroup(g);
#  if Length(gens) = 0 then
#   if HasParent(g) then
#    gens := GeneratorsOfGroup(Parent(g));
#   else
#    Error("sorry, no generators, no one");
#   fi;
#  fi;
#  o := rec( mat := OneImmutable( gens[1]!.mat ), fld := gens[1]!.fld );
#  Objectify( NewType(FamilyObj(gens[1]), IsProjGrpElRep), o );
#  return o;
# end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  OneImmutable( <g> )
# returns immutable one of the projective collineation group <g>
## 
InstallMethod( OneImmutable, 
 "for a projective collineation group",
 # was [IsGroup and IsProjectiveGroupWithFrob], I think might be
 [IsProjectiveGroupWithFrob],
 function( g )
  local gens, o;
  gens := GeneratorsOfGroup(g);
  if Length(gens) = 0 then
   if HasParent(g) and HasOneImmutable(Parent(g)) then # JB 22/03/2014
    gens := GeneratorsOfGroup(Parent(g));
   else
    Error("sorry, no generators, no one");
   fi;
  fi;
  o := rec( mat := OneImmutable( gens[1]!.mat ), fld := BaseField(g),
    frob := gens[1]!.frob^0 );
  Objectify( ProjElsWithFrobType, o);
  return o;
 end );

###################################################################
# All about actions. But low level stuff. In each appropriate files
# for particular geometries, user-friendly action functions must be
# provided.
###################################################################

# CHECKED 6/09/11 jdb
#############################################################################
#P  CanComputeActionOnPoints( <g> )
# is set true if we consider the computation of the action feasible.
# for projective groups.
##
# ml 07/11/2012: I have taken out the view, print and display methods
# for projectivity groups, since these are also collineation groups in FinInG
 
#InstallMethod( CanComputeActionOnPoints, 
# "for a projective group",
# [IsProjectivityGroup],
# function( g )
#  local d,q;
#  d := Dimension( g );
#  q := Size( BaseField( g ) );
#  if (q^d - 1)/(q-1) > FINING.LimitForCanComputeActionOnPoints then
#   return false;
#  else
#   return true;
#  fi;
# end );
  
# CHECKED 6/09/11 jdb
#############################################################################
#P  CanComputeActionOnPoints( <g> )
# is set true if we consider the computation of the action feasible.
# for projective collineation groups.
## 
InstallMethod( CanComputeActionOnPoints, 
 "for a projective group with frob",
 [IsProjectiveGroupWithFrob],
 function( g )
  local d,q;
  d := Dimension( g );
  q := Size( BaseField( g ) );
  if (q^d - 1)/(q-1) > FINING.LimitForCanComputeActionOnPoints then
   return false;
  else
   return true;
  fi;
 end );
  
###################################################################
# Action functions for projective groups and projective collineation
# groups. The four action functions here are low level and not 
# intended for the user.
###################################################################

# CHECKED 6/09/11 jdb
#############################################################################
#F  OnProjPoints( <line>, <el> )
# computes <line>^<el> where this action is the "natural" one, and <line> represents
# a projective point. We called it line, since this functions relies on the Gap action
# function OnLines, which is the "natural" actions of a matrix on a vector line.
# Important: despite its natural name, this function is *not* intended for the user.
# <line>: just a row vector, representing a vector line
# <el>: a projective group element (so a projectivity, *not* a projective collineation element.
# normalizing the result is handled by the Gap function OnLines. This function assumes that 
# the input vector is also normalized (says the GAP manual). This became reality on september 19, 2011 :-)
## 
InstallGlobalFunction( OnProjPoints,
 function( line, el )
  return OnLines(line,el!.mat);
 end );

# CHECKED 6/09/11 jdb
# CHANGED 19/09/2011 jdb + ml
# can be shortened if you use that OnLines normalizes the result.
#############################################################################
#F  OnProjPointsWithFrob( <line>, <el> )
# computes <line>^<el> where this action is the "natural" one, and <line> represents
# a projective point. This function relies on the GAP function OnLines (see above),
# the result is hence normalized
# Important: despite its natural name, this function is *not* intended for the user.
# <line>: just a row vector, representing a projective point.
# <el>: a projective collineation element 
## 
InstallGlobalFunction( OnProjPointsWithFrob,
  function( line, el )
    local vec,c;
#    vec := OnPoints(line,el!.mat)^el!.frob;
    vec := OnLines(line,el!.mat)^el!.frob;
    #c := PositionNonZero(vec);
    #if c <= Length( vec )  then
#        if not(IsMutable(vec)) then
#   vec := ShallowCopy(vec);
#        fi;
#        MultVector(vec,Inverse( vec[c] ));
#    fi;
    return vec;
 end );

# CHECKED 6/09/11 jdb
# CHANGED 19/09/2011 jdb + ml
# CHANGED 20/09/2011 jdb + ml (SemiEchelonMat -> EchelonMat).
#############################################################################
#F  OnProjSubspacesNoFrob( <subspace>, <el> )
# computes <subspace>^<el> where this action is the "natural" one, and <subspace> represents
# a projective subspace. This function relies on the GAP action function
# OnSubspacesByCanonicalBasis. This function assumes as arguments a list (mat) of linearly 
# independent row vectors, in Hermite normal form (triangulied), and return the 
# mat*<el> in Hermite normal form. To be used in user action functions, we EchelonMat it, so that
# the output can be used directly in a Wrap.
# Important: despite its natural name, this function is *not* intended for the user.
# <el>: a projective group element (so a projectivity, *not* a projective collineation element.
## 
InstallGlobalFunction( OnProjSubspacesNoFrob,
 function( matrix, el )
  # matrix is a matrix containing the basis vectors of some subspace.
  local mat;
  mat := TriangulizeMat(OnSubspacesByCanonicalBasis(matrix,el!.mat));
  return mat;
  #return EchelonMat(OnSubspacesByCanonicalBasis(matrix,el!.mat)).vectors;
 end );

# CHECKED 6/09/11 jdb
# CHANGED 19/09/2011 jdb + ml
# CHANGED 20/09/2011 jdb + ml (SemiEchelonMat -> EchelonMat).
#############################################################################
#F  OnProjSubspacesWithFrob( <subspace>, <el> )
# computes <subspace>^<el> where this action is the "natural" one, and <subspace> represents
# a projective subspace. This function relies on the GAP action function
# OnRight, which computs the action of a matrix on a sub vector space. Here we have to rely on 
# OnRight, and so we have to EchelonMat afterwards.
# Important: despite its natural name, this function is *not* intended for the user.
# <el>: a projective group element (so a projectivity, *not* a projective collineation element.
##
InstallGlobalFunction( OnProjSubspacesWithFrob,
  function( matrix, el )
 # matrix is a matrix containing the basis vectors of some subspace.
    local vec,c;
    vec := OnRight(matrix,el!.mat)^el!.frob;
    if not(IsMutable(vec)) then
        vec := MutableCopyMat(vec);
    fi;
    TriangulizeMat(vec);
 #return EchelonMat(vec).vectors;
 return vec;
  end );

###################################################################
# Higher level user friendly operations to compute the action of a
# projective and a projective collineation group. These operations
# are based on the low level functions above.
###################################################################

# CHECKED 6/09/11 jdb
#############################################################################
#P  ActionOnAllProjPoints( <g> )
# returns the action of the projective group <g> on the projective points
# of the underlying projective space.
## 

# ml 07/11/2012: I have taken out the view, print and display methods
# for projectivity groups, since these are also collineation groups in FinInG

#InstallMethod( ActionOnAllProjPoints, 
# "for a projective group",
# [ IsProjectivityGroup ],
# function( pg )
#  local a,d,f,orb;
#  f := BaseField(pg);
#  d := Dimension(pg);
#  orb := MakeAllProjectivePoints(f,d);
#  a := ActionHomomorphism(pg,orb,OnProjPoints,"surjective");
#  SetIsInjective(a,true);
#  return a;
# end );

# CHECKED 6/09/11 jdb
# cvec change 19/3/14
#############################################################################
#O  ActionOnAllProjPoints( <g> )
# returns the action of the projective collineation group <g> on the projective points
# of the underlying projective space.
## 
InstallMethod( ActionOnAllProjPoints, 
    "for a projective collineation group",
 [ IsProjectiveGroupWithFrob ],
 function( pg )
  local a,d,f,o,on,orb,v, m, j;
  Info(InfoFinInG,4,"Using ActionOnAllProjPoints");
  f := BaseField(pg);
  d := Dimension(pg);
  o := One(f);
  on := One(pg);
  v := ZeroMutable(on!.mat[1]);
  v[1] := o;
  #orb := Orbit(pg,v,OnProjPointsWithFrob);
  #orb := Orb(pg,v,OnProjPointsWithFrob);
  orb := [];
  for m in f^d do
   j := PositionNonZero(m);
  if j <= d and m[j] = o then
   Add(orb, CVec(m,f)); #here is the change.
  fi;
  od;
  a := ActionHomomorphism(pg,orb,OnProjPointsWithFrob,"surjective");
  SetIsInjective(a,true);
  return a;
 end );

###################################################################
# NiceMonomorphism material for projective and projective collineation 
# groups. 
###################################################################

# CHECKED 6/09/11 jdb
#############################################################################
#F  NiceMonomorphismByOrbit( <g>, <x>, <op>, <orblen> )
# <g>: projective groups; <x>: an element; <op> operation suitable for <x> and <g>
# important: this functions relies on the GenSS package. 
# As you can probably guess: this is not intended for a user.
##
InstallGlobalFunction( NiceMonomorphismByOrbit,
  function(g,x,op,orblen)
    # g a funny group, Size attribute set!
    # x an element
    # op an operation suitable for x and g
    # It is guaranteed that g acts faithfully on the orbit.
    local cand,h,iso,nr,orb,pgens;
    if orblen <> false then
  orb := Orb(g,x,op,rec(orbsizelimit := orblen, hashlen := 2*orblen,
                              storenumbers := true));
        Enumerate(orb);
    else
        orb := Orb(g,x,op,rec(storenumbers := true));
        Enumerate(orb);
    fi;
 pgens := ActionOnOrbit(orb,GeneratorsOfGroup(g));
    h := GroupWithGenerators(pgens);
    SetSize(h,Size(g));
    nr := Minimum(100,Length(orb));
    cand := rec( points := orb{[1..nr]}, used := 0,
                 ops := ListWithIdenticalEntries(nr,op) );
 iso := GroupHomomorphismByImagesNCStabilizerChain(g,h,pgens,
              rec( Cand := cand ), rec( ) );
    SetIsBijective(iso,true);
    return iso;
  end );

# CHECKED 6/09/11 jdb
#############################################################################
#F  NiceMonomorphismByDomain( <g>, <dom>, <op> )
# <g>: projective groups, size attribute *set* ; <x>: an element; 
# <op> operation suitable for <x> and <g>
# important: this functions relies on the GenSS package. 
##
InstallGlobalFunction( NiceMonomorphismByDomain,
  function(g,dom,op)
    # g a funny group, Size attribute set!
    # dom an orbit of g
    # op the operation suitable for x and g
    # It is guaranteed that g acts faithfully on the orbit.
    local cand,gens,h,ht,i,iso,nr,pgens;
    ht := HTCreate(dom[1],rec(hashlen:=Length(dom)*2));
    for i in [1..Length(dom)] do
      HTAdd(ht,dom[i],i);
    od;
    pgens := [];
    gens := GeneratorsOfGroup(g);
    for i in [1..Length(gens)] do
        Add(pgens,PermList( List([1..Length(dom)],
                                 j->HTValue(ht,op(dom[j],gens[i]))) ));
    od;
    h := GroupWithGenerators(pgens);
    SetSize(h,Size(g));
    nr := Minimum(100,Length(dom));
    cand := rec( points := dom{[1..nr]}, used := 0,
                 ops := ListWithIdenticalEntries(nr,op) );
    iso := GroupHomomorphismByImagesNCStabilizerChain(g,h,pgens,
              rec( Cand := cand ), rec( ) );
    SetIsBijective(iso,true);
    return iso;  
  end );

# CHECKED 6/09/11 jdb
# cvec change 19/3/14
#############################################################################
#O  NiceMonomorphism( <pg> )
# <pg> is a projective group. This operation returns a nice monomorphism.
##
InstallMethod( NiceMonomorphism, 
 "for a projective group (feasible case)",
 [IsProjectivityGroup and CanComputeActionOnPoints and IsHandledByNiceMonomorphism], 
 50,
 function( pg )
 local hom, dom,bf;
 Info(InfoFinInG,4,"Using NiceMonomorphism for proj. group (feasible)");
 bf := BaseField(pg);
    dom := MakeAllProjectivePoints( bf, Dimension(pg) - 1);
    #dom := List(dom,x->CVec(x,bf)); # (ml 31/03/14) MakeAllProjectivePoints produces already cvecs 
 if FINING.Fast then
    hom := NiceMonomorphismByDomain( pg, dom, OnProjPointsWithFrob );
    else 
       hom := ActionHomomorphism(pg, dom, OnProjPointsWithFrob, "surjective");    
       SetIsBijective(hom, true);
    fi;
    return hom;
 end );
  
# CHECKED 6/09/11 jdb
# cvec change 19/3/14
#############################################################################
#O  NiceMonomorphism( <pg> )
# <pg> is a projective group. This operation returns a nice monomorphism.
##
InstallMethod( NiceMonomorphism, 
 "for a projective group (nasty case)",
 [IsProjectiveGroupWithFrob and IsHandledByNiceMonomorphism], 
 50,
 function( pg )
  local can, dom, hom, bf;
  Info(InfoFinInG,4,"Using NiceMonomorphism for proj. group (nasty)");
  bf := BaseField(pg);
  can := CanComputeActionOnPoints(pg);
  if not(can) then
   Error("action on projective points not feasible to calculate");
  else
   dom := MakeAllProjectivePoints( BaseField(pg), Dimension(pg) - 1 );
      #dom := List(dom,x->CVec(x,bf)); # (ml 31/03/14) MakeAllProjectivePoints produces already cvecs 
   if FINING.Fast then
    hom := NiceMonomorphismByDomain( pg, dom, OnProjPointsWithFrob );
   else 
    hom := ActionHomomorphism(pg, dom, OnProjPointsWithFrob, "surjective");    
    SetIsBijective(hom, true);
   fi;
   return hom; 
  fi;
 end );

# CHECKED 6/09/11 jdb
#############################################################################
#O  NiceMonomorphism( <pg> )
# <pg> is a projective collineation group. This operation returns a nice monomorphism.
##
InstallMethod( NiceMonomorphism, 
 "for a projective collineation group (feasible case)",
 [IsProjectiveGroupWithFrob and CanComputeActionOnPoints and
 IsHandledByNiceMonomorphism], 1,
 function( pg )
  return ActionOnAllProjPoints( pg );
 end );
  
# CHECKED 6/09/11 jdb
#############################################################################
#O  NiceMonomorphism( <pg> )
# <pg> is a projective collineation group. This operation returns a nice monomorphism.
##
InstallMethod( NiceMonomorphism, 
 "for a projective collineation group (nasty case)",
 [IsProjectiveGroupWithFrob and IsHandledByNiceMonomorphism], 50,
 function( pg )
  local can;
  can := CanComputeActionOnPoints(pg);
  if not(can) then
   Error("action on projective points not feasible to calculate");
  else
   return ActionOnAllProjPoints( pg );
  fi;
 end );

## FindBasePointCandidates: are these methods also obsolete in the sense that they are never used? No! They are used in GenSS :-)

#############################################################################
#O  FindBasePointCandidates( <g>, <opt>, <i> )
# <pg> is a projective collineation group. <op> and <i> are arguments required
# to be used in GenSS.
##
InstallMethod( FindBasePointCandidates,
  "for a projective group",
  [IsProjectivityGroup,IsRecord,IsInt],
  function(g,opt,i)
    local cand,d,f,gens;
    if IsBound(g!.basepointcandidates) and
       g!.basepointcandidates.used < Length(g!.basepointcandidates.points) then
        return g!.basepointcandidates;
    fi;
    gens := GeneratorsOfGroup(g);
    if IsObjWithMemory(gens[1]) then
        f := BaseField(gens[1]!.el);
        d := NrRows(gens[1]!.el!.mat);
    else
        f := BaseField(g);
        d := Dimension(g);
    fi;
    cand := rec( points := NewMatrix(IsCMatRep, f,d, IdentityMat(d,f)) , used := 0,
                 ops := ListWithIdenticalEntries(d,OnProjPoints) );
    return cand;
  end );

#############################################################################
#O  FindBasePointCandidates( <g>, <opt>, <i> )
# <pg> is a projective collineation group. <op> and <i> are arguments required
# to be used in GenSS.
##
InstallMethod( FindBasePointCandidates,
  "for a projective collineation group",
  [IsProjectiveGroupWithFrob,IsRecord,IsInt],
  function(g,opt,i)
    local cand,d,f,gens;
    if IsBound(g!.basepointcandidates) and
       g!.basepointcandidates.used < Length(g!.basepointcandidates.points) then
        return g!.basepointcandidates;
    fi;
    gens := GeneratorsOfGroup(g);
    if IsObjWithMemory(gens[1]) then
        f := BaseField(gens[1]!.el);
        d := NrRows(gens[1]!.el!.mat);
    else
        f := BaseField(g);
        d := Dimension(g);
    fi;
    cand := rec( points := NewMatrix(IsCMatRep, f,d, IdentityMat(d,f)), used := 0,
                 ops := ListWithIdenticalEntries(d,OnProjPointsWithFrob) );
    if d > 1 then
        Add(cand.points,ShallowCopy(cand.points[1]));
        Add(cand.ops,OnProjPointsWithFrob);
        cand.points[d+1][2] := PrimitiveRoot(f);
    fi;
    return cand;
  end );


#############################################################################
#O  FindBasePointCandidates( <g>, <opt>, <i> )
# <pg> is a projective collineation group. <opt>, <i>, <parentS> are arguments 
# required to be used in GenSS.
##
InstallMethod( FindBasePointCandidates,
  "for a projective collineation group",
  [IsProjectiveGroupWithFrob,IsRecord,IsInt,IsObject],
#
# We need a four-argument version of this method for recent versions of GenSS.
# We don't use "parentS" at all here.
#
  function(g,opt,i,parentS)
    local cand,d,f,j,gens;
    if IsBound(g!.basepointcandidates) and
       g!.basepointcandidates.used < Length(g!.basepointcandidates.points) then
        return g!.basepointcandidates;
    fi;
    gens := GeneratorsOfGroup(g);
    if IsObjWithMemory(gens[1]) then
        f := BaseField(gens[1]!.el);
        d := NrRows(gens[1]!.el!.mat);
    else
        f := BaseField(g);
        d := Dimension(g);
    fi;
    cand := rec( points := NewMatrix(IsCMatRep, f,d, IdentityMat(d,f)), used := 0,
                 ops := ListWithIdenticalEntries(d,OnProjPointsWithFrob) );
    if d > 1 then
        for j in [2..d] do
            Add(cand.points,ShallowCopy(cand.points[1]));
            Add(cand.ops,OnProjPointsWithFrob);
            cand.points[d+j-1][j] := PrimitiveRoot(f);
        od;
    fi;
    return cand;
  end );


#################################################
# Our classical groups:
#################################################


#############################################################################
# Part I: methods for canonical gram matrices and canonical quadratic forms.
# these methods are not intended for the user.
#############################################################################

# CHECKED 21/09/11 jdb
#############################################################################
#O  CanonicalGramMatrix( <type>, <d>, <f> )
## Constructs the canonical gram matrix to construct the canonical 
## forms used in FinInG. See Appendix for exact information on these forms
## and there matrices.
##
InstallMethod( CanonicalGramMatrix, 
 "for a string, an integer, and a field",
 [IsString, IsPosInt, IsField],
 function( type, d, f )
  local one, q, m, i, t, x, w, p;
  one := One( f );
  q := Size(f);

      # Symplectic Gram matrix
  if type = "symplectic" then    
   if IsOddInt(d) then
    Error( "the dimension <d> must be even" );
   fi;    
   m := List( 0 * IdentityMat(d, f), ShallowCopy );
   for i  in [ 1 .. d/2 ]  do
    m[2*i,2*i-1] := -one;
    m[2*i-1,2*i] := one;
   od;
    
      # Unitary Gram matrix      
  elif type = "hermitian" then
   if IsOddInt(DegreeOverPrimeField(f)) then
    Error("field order must be a square");
   fi;
   m := IdentityMat(d, f);
        
      # Orthogonal Gram matrix
  elif type = "hyperbolic" then
   m := List( 0*IdentityMat(d, f), ShallowCopy );
   p := Characteristic(f);
   if IsOddInt(p) and (p + 1) mod 4 = 0 then
    w := one * ((p + 1) / 2);
   else
    w := one;
   fi; 
   for i  in [ 1 .. d/2 ]  do
    m[2*i-1,2*i] := w;
    m[2*i,2*i-1] := w;
   od;
  elif type = "elliptic" then   
   m := List( 0*IdentityMat(d, f), ShallowCopy );
   p := Characteristic(f);
      ## if q is congruent to 5,7 mod 8, then #wrong comment?
      ## the anisotropic part is the primitive root.
   if q mod 4 in [1,2] then 
    t := Z(q);
   else
    t := one;
   fi;
   m{[1,2]}{[1,2]} := [ [ 1, 0 ], [ 0, t ] ] * one;

   if IsOddInt(p) then
    w := one * ((p + 1) / 2);
   else
    w := one;
   fi; 
   for i in [ 2 .. d/2 ]  do
    m[2*i-1,2*i] := w;
    m[2*i,2*i-1] := w;
   od;
  elif type = "parabolic" then 
   m := List( 0*IdentityMat(d, f), ShallowCopy );          
   p := Characteristic(f);
   if IsOddInt(p) then
         ## if q is congruent to 5,7 mod 8, then
         ## the anisotropic part is the primitive root
         ## of the prime subfield.
    if q mod 8 in [5,7] then 
     t := Z(p);
    else
     t := one;
    fi;
    m[1,1] := t;
    w := t * ((p + 1) / 2);
   else
    w := one;
   fi; 
   for i in [ 1 .. (d-1)/2 ]  do
    m[2*i,2*i+1] := w;
    m[2*i+1,2*i] := w;
   od;
  else Error( "type is unknown or not implemented" );
  fi;

    ##  We should return a compressed matrix in order that
    ##  our computations are efficient

  ConvertToMatrixRep( m, f );
  return m;
 end );

# CHECKED 21/09/11 jdb
#############################################################################
#O  CanonicalQuadraticForm( <type>, <d>, <f> )
## Constructs the canonical gram matrix to construct the canonical quadratic
## forms used in FinInG. See Appendix for exact information on these forms
## and there matrices.
####
InstallMethod( CanonicalQuadraticForm, 
 "for a string, an integer and a field",
 [IsString, IsPosInt, IsField],
 function( type, d, f )
  local m, one, q, p, j, x, R;
  one := One( f );
        if type = "hyperbolic" then
   m := MutableCopyMat(0 * IdentityMat(d, f));
   for j in [ 1 .. d/2 ]  do
    m[ 2*j-1 , 2*j ] := one;
   od;
  elif type = "elliptic" then
   m := MutableCopyMat(0 * IdentityMat(d, f));
   m[1,1] := one;
   m[2,1] := one; 
   m[d,d-1] := one;
   for j in [ 2 .. d/2-1 ]  do
    m[ 2*j-1 , 2*j ] := one;
   od;
   p := Characteristic(f);
   q := Size(f);
   if IsOddInt(Log(q, p)) then
    m[2,2] := one;
   else
    R := PolynomialRing( f, 1 );
    x := Indeterminate( f );
    m[2,2] := Z(q)^First( [ 0 .. q-2 ], u -> 
     Length( Factors( R, x^2+x+PrimitiveRoot( f )^u ) ) = 1 );         
   fi;
  elif type = "parabolic" then
   m := MutableCopyMat(0 * IdentityMat(d, f));
   m[1,1] := one;
   for j in [ 1 .. (d-1)/2 ]  do
    m[ 2*j+1 , 2*j ] := one;
   od;
  else Error( "type is unknown or not implemented" );
  fi;

    ##  We should return a compressed matrix in order that
    ##  our computations are efficient

  ConvertToMatrixRep( m, f );
  return m;
 end );


#############################################################################
# Part II: constructor methods.
#############################################################################

###################################################################################
#
#  JB 20/11/2011:  
#  I've done some rigorous testing, and the following work very well:
#    all groups of SymplecticSpace
#    all groups of HyperbolicQuadric
#    all groups of HermitianPolarSpace (hard to check though, things get big fast)
#    all groups of EllipticQuadric (I've recently fixed a bug)
#    all groups of ParabolicQuadric (I've recently fixed a bug)
#
# I guess we could run more tests for higher dimensions and field orders, but I'm
# reasonably confident that it all works well. For example, I tested groups
# of the parabolic quadric up to q^d = 8^6 (d is the projective dimension here).
#    
###################################################################################

#####################################################################
# Isometry groups. In this order: PSO, PGO, PSU, PGU, PSp, and PGSp
#####################################################################

###### Orthogonal groups ######

#############################################################################
#O  SOdesargues( <type>, <d>, <f> )
## returns the projective special orthogonal group, as a projective collineation group.
## The generators of the group are the projective collineation elements that are 
## represented by the matrices that generate SO(type,d,q). The latter is available in GAP
##
InstallMethod( SOdesargues, 
  "for an integer, a positive integer, and a finite field",
  [IsInt, IsPosInt, IsField and IsFinite],
    function(i, d, f)
    local s, m, frob, b, gens, g, q;
    if i = -1 then s := "elliptic";
    elif i = 0 then s := "parabolic";
    elif i = 1 then s := "hyperbolic";
    fi;
    q := Size(f);
    if IsEvenInt(q) then
      m := InvariantQuadraticForm(SO(i,d,q))!.matrix;
      b := BaseChangeOrthogonalQuadratic(m, f)[1];
    else 
      m := InvariantBilinearForm(SO(i,d,q))!.matrix;
      b := BaseChangeOrthogonalBilinear(m, f)[1]; 
    fi; 
    frob := FrobeniusAutomorphism(f);
 
    ## new group elements: x -> b^-1 x b (conjugation by base change)
    ## preserves form... (b x b^-1) (b m b^T) (b x b^-1)^T = x m x^T

    gens := GeneratorsOfGroup( SO(i,d,q) );
    gens := List( gens, y -> b * y * b^-1);
    gens := ProjElsWithFrob( List(gens, x -> [x,frob^0]), f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PSO(",String(i),",",String(d),",",String(q),")") );
    if i = 0 then 
       SetSize( g, Size(SO(i, d, q)) );  ##/ 2); This might be a mistake in Kleidman and Liebeck!
    else
       SetSize( g, Size(SO(i, d, q)) / GCD_INT(2, q-1) ); 
    fi;

    return g;
  end );

#############################################################################
#O  GOdesargues( <type>, <d>, <f> )
## returns the projective general orthogonal group, as a projective collineation group.
## The generators of the group are the projective collineation elements that are 
## represented by the matrices that generate GO(type,d,q). The latter is available in GAP
##
InstallMethod( GOdesargues, [IsInt, IsPosInt, IsField and IsFinite],
  function(i, d, f)
    local m, frob, b, gens, s, g, q;
    if i = -1 then s := "elliptic";
    elif i = 0 then s := "parabolic";
    elif i = 1 then s := "hyperbolic";
    fi;
    q := Size(f);
    if IsEvenInt(q) then
      m := InvariantQuadraticForm(GO(i,d,q))!.matrix;
      b := BaseChangeOrthogonalQuadratic(m, f)[1];
    else 
      m := InvariantBilinearForm(SO(i,d,q))!.matrix;   
      b := BaseChangeOrthogonalBilinear(m, f)[1]; 
    fi; 
    frob := FrobeniusAutomorphism(f);

    ## new group elements: x -> b x b^-1 (conjugation by base change)
    ## preserves form... (b x b^-1) (b m b^T) (b x b^-1)^T = x m x^T

    gens := GeneratorsOfGroup( GO(i,d,q) );
    gens := List( gens, y -> b * y * b^-1);
    gens := ProjElsWithFrob( List(gens, x -> [x,frob^0]), f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PGO(",String(i),",",String(d),",",String(q),")") );
    SetSize( g, Size(GO(i, d, q)) / GCD_INT(2,q-1) ); 
    return g;
  end );

###### Unitary groups ######

#############################################################################
#O  SUdesargues( <type>, <d>, <f> )
## returns the projective special unitary group, as a projective collineation group.
## The generators of the group are the projective collineation elements that are 
## represented by the matrices that generate SU(type,d,q). The latter is available in GAP
##
InstallMethod( SUdesargues, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local m, frob, b, gens, g, sqrtq;
    sqrtq := Sqrt(Size(f));
    m := InvariantSesquilinearForm(SU(d,sqrtq))!.matrix;        
    frob := FrobeniusAutomorphism(f);
    b := BaseChangeHermitian(m, f)[1];
    ## new group elements: x -> b x b^-1 (conjugation by base change)
    ## preserves form... (b x b^-1) (b m b^Tfrob) (b x b^-1)^Tfrob = x m x^Tfrob
    gens := GeneratorsOfGroup( SU(d,sqrtq) );
    gens := List( gens, y -> b * y * b^-1);
    gens := ProjElsWithFrob( List(gens, x -> [x,frob^0]), f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PSU(",String(d),",",String(sqrtq),"^2)") );
    SetSize( g, Size( SU(d, sqrtq) ) / GCD_INT(sqrtq+1,d)  );
    return g;
  end );

#############################################################################
#O  GUdesargues( <type>, <d>, <f> )
## returns the projective general unitary group, as a projective collineation group.
## The generators of the group are the projective collineation elements that are 
## represented by the matrices that generate GU(type,d,q). The latter is available in GAP
##
InstallMethod( GUdesargues, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local m, frob, b, gens, g, sqrtq;
    sqrtq := Sqrt(Size(f));
    m := InvariantSesquilinearForm(GU(d,sqrtq))!.matrix;      
    frob := FrobeniusAutomorphism(f);
    b := BaseChangeHermitian(m, f)[1];
    ## new group elements: x -> b x b^-1 (conjugation by base change)
    gens := GeneratorsOfGroup( GU(d,sqrtq) );
    gens := List( gens, y -> b * y * b^-1);
    gens := ProjElsWithFrob( List(gens, x -> [x,frob^0]), f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PGU(",String(d),",",String(sqrtq),"^2)") );
    SetSize( g, Size( GU(d, sqrtq) ) / (sqrtq+1) );
    return g;
  end );

###### Symplectic groups ######

#############################################################################
#O  Spdesargues( <d>, <f> )
## returns the projective special symplectic group, as a projective collineation group.
## The generators of the group are the projective collineation elements that are 
## represented by the matrices that generate Sp(d,q). The latter is available in GAP
##
InstallMethod( Spdesargues, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local m, frob, b, gens, g, q, sp;
    q := Size(f);
    m := InvariantBilinearForm(Sp(d,q))!.matrix;   
    b := BaseChangeSymplectic(m, f)[1];  ## change made after new forms code
    frob := FrobeniusAutomorphism(f);
    ## new group elements: x -> b x b^-1 (conjugation by base change)
    sp := Sp(d,q);
    gens := GeneratorsOfGroup( sp );
    gens := List( gens, y -> b * y * b^-1);
    gens := ProjElsWithFrob( List(gens, x -> [x,frob^0]), f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PSp(",String(d),",",String(q),")") );
    SetSize( g, Size( sp )/GCD_INT(2, q-1) );
    return g;
  end );

#############################################################################
#O  GeneralSymplecticGroup( <d>, <f> )
## returns the general symplectic group. See the internal comment here why
## we add this function.
##
InstallMethod( GeneralSymplecticGroup, [IsPosInt, IsField and IsFinite],
  function(d, f)

## The command "Sp" in the GAP library returns the symplectic 
## isometry group (see classical.gi). However, in odd characteristic,
## the symplectic isometries have index 2 in the symplectic similarity
## group. The preimage in the matrix group of the symplectic 
## similarities is the isometries extended by the cyclic
## group generated by the map which simply multiplies one half
## of the symplectic basis by the primitive element of the field
## and leaves the other half alone. 
  
  local sp, gens, z, delta, i, g, q;
  q := Size(f);
  if IsOddInt(d) then 
     Error("dimension must be an even");
  fi;
  sp := Sp(d, q);
  gens := GeneratorsOfGroup(sp);
  z := PrimitiveRoot( f );
  delta := IdentityMat(d, f);
  for i in [1..d/2] do delta[i,i] := z; od;
  gens := Concatenation(gens, [delta]);
  g := GroupWithGenerators( gens );
  SetName( g, Concatenation("GSp(",String(d),",",String(q),")") );
  SetSize( g, (q-1) * Size(sp) );
  return g;
  end );

#############################################################################
#O  GSpdesargues( <d>, <f> )
## returns the projective general symplectic group, as a projective collineation group.
## The generators of the group are the projective collineation elements that are 
## represented by the matrices that generate GSp(d,q). The latter is made possible now (see above method).
##
InstallMethod( GSpdesargues, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local m, frob, b, gens, g, q, gsp;
    q := Size(f);
    m := InvariantBilinearForm(Sp(d,q))!.matrix;     
    b := BaseChangeToCanonical( BilinearFormByMatrix(m, f) );
    frob := FrobeniusAutomorphism(f);
    ## new group elements: x -> b x b^-1 (conjugation by base change)
    gsp := GeneralSymplecticGroup(d,f);
    gens := GeneratorsOfGroup( gsp );
    gens := List( gens, y -> b * y * b^-1);
    gens := ProjElsWithFrob( List(gens, x -> [x,frob^0]), f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PGSp(",String(d),",",String(q),")") );
    SetSize( g, Size(gsp) / (q-1) );    
    return g;
  end );

#################################################
# Similarity and semi-similarity groups: In this order: PGammaSp, DeltaO (+,-,parabolic), 
#################################################

###### Symplectic group ######

#############################################################################
#O  GammaSp( <d>, <f> )
## returns the projective semi-linear symplectic group.
## We rely on GSp(d,q), and the frobenius automorphism.
##
InstallMethod( GammaSp, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local m, frob, b, gens, g, q, gsp;
    q := Size(f);
    m := InvariantBilinearForm(Sp(d,q))!.matrix;     
    b := BaseChangeToCanonical( BilinearFormByMatrix(m, f) );
    frob := FrobeniusAutomorphism(f);
    ## new group elements: x -> b x b^-1 (conjugation by base change)
    gsp := GeneralSymplecticGroup(d,f);
    gens := GeneratorsOfGroup( gsp );
    gens := List( gens, y -> b * y * b^-1);
    gens := List( gens, x -> [x, frob^0]);
    Add(gens, [IdentityMat(d, f), frob] );
    gens := ProjElsWithFrob( gens, f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PGammaSp(",String(d),",",String(q),")") );
    SetSize( g, Order(frob) * Size(gsp) / (q - 1) );  
    return g;
  end );

###### Orthogonal (elliptic) groups ######

#############################################################################
#O  DeltaOminus( <d>, <f> )
## returns the projective similarity group of an elliptic orthogonal form
## We rely on GOdesargues.
##
InstallMethod( DeltaOminus, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local go, gens, g, q, one, mat, i, combs, two, a, b, 
          twobytwo, mu, z, zero;  

    ## Note here that for q even, the projective similarity group
    ## is equal to the projective isometry group. For q odd,
    ## the index of the projective isometry group in the projective
    ## similarity group is 2. Moreover, we have two cases modulo 4.
    ## For q = 3 mod 4, we adjoin the matrix (e.g., for d = 6)
    ##    a  b  .  .  .  .  
    ##    b -a  .  .  .  .  
    ##    .  .  .  1  .  .  
    ##    .  . -1  .  .  .  
    ##    .  .  .  .  .  1  
    ##    .  .  .  . -1  .
    ## where a^2+b^2 = Z(q)^((q-1)/2), 
    ## to the isometry group to obtain the similarity group (see
    ## Kleidman and Liebeck, Section 2.8). For q = 1 mod 4, we
    ## use the matrix
    ##    .  1  .  .  .  .  
    ##    z  .  .  .  .  .  
    ##    .  .  .  1  .  .  
    ##    .  .  z  .  .  .  
    ##    .  .  .  .  .  1  
    ##    .  .  .  .  z  .
    ## where z = Z(q).

    one := One(f);
    mat := NullMat(d,d,f);
    q := Size(f);
    z := Z(q);
    go := GOdesargues(-1,d,f);

    if q mod 4 = 3 then
       for i in [2..d/2] do
           mat[2*i-1,2*i] := one;   
           mat[2*i,2*i-1] := -one;  
       od;  
       mu := z^((q-1)/2);;
       combs := Combinations(AsList(f),2);;
       two := First(combs, t -> not IsZero(t[1]) and not IsZero(t[2])
                           and t[1]^2+t[2]^2=mu);
       a := two[1]; b:= two[2];
       twobytwo := [[a,b],[b,-a]];
       mat{[1,2]}{[1,2]} := twobytwo;
    elif q mod 4 = 1 then
       z := Z(q);
       zero := Zero(f);
       for i in [1..d/2] do
           mat{[2*i-1,2*i]}{[2*i-1,2*i]} := [[ zero, one ], [z, zero]];
       od;
    else 
       return go; 
    fi;

    gens := ShallowCopy(GeneratorsOfGroup( go ));
    Add(gens, ProjElWithFrob( mat, IdentityMapping(f), f) );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PDeltaO-(",String(d),",",String(Size(f)),")") );
       ## scalars are completely contained in matrix group, (q-1) cancels with (q-1)
    SetSize( g, Size(GO(-1,d,q)) ); 
    return g;
  end ); 


#############################################################################
#O  GammaOminus( <d>, <f> )
## returns the projective semi-similarity group of an elliptic orthogonal form
## We rely on DeltaOminus and the Frobenius automorphism.
##
InstallMethod( GammaOminus, [IsPosInt, IsField and IsFinite],
  function(d, f)
  local q, gram, mat, p, a, go, gens, coll, frob, block, mat2, i; 
  
  ## Works beautifully for odd q! Tested for possible output 
  ## (q,d) in {(4,9),(4,25),(4,27),(4,49),(6,9)}

  ## After some calculations using the information in Section 2.8
  ## of Kleidman and Liebeck, we find that the following matrix M 
  ## (n.b., you should extrapolate the dimension) together with
  ## the Frobenius automorphism of GF(q) defines a semisimilarity
  ## of our canonical form in FinInG:
  ##    a  .  .  .  .  .  
  ##    .  b  .  .  .  .  
  ##    .  .  .  l  .  .  
  ##    .  .  l  .  .  .  
  ##    .  .  .  .  .  l  
  ##    .  .  .  .  l  .
  ## where a = l * alpha^((1-p)/2) and b = l * beta^((1-p)/2), and 
  ## the first block of our Gram matrix is diag(alpha, beta).
  ##  JB 20/11/2011: Fixed the bug for q even. Simply changed the change of basis matrix.

  q := Size(f);
  p := Characteristic( f );
  go := DeltaOminus( d, f );

  if q = p then
     coll := go;
  elif IsOddInt(q) then
     gram := CanonicalGramMatrix("elliptic", d, f);
     mat := MutableCopyMat( gram );
  mat[1,1] := gram[3,4] * gram[1,1]^((1-p)/2); 
  mat[2,2] := gram[3,4] * gram[2,2]^((1-p)/2);
  ConvertToMatrixRep( mat, f );
  frob := FrobeniusAutomorphism( f );
  a := ProjElWithFrob( mat, frob, f);
     gens := ShallowCopy( GeneratorsOfGroup(go) );
     Add(gens, a);
     coll := GroupWithGenerators( gens );
  SetName( coll, Concatenation("PGammaO-(",String(d),",",String(q),")") );
  SetSize( coll, Size(go) * Order(frob) );
  else
     ## We must find a semisimilarity for the first (2x2) block. Then
     ## simply extend it naturally to fit with the canonical form.

     gram := CanonicalQuadraticForm("elliptic", d, f);
     block :=Forms_RESET( MutableCopyMat( gram{[1,2]}{[1,2]} ), 2, q);
  frob := FrobeniusAutomorphism( f );
  mat := BaseChangeOrthogonalQuadratic(block^(frob^-1), f)[1];
 
   ## JB is a little bit unsure if this will work all the time. So a test is needed:
  if not Forms_RESET(mat * block^(frob^-1) *TransposedMat(mat), 2, q) = block then
     Error("Inappropriate matrix for change of basis");
  fi;
 
     mat2 := IdentityMat(d,f);  
     mat2{[1,2]}{[1,2]} := mat;
  a := ProjElWithFrob( mat2, frob, f);
  gens := ShallowCopy( GeneratorsOfGroup(go) );
     Add(gens, a);
     coll := GroupWithGenerators( gens );
  SetName( coll, Concatenation("PGammaO-(",String(d),",",String(q),")") );
  SetSize( coll, Size(go) * Order(frob) );
  fi;
  
  return coll;
  end );

###### Orthogonal (parabolic) groups ######

#############################################################################
#O  GammaO( <d>, <f> )
## returns the projective semi-similarity group of a parabolic orthogonal form
## We rely on GO (available in GAP).
##
InstallMethod( GammaO, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local q, p, go, gens, frob, m, b, lambda, g, w, one;
    one := One(f);
    q := Size(f);
    p := Characteristic(f);
    go := GO(0, d, q);
    gens := ShallowCopy(GeneratorsOfGroup(go));
    frob := FrobeniusAutomorphism( f );
    if IsOddInt(q) then
      m := InvariantBilinearForm(GO(0,d,q))!.matrix;
      b := BaseChangeOrthogonalBilinear(m, f)[1]; 
      gens := List(gens, t->b*t*b^-1);; 
    else 
      m := InvariantQuadraticForm(GO(0,d,q))!.matrix;
      b := BaseChangeOrthogonalQuadratic(m, f)[1];
      gens := List(gens, t->b*t*b^-1);;
    fi;
    if IsOddInt(p) then
       if q mod 8 in [5,7] then 
          w := Z(p) * ((p + 1) / 2);
       else
          w := one * ((p + 1) / 2);
       fi; 
    else
       w := one;
    fi; 
    lambda := First(AsList(f),t->t^2 = w^(p-1));
    gens := List(gens, x -> [x,frob^0]);
    Add(gens, [lambda * IdentityMat(d, f), frob] );
    gens := ProjElsWithFrob( gens, f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PGammaO(",String(d),",",String(q),")") );  
    SetSize( g, Order(frob) * Size(go) / GCD_INT(2,q-1) );    
       ## Careful to read  Kleidman and Liebeck correctly. For q even, we take the symplectic group.
    return g;
  end );


###### Orthogonal (hyperbolic) groups ######

#############################################################################
#O  DeltaOplus( <d>, <f> )
## returns the projective similarity group of an hyperbolic orthogonal form
## We rely on GO (available in GAP).
##
InstallMethod( DeltaOplus, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local q, go, m, w, mu, i, gens, g, b;  
    q := Size(f);
    go := GO(1, d, q);
    gens := ShallowCopy(GeneratorsOfGroup(go));
  
    if IsOddInt(q) then
      m := InvariantBilinearForm(go)!.matrix;
      b := BaseChangeOrthogonalBilinear(m, f)[1]; 
      w := PrimitiveRoot( f );
    
    ## put primitive root on odd places of diagonal
    ## of identity matrix

      mu := IdentityMat(d,f);
      for i in [1..d/2] do
        mu[2*i-1,2*i-1] := w;
      od;

      gens := List(gens, t->b*t*b^-1);; 
      Add(gens, mu);
    else 
      m := InvariantQuadraticForm(go)!.matrix;
      b := BaseChangeOrthogonalQuadratic(m, f)[1];
      gens := List(gens, t->b*t*b^-1);;
    fi;

    gens := ProjElsWithFrob( List(gens, x -> [x,IdentityMapping(f)]), f );
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PDeltaO+(",String(d),",",String(q),")") );
    SetSize( g, 2*q^(d*(d-2)/4)*(q^(d/2)-1)*Product(List([1..d/2-1],
                   i -> (q^(2*i)-1) )) );
    return g;
  end );

#############################################################################
#O  GammaOplus( <d>, <f> )
## returns the projective semi-similarity group of an hyperbolic orthogonal form
## We rely on DeltaOplus and the Frobenius automorphism.
##
InstallMethod( GammaOplus, [IsPosInt, IsField and IsFinite],
  function(d, f)
    local q, deltao, gens, frob, lambda, g;
    q := Size(f);
    deltao := DeltaOplus(d, f);
    gens := ShallowCopy(GeneratorsOfGroup(deltao));
    frob := FrobeniusAutomorphism( f );
    Add(gens, ProjElWithFrob( IdentityMat(d, f), frob, f ));
    g := GroupWithGenerators( gens );
    SetName( g, Concatenation("PGammaO+(",String(d),",",String(q),")") );
    SetSize( g, Log(q, Characteristic(f)) * Size(deltao) );
    return g;
  end );

###### Hermitian groups ######

#############################################################################
#O  GammaU( <d>, <f> )
## returns the projective semi-similarity group of hermitian form
## We rely on GU and the Frobenius automorphism.
##
## Issue here. The centre of GammaU is nontrivial for d=2.
## Our construction of classical groups in FinInG factors out the scalars,
## but not the full centre.
##
InstallMethod( GammaU, [IsPosInt, IsField and IsFinite],
  function(d, f)
   ## bug here, there is more than scalars in the kernel of the action!
    local m, frob, b, gens, g, q, sqrtq, gu;
    q := Size(f);
    sqrtq := Sqrt(Size(f));
    m := InvariantSesquilinearForm(GU(d,sqrtq))!.matrix;     
    b := BaseChangeHermitian(m, f)[1];
    frob := FrobeniusAutomorphism(f);
    gu := GU(d,sqrtq);
    gens := GeneratorsOfGroup( gu );
    gens := List( gens, y -> b * y * b^-1);
    gens := List( gens, x -> [x, frob^0]);
    Add(gens, [IdentityMat(d, f), frob] );
    gens := ProjElsWithFrob( gens, f );
    g := GroupWithGenerators( gens );
    SetSize( g, Order(frob) * Size(gu) / (sqrtq+1) );
    if d = 2 then
       Info(InfoFinInG, 1, "Warning: We have only factored scalars out of GammaU to construct a central cover of PGammaU.\n The centre is thus nontrivial and acts trivially on totally isotropic 1-spaces.");
       Info(InfoFinInG, 2, "So be careful because you're opening a can of worms!");
       SetName( g, Concatenation("2.PGammaU(",String(d),",",String(sqrtq),"^2)") );
    else
       SetName( g, Concatenation("PGammaU(",String(d),",",String(sqrtq),"^2)") ); 
    fi;
    return g;
  end );







[Dauer der Verarbeitung: 0.45 Sekunden, vorverarbeitet 2026-04-25]