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 157 kB image not shown  

SSL gpolygons.gi   Sprache: unbekannt

 
#############################################################################
##
##  gpolygons.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 generalised polygons.
##
#############################################################################

#############################################################################
# Part I: generic part
# This section is generic, i.e. if someone constructs a GP and obeys the representation,
# these methods will work.
#############################################################################
# about IsGeneralisedPolygonRep
# objects belonging to IsGeneralisedPolygonRep should have several fields in their record:
# pointsobj, linesobj, incidence, listelements, shadowofpoint, shadowofline, distance.
#
# pointsobj: a list containing the *underlying objects* for the points of the GP
#
# linesobj: a list containing the *underlying objects* for the lines of the GP
#
# incidence: a function, taking two *elements of the GP* as argument, returning true or false
#    we assume that the elements that are argument of this built in function, belong
#    to the same geometry. See generic method IsIncident.
#
# listelements: a function taking an integer as argument, returning
# a list of all elements of the GP of the given type. This list will be turned into an iterator
# by the method installed for Iterator for elements of GPs.
#
# shadowofpoint: a function, taking a *point of a GP* as argument, returning a list
# of lines incident with the given point.
#
# shadowofline: a function, taking a *line of a GP* as argument, returning a list
# of points incident with the given line.
#  The method for ShadowOfElement should do the necessary checks and pass the appropriate
#  function to the method installed for Iterator for shadow objects.
#
# span: a function taking two *points of a GP* returning fail or the unique line incident with the two points.
#
# meet: a function taking two *lines of a GP* returning fail or the unique point incident with the two lines.
#
# distance: a function taking two *elements of a GP* and returning their distance in the incidence graph.
#
# action: a function describing an action on the *underlying objects*.
#
# gonality: it is not very explicitely documented, but one can actually construct
#   generalised n-gons for n different than 3,4,6,8. To avoid checking the diameter of the underlying
#   graph e.g. for ViewObj, in these case the field gonality is set upon creation. One could say
#   that this field replaces the categories IsProjectivePlaneCategory, IsGeneralisedQuadrangle, IsGeneralisedHexagon
#   and IsGeneralisedOctagon for these arbitrary cases.
#
# Note: - If an object belongs to IsGeneralisedPolygon, then the "generic operations" to explore the GP
#   are *applicable* (does not imply that a specific method is installed or will be working).
#  - If a GP is constructed using a "Generic method", the above fields are created as described, making
#   all the methods for the "generic operations" working.
#  - If a GP is created as an object in IsGeneralisedPolygon and IsGeneralisedPolygonRep, with some of
#   these fields lacking or different, than separate methods need to be installed for certain operations
#   This is not problematic. A typical example are the hexagons: they belong also to IsLieGeometry,
#   so it is easy to get the right methods selected. Furthermore, typical methods for Lie geometries become
#   applicable (but might also need separate methods).
#  - If a GP is constructed using the "generic construction methods", there is always an underlying graph (to
#   check whether the user really constructs a GP. Creating the graph can be time consuming, but there is
#   the possibility to use a group. There is no NC version, either you are a developper, and you want to make
#   a particular GP (e.g. the hexagons) and then you know what you do and there is no need to check whether your
#   developed GP is really a GP, or you are a user and must be protected against yourself.
#   The computed graph is stored as a mutable attribute.
#  - For the particular GPs: of course we know that they are a GP, so on construction, we do not compute
#   the underlying graph.
#  - The classical GQs belong to IsGeneralisedPolygon but *not* to IsGeneralisedPolygonRep. For them there is
#   either an atrtibute set on creation (e.g. Order), or a seperate method for other generic operations.
#
#############################################################################

#############################################################################
#
# Construction of GPs
#
#############################################################################

#############################################################################
#O  GeneralisedPolygonByBlocks( <list> )
# returns a GP, the points are Union(blocks), the lines are the blocks. functions
# for shadows are installed. It is checked whether this is really a GP.
# Note that we allow weak GPs: these are GPs "without order", i.e. bipartite graph,
# grith = 2*diameter, but no constant valency for the vertices in (on of) the components
# of the graph. We can do the necessary checks with LocalParameters.
##
InstallMethod( GeneralisedPolygonByBlocks,
    "for a homogeneous list",
    [ IsHomogeneousList ],
    function( blocks )
        local pts, gp, ty, i, graph, sz, adj, girth, shadpoint, shadline, s, t, dist, vn,
  listels, objs, act, spanoftwopoints, meetoftwolines, bicomp, pointvertices, lp, linevertices;
        pts := Union(blocks);

        i := function( x, y )
        if IsSet( x!.obj ) and not IsSet( y!.obj ) then
            return y!.obj in x!.obj;
        elif IsSet( y!.obj ) and not IsSet( x!.obj ) then
            return x!.obj in y!.obj;
        else
            return x!.obj = y!.obj;
        fi;
        end;

        sz := Size(pts);

  adj := function(x,y)
   if IsSet(x) and not IsSet(y) then
    return y in x;
   elif IsSet(y) and not IsSet(x) then
    return x in y;
   else
    return false;
   fi;
  end;

  act := function(x,g)
   return x;
  end;

        graph := Graph(Group(()), Concatenation(pts,blocks), act, adj );
        girth := Girth(graph);

        if IsBipartite(graph) then
            if not girth = 2*Diameter(graph) then
                Error("<blocks> are not defining a generalised polygon");
            fi;
        else
            Error("<blocks are not defining a generalised polygon");
        fi;

        listels := function( geom, i )
   if i = 1 then
    return List(pts,x->Wrap(geom,i,x));
   else
    return List(blocks,x->Wrap(geom,i,x));
   fi;
  end;

  vn := VertexNames(graph);

        shadpoint := function( pt )
            return List(Filtered(blocks,x->pt!.obj in x),y->Wrap(pt!.geo,2,y));
        end;

        shadline := function( line )
            return List(line!.obj,x->Wrap(line!.geo,1,x));
        end;

  #we have the graph now, the following is easy.
  bicomp := Bicomponents(graph);
  pointvertices := First(bicomp,x->1 in x); #just take all points
  lp := LocalParameters(graph,pointvertices);
  t := lp[1][3]-1; #is the number of lines on a point, is -1 if there is no order, subtract to have t
  linevertices := First(bicomp,x->not 1 in x); #just take all lines
  lp := LocalParameters(graph,linevertices);
  s := lp[1][3]-1; #is the number of points on a line, is -1 if there is no orde, subtract to have s

  dist := function( el1, el2 )
   return Distance(graph,Position(vn,el1!.obj),Position(vn,el2!.obj));
  end;

        spanoftwopoints := function(x,y) #x and y are elements
            local i,j,span,el;
            i := Position(vn,x!.obj);
            j := Position(vn,y!.obj);
            el := Intersection(DistanceSet(graph,[1],i), DistanceSet(graph,[1],j));
            if not Length(el) = 0 then
                span := vn{el};
                return Wrap(x!.geo,2,span[1]);
            else
                Info(InfoFinInG, 1, "<x> and <y> do not span a line of gp");
                return fail;
            fi;
        end;

        meetoftwolines := function(x,y) #x and y are elements
            local i,j,meet,el;
            i := Position(vn,x!.obj);
            j := Position(vn,y!.obj);
            el := Intersection(DistanceSet(graph,[1],i), DistanceSet(graph,[1],j));
            if not Length(el) = 0 then
                meet := vn{el};
                return Wrap(x!.geo,1,meet[1]);
            else
                Info(InfoFinInG, 1, "<x> and <y> do meet in a common point of gp");
                return fail;
            fi;
        end;

        gp := rec( pointsobj := pts, linesobj := blocks, incidence := i, listelements := listels,
     shadowofpoint := shadpoint, shadowofline := shadline, distance := dist,
                    span := spanoftwopoints, meet := meetoftwolines );

        if t = -2 or s = -2 then
   ty := NewType( GeometriesFamily, IsWeakGeneralisedPolygon and IsGeneralisedPolygonRep );
            gp!.gonality := girth/2;
  elif girth = 6 then
            ty := NewType( GeometriesFamily, IsProjectivePlaneCategory and IsGeneralisedPolygonRep );
        elif girth = 8 then
            ty := NewType( GeometriesFamily, IsGeneralisedQuadrangle and IsGeneralisedPolygonRep );
        elif girth = 12 then
            ty := NewType( GeometriesFamily, IsGeneralisedHexagon and IsGeneralisedPolygonRep );
        elif girth = 16 then
            ty := NewType( GeometriesFamily, IsGeneralisedOctagon and IsGeneralisedPolygonRep );
        else
            ty := NewType( GeometriesFamily, IsGeneralisedPolygon and IsGeneralisedPolygonRep );
            gp!.gonality := girth/2;
        fi;

        Objectify( ty, gp );
        SetTypesOfElementsOfIncidenceStructure(gp, ["point","line"]);
        if s <> -2 and t <> -2 then
   SetOrder(gp, [s, t]);
  fi;
        SetRankAttr(gp, 2);
        Setter( IncidenceGraphAttr )( gp, graph );
        Setter( HasGraphWithUnderlyingObjectsAsVertices )( gp, true);
        return gp;
  end );

#############################################################################
#O  GeneralisedPolygonByIncidenceMatrix( <matrix> )
# returns a GP. points are [1..NrRows(matrix)], blocks are sets of entries equal to one.
# Blocks are then used through GeneralisedPolygonByBlocks.
# the commented out check dates from the times that this was only use to construct
# projective planes.
##
InstallMethod( GeneralisedPolygonByIncidenceMatrix,
    "for a matrix",
    [ IsMatrix ],
    function( mat )
    ## Rows represent blocks and columns represent points...
    local v, q, row, blocks, gp;
    v := NrRows(mat);
    #if not ForAll(mat, t->Size(t)=v) then
    #   Error("Matrix is not square");
    #fi;

    blocks := [];
    for row in mat do
        Add(blocks, Positions(row,1));
    od;

    gp := GeneralisedPolygonByBlocks( blocks );
    Setter( IncidenceMatrixOfGeneralisedPolygon )( gp, mat );
    return gp;
  end );

#############################################################################
#O  GeneralisedPolygonByElements( <pts>, <lns>, <inc> )
# <pts>: set of elements of some incidence structure, representing points of GP.
# <lns>: set of elements of some incidence structure, representing points of GP.
# <inc>: incidence function.
# it is checked throug the graph that the incidence structure is a GP.
##
InstallMethod( GeneralisedPolygonByElements,
    "for two sets (points and lines), and an incidence function",
    [ IsSet, IsSet, IsFunction ],
    function( pts, lns, inc )
    local adj, act, graph, ty, girth, shadpoint, shadline, s, t,
 gp, vn, dist, listels, wrapped_incidence, spanoftwopoints, meetoftwolines,
 bicomp, pointvertices, linevertices, lp;

    adj := function(x,y)
    if x in pts and y in pts then
        return false;
    elif x in lns and y in lns then
        return false;
    else
        return inc(x,y);
    fi;
    end;

    # this is the situation where the user gives no group at all. So action function is trivial too.
    act := function(x,g)
        return x;
    end;

    graph := Graph(Group(()), Concatenation(pts,lns), act, adj, true );
    girth := Girth(graph);

    if IsBipartite(graph) then
        if not girth = 2*Diameter(graph) then
            Error("<pts>, <lns>, <inc> are not defining a generalised polygon");
        fi;
    else
        Error("elements are not defining a generalised polygon");
    fi;

 bicomp := Bicomponents(graph);
 pointvertices := First(bicomp,x->1 in x); #just take all points
 lp := LocalParameters(graph,pointvertices);
 t := lp[1][3]-1; #is the number of lines on a point, is -1 if there is no order, subtract to have t
 linevertices := First(bicomp,x->(Size(pts)+1) in x); #just take all lines
 lp := LocalParameters(graph,linevertices);
 s := lp[1][3]-1; #is the number of points on a line, is -1 if there is no order, subtract to have s

 # inc takes in fact underlying objects as arguments. So we must make a new function that takes
 # as arguments elements of this geometry and pipes the underlying objects to inc.

 wrapped_incidence := function(x,y)
  return inc(x!.obj,y!.obj);
 end;

    listels := function( geom, i )
  if i = 1 then
   return List(pts,x->Wrap(geom,i,x));
  else
   return List(lns,x->Wrap(geom,i,x));
  fi;
 end;

    shadpoint := function( pt )
        return List(vn{Adjacency(graph,Position(vn,pt!.obj))},x->Wrap(gp,2,x));
    end;

    shadline := function( line )
        return List(vn{Adjacency(graph,Position(vn,line!.obj))},x->Wrap(gp,1,x));
    end;

    vn := VertexNames(graph);
 dist := function( el1, el2 )
        return Distance(graph,Position(vn,el1!.obj),Position(vn,el2!.obj));
    end;

    spanoftwopoints := function(x,y) #x and y are elements
        local i,j,span,el;
        i := Position(vn,x!.obj);
        j := Position(vn,y!.obj);
        el := Intersection(DistanceSet(graph,[1],i), DistanceSet(graph,[1],j));
        if not Length(el) = 0 then
            span := vn{el};
            return Wrap(x!.geo,2,span[1]);
        else
            Info(InfoFinInG, 1, "<x> and <y> do not span a line of gp");
            return fail;
        fi;
    end;

    meetoftwolines := function(x,y) #x and y are elements
        local i,j,meet,el;
        i := Position(vn,x!.obj);
        j := Position(vn,y!.obj);
        el := Intersection(DistanceSet(graph,[1],i), DistanceSet(graph,[1],j));
        if not Length(el) = 0 then
            meet := vn{el};
            return Wrap(x!.geo,1,meet[1]);
        else
            Info(InfoFinInG, 1, "<x> and <y> do meet in a common point of gp");
            return fail;
        fi;
    end;

    gp := rec( pointsobj := pts, linesobj := lns, incidence := wrapped_incidence, listelements := listels,
    shadowofpoint := shadpoint, shadowofline := shadline, distance := dist,
                span := spanoftwopoints, meet := meetoftwolines );

 if t = -2 or s = -2 then
  ty := NewType( GeometriesFamily, IsWeakGeneralisedPolygon and IsGeneralisedPolygonRep );
  gp!.gonality := girth/2;
 elif girth = 6 then
        ty := NewType( GeometriesFamily, IsProjectivePlaneCategory and IsGeneralisedPolygonRep );
    elif girth = 8 then
        ty := NewType( GeometriesFamily, IsGeneralisedQuadrangle and IsGeneralisedPolygonRep );
    elif girth = 12 then
        ty := NewType( GeometriesFamily, IsGeneralisedHexagon and IsGeneralisedPolygonRep );
    elif girth = 16 then
        ty := NewType( GeometriesFamily, IsGeneralisedOctagon and IsGeneralisedPolygonRep );
    else
        ty := NewType( GeometriesFamily, IsGeneralisedPolygon and IsGeneralisedPolygonRep );
        gp!.gonality := girth/2;
    fi;

    Objectify( ty, gp );
 if s <> -2 and t <> -2 then
  SetOrder(gp, [s, t]);
 fi;
    SetTypesOfElementsOfIncidenceStructure(gp, ["point","line"]);
    SetRankAttr(gp, 2);
    Setter( IncidenceGraphAttr )( gp, graph );
    Setter( HasGraphWithUnderlyingObjectsAsVertices )( gp, true);
    return gp;
end );

#############################################################################
#O  GeneralisedPolygonByElements( <pts>, <lns>, <inc>, <group>, <act> )
# <pts>: set of elements of some incidence structure, representing points of GP.
# <lns>: set of elements of some incidence structure, representing points of GP.
# <inc>: incidence function.
# <group>: group preserving <pts>, <lns> and <inc>
# <act>: action function for group on <pts> and <lns>.
# it is checked throug the graph that the incidence structure is a GP, by using
# the group, this is much more efficient. The user is responsible the <group>
# really preserves <pts> and <lns>
##
InstallMethod( GeneralisedPolygonByElements,
    "for two sets (points and lines), and an incidence function",
    [ IsSet, IsSet, IsFunction, IsGroup, IsFunction ],
    function( pts, lns, inc, group, act )
    local adj, graph, ty, girth, shadpoint, shadline, s, t, gp, vn,
 dist, listels, wrapped_incidence, spanoftwopoints, meetoftwolines,
 bicomp, pointvertices, linevertices, lp;

    adj := function(x,y)
    if x in pts and y in pts then
        return false;
    elif x in lns and y in lns then
        return false;
    else
        return inc(x,y);
    fi;
    end;

    graph := Graph(group, Concatenation(pts,lns), act, adj, true );
    girth := Girth(graph);

    if IsBipartite(graph) then
        if not girth = 2*Diameter(graph) then
            Error("<blocks> are not defining a generalised polygon");
        fi;
    else
        Error("elements are not defining a generalised polygon");
    fi;

 bicomp := Bicomponents(graph);
 pointvertices := First(bicomp,x->1 in x); #just take all points
 lp := LocalParameters(graph,pointvertices);
 t := lp[1][3]-1; #is the number of lines on a point, is -1 if there is no order, subtract -1 to have t
 linevertices := First(bicomp,x->(Size(pts)+1) in x); #just take all lines
 lp := LocalParameters(graph,linevertices);
 s := lp[1][3]-1; #is the number of points on a line, is -1 if there is no order, subtract -1 to have s

    vn := VertexNames(graph);

 # inc takes in fact underlying objects as arguments. So we must make a new function that takes
 # as arguments elements of this geometry and pipes the underlying objects to inc.

 wrapped_incidence := function(x,y)
  return inc(x!.obj,y!.obj);
 end;

    listels := function( geom, i )
  if i = 1 then
   return List(pts,x->Wrap(geom,i,x));
  else
   return List(lns,x->Wrap(geom,i,x));
  fi;
 end;

    shadpoint := function( pt )
        return List(vn{Adjacency(graph,Position(vn,pt!.obj))},x->Wrap(gp,2,x));
    end;

    shadline := function( line )
        return List(vn{Adjacency(graph,Position(vn,line!.obj))},x->Wrap(gp,1,x));
    end;

    dist := function( el1, el2 )
        return Distance(graph,Position(vn,el1!.obj),Position(vn,el2!.obj));
    end;

    spanoftwopoints := function(x,y) #x and y are elements
        local i,j,span,el;
        i := Position(vn,x!.obj);
        j := Position(vn,y!.obj);
        el := Intersection(DistanceSet(graph,[1],i), DistanceSet(graph,[1],j));
        if not Length(el) = 0 then
            span := vn{el};
            return Wrap(x!.geo,2,span[1]);
        else
            Info(InfoFinInG, 1, "<x> and <y> do not span a line of gp");
            return fail;
        fi;
    end;

    meetoftwolines := function(x,y) #x and y are elements
        local i,j,meet,el;
        i := Position(vn,x!.obj);
        j := Position(vn,y!.obj);
        el := Intersection(DistanceSet(graph,[1],i), DistanceSet(graph,[1],j));
        if not Length(el) = 0 then
            meet := vn{el};
            return Wrap(x!.geo,1,meet[1]);
        else
            Info(InfoFinInG, 1, "<x> and <y> do meet in a common point of gp");
            return fail;
        fi;
    end;

    gp := rec( pointsobj := pts, linesobj := lns, incidence := wrapped_incidence, listelements := listels,
    shadowofpoint := shadpoint, shadowofline := shadline, distance := dist, span := spanoftwopoints,
                meet := meetoftwolines, action := act );

 if t = -2 or s = -2 then
  ty := NewType( GeometriesFamily, IsWeakGeneralisedPolygon and IsGeneralisedPolygonRep );
  gp!.gonality := girth/2;
 elif girth = 6 then
        ty := NewType( GeometriesFamily, IsProjectivePlaneCategory and IsGeneralisedPolygonRep );
    elif girth = 8 then
        ty := NewType( GeometriesFamily, IsGeneralisedQuadrangle and IsGeneralisedPolygonRep );
    elif girth = 12 then
        ty := NewType( GeometriesFamily, IsGeneralisedHexagon and IsGeneralisedPolygonRep );
    elif girth = 16 then
        ty := NewType( GeometriesFamily, IsGeneralisedOctagon and IsGeneralisedPolygonRep );
    else
        ty := NewType( GeometriesFamily, IsGeneralisedPolygon and IsGeneralisedPolygonRep );
        gp!.gonality := girth/2;
    fi;

    Objectify( ty, gp );
 if s <> -2 and t <> -2 then
  SetOrder(gp, [s, t]);
 fi;
 SetTypesOfElementsOfIncidenceStructure(gp, ["point","line"]);
    SetRankAttr(gp, 2);
    Setter( IncidenceGraphAttr )( gp, graph );
    Setter( HasGraphWithUnderlyingObjectsAsVertices )( gp, true);
    return gp;
end );

#############################################################################
# View methods for GPs.
#############################################################################

InstallMethod( ViewObj,
 "for a projective plane in GP rep",
 [ IsProjectivePlaneCategory and IsGeneralisedPolygonRep],
 function( p )
        if HasOrder(p) then
            Print("<projective plane order ",Order(p)[1],">");
        else
            Print("<projective plane>");
        fi;
 end );

InstallMethod( ViewObj,
 "for a projective plane in GP rep",
 [ IsGeneralisedQuadrangle and IsGeneralisedPolygonRep],
 function( p )
        if HasOrder(p) then
            Print("<generalised quadrangle of order ",Order(p),">");
        else
            Print("<generalised quadrangle>");
        fi;
 end );

InstallMethod( ViewObj,
 "for a projective plane in GP rep",
 [ IsGeneralisedHexagon and IsGeneralisedPolygonRep],
 function( p )
        if HasOrder(p) then
            Print("<generalised hexagon of order ",Order(p),">");
        else
            Print("<generalised hexagon>");
        fi;
 end );

InstallMethod( ViewObj,
 "for a projective plane in GP rep",
 [ IsGeneralisedOctagon and IsGeneralisedPolygonRep],
 function( p )
        if HasOrder(p) then
            Print("<generalised octagon of order ",Order(p),">");
        else
            Print("<generalised octagon>");
        fi;
 end );

InstallMethod( ViewObj,
 "for a projective plane in GP rep",
 [ IsGeneralisedPolygon and IsGeneralisedPolygonRep],
 function( gp )
        if HasOrder(gp) then
            Print("<generalised polygon of gonality ",String(gp!.gonality)," and order ",Order(gp),">");
        else
            Print("<generalised polygon of gonality ",String(gp!.gonality),">");
        fi;
 end );

InstallMethod( ViewObj,
 "for a projective plane in GP rep",
 [ IsWeakGeneralisedPolygon and IsGeneralisedPolygonRep],
 function( gp )
  Print("<weak generalised polygon of gonality ",String(gp!.gonality),">");
 end );

#############################################################################
#
# Basic methods for elements (including construction and iterator).
#
#############################################################################

#############################################################################
#O  Order( <x> )
##
InstallMethod( Order,
 "for a weak generalised polygon",
 [ IsWeakGeneralisedPolygon ],
 function( gp )
  Error("<gp> is a weak generalised polygon and has no order");
 end );

#############################################################################
#O  UnderlyingObject( <x> )
##
InstallMethod( UnderlyingObject,
 "for an element of a LieGeometry",
 [ IsElementOfGeneralisedPolygon ],
 function( x )
  return x!.obj;
 end );

#############################################################################
#O  ObjectToElement( <geom>, <type>, <obj> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m> if and only if <obj> is the list [v,m].
##
InstallMethod( ObjectToElement,
 "for ageneralised polygon, an integer and an object",
 [ IsGeneralisedPolygon and IsGeneralisedPolygonRep, IsPosInt, IsObject],
 function(gp, t, obj)
  if t=1 then
   if obj in gp!.pointsobj then
    return Wrap(gp,t,obj);
   else
    Error("<obj> does not represent a point of <gp>");
   fi;
  elif t=2 then
   if obj in gp!.linesobj then
    return Wrap(gp,t,obj);
   else
    Error("<obj> does not represent a line of <gp>");
   fi;
  else
   Error("<gp> is a point-line geometry not containing elements of type ",t);
  fi;
 end );

#############################################################################
#O  ObjectToElement( <geom>, <obj> )
# returns the subspace of <geom>, with representative <v> and subspace at infinity
# determined by <m> if and only if <obj> is the list [v,m].
##
InstallMethod( ObjectToElement,
 "for ageneralised polygon and an object",
 [ IsGeneralisedPolygon and IsGeneralisedPolygonRep, IsObject],
 function(gp, obj)
  if obj in gp!.pointsobj then
   return Wrap(gp,1,obj);
  elif obj in gp!.linesobj then
   return Wrap(gp,2,obj);
  else
   Error("<obj> does not represent an element of <gp>");
  fi;
 end );

#############################################################################
#O  ElementsOfIncidenceStructure( <gp>, <j> )
# returns the elements of <gp> of type <j>
##
InstallMethod( ElementsOfIncidenceStructure,
 "for a generalised polygon and a positive integer",
 [IsGeneralisedPolygon and IsGeneralisedPolygonRep, IsPosInt],
 function( gp, j )
  local s, t, sz;
  if j in [1,2] then
   s := Order(gp)[j]; t := Order(gp)[3-j];
  else
   Error("Incorrect type value");
  fi;
  if IsProjectivePlaneCategory(gp) then
   sz := s^2 + s + 1;
  elif IsGeneralisedQuadrangle(gp) then
   sz := (1+s)*(1+s*t);
  elif IsGeneralisedHexagon(gp) then
   sz := (1+s)*(1+s*t+s^2*t^2);
  elif IsGeneralisedOctagon(gp) then
   sz := (1+s)*(1+s*t+s^2*t^2+s^3*t^3);
  else
            if j=1 then
                sz := Length(gp!.pointsobj);
            else
                sz := Length(gp!.linesobj);
            fi;
        fi;
  return Objectify( NewType( ElementsCollFamily, IsElementsOfGeneralisedPolygon and
                                IsElementsOfGeneralisedPolygonRep),
        rec( geometry := gp, type := j, size := sz )
      );
 end );

#############################################################################
#O  ElementsOfIncidenceStructure( <gp>, <j> )
# returns the elements of <gp> of type <j>
##
InstallMethod( ElementsOfIncidenceStructure,
 "for a generalised polygon and a positive integer",
 [IsWeakGeneralisedPolygon and IsGeneralisedPolygonRep, IsPosInt],
 function( gp, j )
  local s, t, sz;
  if not j in [1,2] then
   Error("Incorrect type value");
  fi;
        if j=1 then
   sz := Length(gp!.pointsobj);
  else
   sz := Length(gp!.linesobj);
  fi;
  return Objectify( NewType( ElementsCollFamily, IsElementsOfGeneralisedPolygon and
       IsElementsOfGeneralisedPolygonRep),
      rec( geometry := gp, type := j, size := sz ) );
 end );

#############################################################################
#O  Points( <gp>  )
# returns the points of <gp>.
##
InstallMethod( Points,
 "for a generalised polygon",
 [IsGeneralisedPolygon and IsGeneralisedPolygonRep],
 function( gp )
  return ElementsOfIncidenceStructure(gp, 1);
 end);

#############################################################################
#O  Lines( <gp>  )
# returns the lines of <gp>.
##
InstallMethod( Lines,
 "for a generalised polygon",
 [IsGeneralisedPolygon and IsGeneralisedPolygonRep],
 function( gp )
  return ElementsOfIncidenceStructure(gp, 2);
 end);

#############################################################################
# Display methods: Element collections
#############################################################################

InstallMethod( ViewObj,
 "for elements of a generalised polygon",
 [ IsElementsOfGeneralisedPolygon and IsElementsOfGeneralisedPolygonRep ],
 function( vs )
  local l;
  l := ["points","lines"];
  Print("<", l[vs!.type]," of ");
  ViewObj(vs!.geometry);
  Print(">");
 end );

InstallMethod( PrintObj,
 "for elements of a generalised polygon",
 [ IsElementsOfGeneralisedPolygon and IsElementsOfGeneralisedPolygonRep ],
 function( vs )
  Print("ElementsOfIncidenceStructure( ",vs!.geometry," , ",vs!.type,")");
 end );

#############################################################################
#O  Size( <gp>  )
# returns the size of a collection of elements of a <gp>
##
InstallMethod(Size,
 "for elements of a generalised polygon",
 [IsElementsOfGeneralisedPolygon],
 vs -> vs!.size );

#############################################################################
#O  Iterator( <vs>  )
# returns an iterator for the elements of a gp
##
InstallMethod( Iterator,
 "for elements of a generalised polygon",
 [ IsElementsOfGeneralisedPolygon and IsElementsOfGeneralisedPolygonRep],
 function( vs )
  local gp, j, vars;
  gp := vs!.geometry;
  j := vs!.type;
  if j in [1,2] then
   return IteratorList(gp!.listelements(gp,j)); #looks a bit strange, but correct.
  else
   Error("Element type does not exist");
  fi;
 end );

#############################################################################
#O  Iterator( <shadow>  )
# returns an iterator for a shadow of elements of a gp
##
InstallMethod( Iterator,
 "for shadow elements of a generalised polygon",
 [IsShadowElementsOfGeneralisedPolygon and IsShadowElementsOfGeneralisedPolygonRep ],
 function( vs )
        return IteratorList(vs!.func(vs!.element));
 end);

#############################################################################
#O  Random( <vs>  )
# In general, the list of elements might be stored in the GP itself. Then
# the standard method uses the Iterator. This standard method will be called
# also if our particular GPs do not have a collienation/elation group, the
# iterator will be used, which causes the computation of the collineation
#   group including a nice monomorphism. The next time Random is used, this
# group is used.
##
InstallMethod( Random,
 "for a collection of elements of a generalised polygon",
 [ IsElementsOfGeneralisedPolygon and IsElementsOfGeneralisedPolygonRep ],
 function( vs )
  local geo, type, class, group, rep, act;
  geo := vs!.geometry;
  type := vs!.type;
  if IsClassicalGeneralisedHexagon(geo) and HasCollineationGroup(geo) then
   group := CollineationGroup(geo);
   act := CollineationAction(group);
   rep := RepresentativesOfElements(geo)[type];
   return act(rep,Random(group));
  elif HasElationGroup(geo) then
   group := ElationGroup(geo);
   act := CollineationAction(group);
   rep := RepresentativesOfElements(geo)[type];
   return act(Random(rep),Random(group));
  else
   TryNextMethod();
  fi;
 end );

#############################################################################
#O  IsIncident( <x>, <y>  )
# simply uses the incidence relation that is built in in the gp.
# caveat: check here that elements belong to the same geometry!
##
InstallMethod( IsIncident,
 "for elements of a generalised polygon",
    [IsElementOfGeneralisedPolygon, IsElementOfGeneralisedPolygon],
 function( x, y )
  local inc;
  if not x!.geo = y!.geo then
   Error("The elements <x> and <y> do not belong to the same geometry");
  else
   inc := x!.geo!.incidence;
   return inc(x, y);
  fi;
 end );

#############################################################################
#O  Span( <x>, <y>  )
# return the line spanned by <x> and <y>, if they span a line at all.
##
InstallMethod( Span,
    "for two elements of a generalised polygon",
    [ IsElementOfGeneralisedPolygon, IsElementOfGeneralisedPolygon ],
    function( x, y )
        local graph, vn, el, i, j, span;
        if not x!.type = 1 and y!.type = 1 then
            Error("<x> and <y> must be points of a generalised polygon");
        elif not x!.geo = y!.geo then
            Error("<x> and <y> must belong to the same generalised polygon");
        fi;
        return x!.geo!.span(x,y);
    end );

#############################################################################
#O  Meet( <x>, <y>  )
# return the line spanned by <x> and <y>, if they span a line at all.
##
InstallMethod( Meet,
    "for two elements of a generalised polygon",
    [ IsElementOfGeneralisedPolygon, IsElementOfGeneralisedPolygon ],
    function( x, y )
        local graph, vn, el, i, j, meet;
        if not x!.type = 2 and y!.type = 2 then
            Error("<x> and <y> must be lines of a generalised polygon");
        elif not x!.geo = y!.geo then
            Error("<x> and <y> must belong to the same generalised polygon");
        fi;
        return x!.geo!.meet(x,y);
    end );

#############################################################################
#O  Wrap( <geo>, <type>, <o>  )
# returns the element of <geo> represented by <o>.
# this method is generic, but of course not fool proof.
##
InstallMethod( Wrap,
 "for a generalised polygon and an object",
 [IsGeneralisedPolygon, IsPosInt, IsObject],
 function( geo, type, o )
  local w;
  w := rec( geo := geo, type := type, obj := o );
  Objectify( NewType( ElementsOfIncidenceStructureFamily,
   IsElementOfIncidenceStructureRep and IsElementOfGeneralisedPolygon ), w );
  return w;
  end );

# CHECKED 11/09/11 jdb
#############################################################################
#A  TypesOfElementsOfIncidenceStructure( <gp> )
# returns the names of the types of the elements of the projective space <ps>
# the is a helper operation.
##
InstallMethod( TypesOfElementsOfIncidenceStructurePlural,
 "for a generalised polygon in the general representation",
    [ IsGeneralisedPolygon and IsGeneralisedPolygonRep ],
  x -> ["points", "lines"] );

#############################################################################
#O ShadowOfElement(<gp>, <el>, <j> )
##
InstallMethod( ShadowOfElement,
 "for a generalised polygon, an element, and an integer",
 [IsGeneralisedPolygon and IsGeneralisedPolygonRep, IsElementOfGeneralisedPolygon, IsPosInt],
 function( gp, el, j )
  local shadow, func;
        if not AmbientGeometry(el) = gp then
            Error("ambient geometry of <el> is not <gp>");
        fi;
        if j = el!.type then
            func := x->[x];
        elif j = 1 then
            func := gp!.shadowofline;
        elif j = 2 then
            func := gp!.shadowofpoint;
        else
            Error("<gp> has no shadow elements of type", j );
        fi;

        shadow := rec( geometry := gp, type := j, element := el, func := func );
  return Objectify( NewType( ElementsCollFamily, IsElementsOfIncidenceStructure and
       IsShadowElementsOfGeneralisedPolygon and
       IsShadowElementsOfGeneralisedPolygonRep),
       shadow
      );
 end);

#############################################################################
# View methods for shadow objects.
#############################################################################

InstallMethod( ViewObj,
 "for shadow elements of a generalised polygon",
 [ IsShadowElementsOfGeneralisedPolygon and IsShadowElementsOfGeneralisedPolygonRep ],
 function( vs )
  Print("<shadow ",TypesOfElementsOfIncidenceStructurePlural(vs!.geometry)[vs!.type]," in ");
  ViewObj(vs!.geometry);
  Print(">");
 end );

#############################################################################
#O  Points( <el> )
# returns the points, i.e. elements of type <1> in <el>, relying on ShadowOfElement
# for particular <el>.
##
InstallMethod( Points,
    "for an element of a generalised polygon",
 [ IsElementOfGeneralisedPolygon ],
 function( var )
  return ShadowOfElement(var!.geo, var, 1);
 end );

#############################################################################
#O  Lines( <el> )
# returns the lines, i.e. elements of type <2> in <el>, relying on ShadowOfElement
# for particular <el>.
##
InstallMethod( Lines,
    "for an element of a generalised polygon",
 [ IsElementOfGeneralisedPolygon ],
 function( var )
  return ShadowOfElement(var!.geo, var, 2);
 end );

#############################################################################
#O  DistanceBetweenElements( <gp>, <el1>, <el2> )
# returns the distance in the incidence graph between two elements
# Important notice: the '5' before the function increases the priority of this
# method for a pair of points satisfying the filters. The only situation where
# this is relevant is to compute the distance between elements of the Classical
# hexagons. Elements of these are also IsSubspaceOfClassicalPolarSpace. For
# elements of classical GQs, the above method for IsSubspaceOfClassicalPolarSpace
# must be applied. For elements of classical GHs, the generic method here must be
# used. But elements of classical GHs satisfy both filters, so the rank of the filters
# is used to select the method. As the rank of IsSubspaceOfClassicalPolarSpace is
# larger than the rank of IsElementOfGeneralisedPolygon, the wrong method gets
# selected for elements of GHs. The difference in rank is currently 2, times 2 makes
# 4, so adding 5 here should do the job, and it does.
##
InstallMethod( DistanceBetweenElements,
    "for a gp in gpRep and two of its elements",
 [ IsElementOfGeneralisedPolygon, IsElementOfGeneralisedPolygon],
    5,
 function( p, q )
  local geo;
        geo := p!.geo;
        if not geo = q!.geo then
            Error("<p> and <q> are not elements of the same generalised polygon");
        fi;
        return geo!.distance(p,q);
 end );

#############################################################################
#O  IncidenceGraph( <gp> )
# We could install a generic method. But currently, our particular GPs (hexagons,
# elation GQs, and classical GQs) have a particular method for good reasons. All other GPs
# currently possible to construct, have their incidence graph computed upon construction.
# So we may restrict here to checking whether this attribute is bounded, and return it,
# or print an error message. Note that we deal here with a mutable attribute.
###
InstallMethod( IncidenceGraph,
    "for a generalised polygon (in all possible representations",
    [ IsGeneralisedPolygon ],
    function( gp )
    local points, lines, graph, sz, adj, elations, gg, coll;
    #if not "grape" in RecNames(GAPInfo.PackagesLoaded) then
    #   Error("You must load the GRAPE package\n");
    #fi;
    if IsBound(gp!.IncidenceGraphAttr) then
       return gp!.IncidenceGraphAttr;
    else
        Error("no method installed currently");
    fi;
    end );

#############################################################################
#O  IncidenceMatrixOfGeneralisedPolygon( <gp> )
#
InstallMethod( IncidenceMatrixOfGeneralisedPolygon,
 "for a generalised polygon",
 [ IsGeneralisedPolygon ],
 function( gp )
  local graph, mat, incmat, szpoints, szlines;
  graph := IncidenceGraph( gp );
  mat := CollapsedAdjacencyMat(Group(()), graph);

    ## The matrix above is the adjacency matrix of the
    ## bipartite incidence graph.

  szpoints := Size(Points(gp));
  szlines := Size(Lines(gp));

  incmat := mat{[1..szpoints]}{[szpoints+1..szpoints+szlines]};
  return incmat;
 end );

#############################################################################
#O  CollineationGroup( <gp> )
# This method is generic. Note that:
# - for classical GQs, we have completely different methods to compute their
# collineation group, of course for good reasons;
# - for classical generalised hexagons, the same remark applies;
# - when a GP is constructed through generic methods, the underlying graph is
# always computed, since this is the only way to check if the input is not rubbish.
# But then the VertexNames of the constructed graph are the underlying objects.
# For particular GQs, the underlying graph is not computed upon construction.
#   But computing a graph afterwards, is very naturally done with the elements themselves
#   as VertexNames. This has some technical consequences to compute the collineation
#   group and to define the CollineationAction of it.
# To distinguish in this method, we introduced the property HasGraphWithUnderlyingObjectsAsVertices.
###
InstallMethod( CollineationGroup,
    "for a generalised polygon",
    [ IsGeneralisedPolygon and IsGeneralisedPolygonRep ],
    function( gp )
        local graph, aut, act, stab, coll, ptsn, points, pointsobj;
        graph := IncidenceGraph( gp );
        aut := AutomorphismGroup( graph );
        points := AsList(Points(gp));
        if HasGraphWithUnderlyingObjectsAsVertices(gp) then
            pointsobj := List(points,x->x!.obj);
            ptsn := Set(pointsobj,x->Position(VertexNames(graph),x));
        else
            ptsn := Set(points,x->Position(VertexNames(graph),x));
        fi;
        coll := Stabilizer(aut, ptsn, OnSets);
        if HasGraphWithUnderlyingObjectsAsVertices(gp) then
            act := function(el,g)
                local src,img;
                if el!.type = 1 then
                    src := Position(VertexNames(graph),el!.obj);
                    img := src^g;
                    return Wrap(gp,1,VertexNames(graph)[img]);
                elif el!.type = 2 then
                    src := Position(VertexNames(graph),el!.obj);
                    img := src^g;
                    return Wrap(gp,2,VertexNames(graph)[img]);
                fi;
            end;
        else
            act := function(el,g)
                local src,img;
    src := Position(VertexNames(graph),el); #change wrt generic function which would be el!.obj
    img := src^g;
    return VertexNames(graph)[img];
            end;
        fi;
        SetCollineationAction( coll, act );
  return coll;
    end );

#############################################################################
#O  BlockDesignOfGeneralisedPolygon( <gp> )
# Note about BlockDesign: this is a global (so read-only) function in the
# "design" package. We have created in FinInG a function BlockDesign (not
# through DeclareGlobalFunction, so it can be overwritten at user level and
# through loading other packages), so that the method for BlockDesignOfGeneralisedPolygon
# can be loaded without the "design" package loaded. We make sure that this method checks
# whether design is loaded, and produces an error when this is not the case.
#
InstallMethod( BlockDesignOfGeneralisedPolygon,
    "for a generalised polygon",
    [ IsGeneralisedPolygon and IsGeneralisedPolygonRep ],
    function( gp )
        local points, lines, des, blocks, l, b, elations, gg, orbs;
        if not IsPackageLoaded("design") then #this is a gap4r10 function.
        #if not "design" in RecNames(GAPInfo.PackagesLoaded) then
            Error("You must load the DESIGN package\n");
        fi;
        if IsBound(gp!.BlockDesignOfGeneralisedPolygonAttr) then
            return gp!.BlockDesignOfGeneralisedPolygonAttr;
        fi;
        points := AsList(Points(gp));;
        lines := AsList(Lines(gp));;
        if IsElationGQ(gp) and HasElationGroup( gp ) then
            elations := ElationGroup(gp);
            Info(InfoFinInG, 1, "Computing orbits on lines of gen. polygon...");
            orbs := List( Orbits(elations, lines, CollineationAction(elations)), Representative);
            orbs := List(orbs, l -> Filtered([1..Size(points)], i -> points[i] * l));
            gg := Action(elations, points, CollineationAction( elations ) );
            Info(InfoFinInG, 1, "Computing block design of generalised polygon...");
            des := BlockDesign(Size(points), orbs, gg );
        elif HasCollineationGroup(gp) then
            gg := CollineationGroup(gp);
            orbs := List( Orbits(gg, lines, CollineationAction(gg)), Representative);
            orbs := List(orbs, l -> Filtered([1..Size(points)], i -> points[i] * l));
            gg := Action(gg, points, CollineationAction( gg ) );
            des := BlockDesign(Size(points), orbs, gg );
        else
            blocks := [];
            for l in lines do
                b := Filtered([1..Size(points)], i -> points[i] * l);
                Add(blocks, b);
            od;
            des := BlockDesign(Size(points), Set(blocks));
        fi;
        Setter( BlockDesignOfGeneralisedPolygonAttr )( gp, des );
        return des;
  end );

#############################################################################
#
# Part II: particular models of GPs.
#
#############################################################################

#############################################################################
#
# Desarguesian projective planes. Methods needed:
# - DistanceBetweenElements
# - IncidenceGraph
#
#############################################################################

#############################################################################
#O  DistanceBetweenElements( <v>, <w> )
# It is possible to create points and lines of PG(2,q) in the category
# IsElementsOfGeneralisedPolygon (or even more specified). But this would increase
# the dependency of projectivespace.gi on gpolygons.gd, which we want to avoid.
###
InstallMethod( DistanceBetweenElements,
    "for subspaces of a projective space",
    [ IsSubspaceOfProjectiveSpace, IsSubspaceOfProjectiveSpace ],
    function( v, w )
        if not IsDesarguesianPlane(v!.geo) then
            Error( "Elements must have a generalised polygon as ambient geometry" );
        fi;
        if not v!.geo = w!.geo then
            Error( "Elements must belong to the same generalised polygon ");
        fi;
        if v = w then
            return 0;
        elif v!.type <> w!.type then
   if IsIncident(v,w) then
    return 1;
   else
    return 3;
   fi;
  else
   return 2;
  fi;
 end );

#############################################################################
#O  IncidenceGraph( <gp> )
# Note that computing the collineation group of a projective space is zero
# computation time. So useless to print the warning here if the group is not
# yet computed.
##
# Note that there is actually a method for IsProjectiveSpace, and IsDesarguesianPlane
# is a subcategory of IsProjectiveSpace. But the property HasGraphWithUnderlyingObjectsAsVertices
# is important for IsGeneralisedPolygon. We could check in the method for projective
# spaces whether the spaces is a plane, and set the property there, but we want
# to keep projectivespace.gi independent from gpolygons.gd.
###
InstallMethod( IncidenceGraph,
    "for a Desarguesian plane",
    [ IsDesarguesianPlane ],
    function( gp )
        local points, lines, graph, adj, group, coll, sz;
        #if not "grape" in RecNames(GAPInfo.PackagesLoaded) then
        #    Error("You must load the GRAPE package\n");
        #fi;
        if IsBound(gp!.IncidenceGraphAttr) then
            return gp!.IncidenceGraphAttr;
        fi;
        points := AsList(Points(gp));
        lines := AsList(Lines(gp));
        Setter( HasGraphWithUnderlyingObjectsAsVertices )( gp, false );
        Info(InfoFinInG, 1, "Computing incidence graph of generalised polygon...");
        adj := function(x,y)
            if x!.type <> y!.type then
                return IsIncident(x,y);
            else
                return false;
            fi;
        end;
        group := CollineationGroup(gp);
        graph := Graph(group,Concatenation(points,lines),OnProjSubspaces,adj,true);
        Setter( IncidenceGraphAttr )( gp, graph );
        return graph;
    end );

#############################################################################
#
# Classical GQs. Methods needed:
# - DistanceBetweenElements
# - IncidenceGraph
#
#############################################################################

#############################################################################
#O  DistanceBetweenElements( <v>, <w> )
# It is possible to create points and lines of PG(2,q) in the category
# IsElementsOfGeneralisedPolygon (or even more specified). But this would increase
# the dependency of projectivespace.gi on gpolygons.gd, which we want to avoid.
###
InstallMethod( DistanceBetweenElements,
    "for subspaces of a projective space",
    [ IsSubspaceOfClassicalPolarSpace, IsSubspaceOfClassicalPolarSpace ],
    function( v, w )
        if not IsClassicalGQ(v!.geo) then
            Error( "Elements must have a generalised polygon as ambient geometry" );
        fi;
        if not v!.geo = w!.geo then
            Error( "Elements must belong to the same generalised polygon ");
        fi;
        if v = w then
            return 0;
        elif v!.type <> w!.type then
   if IsIncident(v,w) then
    return 1;
   else
    return 3;
   fi;
  else
   if v!.type = 1 then
    if Span(v,w) in v!.geo then
     return 2;
    else
     return 4;
    fi;
   else
    if ProjectiveDimension(Meet(v,w)) = 0 then
     return 2;
    else
     return 4;
    fi;
   fi;
  fi;
 end );

#############################################################################
#O  IncidenceGraph( <gp> )
##
# Note that there is actually a method for IsProjectiveSpace, and IsDesarguesianPlane
# is a subcategory of IsProjectiveSpace. But the property HasGraphWithUnderlyingObjectsAsVertices
# is important for IsGeneralisedPolygon. We could check in the method for projective
# spaces whether the spaces is a plane, and set the property there, but we want
# to keep polarspace.gi independent from gpolygons.gd.
###
InstallMethod( IncidenceGraph,
    "for a generalised polygon (in all possible representations",
    [ IsClassicalGQ ],
    function( gp )
        local points, lines, graph, adj, group, coll, sz;
        #if not "grape" in RecNames(GAPInfo.PackagesLoaded) then
        #    Error("You must load the GRAPE package\n");
        #fi;
        if IsBound(gp!.IncidenceGraphAttr) then
            return gp!.IncidenceGraphAttr;
        fi;
        if not HasCollineationGroup(gp) then
            Error("No collineation group computed. Please compute collineation group before computing incidence graph\,n");
        else
            points := AsList(Points(gp));
            lines := AsList(Lines(gp));
            Setter( HasGraphWithUnderlyingObjectsAsVertices )( gp, false );
            Info(InfoFinInG, 1, "Computing incidence graph of generalised polygon...");
            adj := function(x,y)
                if x!.type <> y!.type then
                    return IsIncident(x,y);
                else
                    return false;
                fi;
            end;
            group := CollineationGroup(gp);
            graph := Graph(group,Concatenation(points,lines),OnProjSubspaces,adj,true);
            Setter( IncidenceGraphAttr )( gp, graph );
            return graph;
        fi;
  end );

#############################################################################
#
#  Classical Generalised Hexagons
#  This section implements H(q) and T(q,q^3). In FinInG, these geometries
#  are nicely constructed inside polar spaces, but are also constructed
#  formally as generalised polygons, which make typical operations available
#  Both are also Lie geometries, and are hard wired embedded inside the corresponding
#  polar space. See chapter 4 of the documentation.
#
#  For both models we (have to) install methods for Wrap etc. This makes other
#  operations, like OnProjSubspaces (action function) generic. As such, we can fully
#  exploit the fact that these geometries are also Lie geometries.
#
#############################################################################

#############################################################################
#O  Wrap( <geo>, <type>, <o>  )
# returns the element of <geo> represented by <o>
##
InstallMethod( Wrap,
 "for a generalised polygon and an object",
 [IsClassicalGeneralisedHexagon, IsPosInt, IsObject],
 function( geo, type, o )
  local w;
  w := rec( geo := geo, type := type, obj := o );
  Objectify( NewType( SoPSFamily, IsElementOfIncidenceStructureRep and IsElementOfGeneralisedPolygon
   and IsSubspaceOfClassicalPolarSpace ), w );
  return w;
  end );

#############################################################################
# The fixed, hard-coded triality :-)
#############################################################################

#############################################################################
#F  SplitCayleyPointToPlane5( <el> )
# returns a list of vectors spanning the plane of W(5,q): ---, which is the
# image of the point represented by <w> under the fixed triality
###
InstallGlobalFunction( SplitCayleyPointToPlane5,
    function(w, f)
        local z, hyps, q, y, spacevec, hyp, vec, int, n;
        q := Size(f);
        #w := Unpack(elvec);
  y := w{[1..3]};
        y{[5..7]} := w{[4..6]};
        y[4] := (y[1]*y[5]+y[2]*y[6]+y[3]*y[7])^(q/2);
        y[8] := -y[4];
        z := [];
  n := Zero(f);
        z[1] := [n,y[3],-y[2],y[5],y[8],n,n,n];
        z[2] := [-y[3],n,y[1],y[6],n,y[8],n,n];
        z[3] := [y[2],-y[1],n,y[7],n,n,y[8],n];
        z[4] := [n,n,n,-y[4],y[1],y[2],y[3],n];
        z[5] := [y[4],n,n,n,n,y[7],-y[6],y[1]];
        z[6] := [n,y[4],n,n,-y[7],n,y[5],y[2]];
        z[7] := [n,n,y[4],n,y[6],-y[5],n,y[3]];
        z[8] := [y[5],y[6],y[7],n,n,n,n,-y[8]];
        z := Filtered(z,x->not IsZero(x));
        hyp := [0,0,0,1,0,0,0,1]*Z(q)^0;
        Add(z,[0,0,0,1,0,0,0,1]*Z(q)^0);
        spacevec := NullspaceMat(TransposedMat(z));
  int := IdentityMat(8,f){[1..7]};
  int[4][8] := -One(f); #could have been One(f) too, since this is only used in even char...
  vec := SumIntersectionMat(spacevec, int)[2];
        return vec{[1..3]}{[1,2,3,5,6,7]};
    end );

#############################################################################
#F  SplitCayleyPointToPlane( <elvec>, <f> )
# returns a list of vectors spanning the plane of Q(6,q): ---, which is the
# image of the point represented by <elvec> under the fixed triality
##
InstallGlobalFunction( SplitCayleyPointToPlane,
 function(elvec, f)
  local z, hyps, y, spacevec, hyp, vec, int, n;
  y := ShallowCopy(elvec);
  y[8] := -y[4];
  z := [];
  n := Zero(f);
  z[1] := [n,y[3],-y[2],y[5],y[8],n,n,n];
  z[2] := [-y[3],n,y[1],y[6],n,y[8],n,n];
  z[3] := [y[2],-y[1],n,y[7],n,n,y[8],n];
  z[4] := [n,n,n,-y[4],y[1],y[2],y[3],n];
  z[5] := [y[4],n,n,n,n,y[7],-y[6],y[1]];
  z[6] := [n,y[4],n,n,-y[7],n,y[5],y[2]];
  z[7] := [n,n,y[4],n,y[6],-y[5],n,y[3]];
  z[8] := [y[5],y[6],y[7],n,n,n,n,-y[8]];
  z := Filtered(z,x->not IsZero(x));
  hyp := [0,0,0,1,0,0,0,1]*One(f);
  Add(z,[0,0,0,1,0,0,0,1]*One(f));
  spacevec := NullspaceMat(TransposedMat(z));
  int := IdentityMat(8,f){[1..7]};
  int[4,8] := -One(f);
  vec := SumIntersectionMat(spacevec, int)[2];
  return vec{[1..3]}{[1..7]};
 end );

#############################################################################
#F  ZeroPointToOnePointsSpaceByTriality( <elvec>, <frob>, <f> )
# returns a list of vectors spanning the solid of Q+(7,q): ---, which is the
# image of the point represented by <elvec> under the fixed triality
##
InstallGlobalFunction( ZeroPointToOnePointsSpaceByTriality,
 function(elvec,frob,f)
 # elvec represents a point of T(q,q^3)
  local z, hyps, y, spacevec, n;
  n := Zero(f);
  y := elvec^frob;
  z := [];
  z[1] := [n,y[3],-y[2],y[5],y[8],n,n,n];
  z[2] := [-y[3],n,y[1],y[6],n,y[8],n,n];
  z[3] := [y[2],-y[1],n,y[7],n,n,y[8],n];
  z[4] := [n,n,n,-y[4],y[1],y[2],y[3],n];
  z[5] := [y[4],n,n,n,n,y[7],-y[6],y[1]];
  z[6] := [n,y[4],n,n,-y[7],n,y[5],y[2]];
  z[7] := [n,n,y[4],n,y[6],-y[5],n,y[3]];
  z[8] := [y[5],y[6],y[7],n,n,n,n,-y[8]];
  z := Filtered(z,x->not IsZero(x));
  spacevec := NullspaceMat(TransposedMat(z));
  return spacevec;
 end );

#############################################################################
#F  TwistedTrialityHexagonPointToPlaneByTwoTimesTriality( <elvec>, <frob>, <f> )
# elvec represents a point of T(q^3,q). elvec^frob is a one point, elvec^frob^2
# is a two point. This function computes a basis for the intersection of the
# one and two point (which are actually generators of Q+(7,q)). There intersection
# will be a plane containing the q+1 lines through elvec.
##
InstallGlobalFunction( TwistedTrialityHexagonPointToPlaneByTwoTimesTriality,
 function(elvec,frob,f)
  local z, hyps, y, pg, spacevec1, spacevec2, n;
  n := Zero(f);
  #y := Unpack(elvec)^frob;
  y := elvec^frob;
  z := [];
  z[1] := [n,y[3],-y[2],y[5],y[8],n,n,n];
  z[2] := [-y[3],n,y[1],y[6],n,y[8],n,n];
  z[3] := [y[2],-y[1],n,y[7],n,n,y[8],n];
  z[4] := [n,n,n,-y[4],y[1],y[2],y[3],n];
  z[5] := [y[4],n,n,n,n,y[7],-y[6],y[1]];
  z[6] := [n,y[4],n,n,-y[7],n,y[5],y[2]];
  z[7] := [n,n,y[4],n,y[6],-y[5],n,y[3]];
  z[8] := [y[5],y[6],y[7],n,n,n,n,-y[8]];
  z := Filtered(z,x->not IsZero(x));
  spacevec1 := NullspaceMat(TransposedMat(z));
  z := y^frob;
  y := [];
  y[1] := [n,-z[3],z[2],n,z[4],n,n,z[5]];
  y[2] := [z[3],n,-z[1],n,n,z[4],n,z[6]];
  y[3] := [-z[2],z[1],n,n,n,n,z[4],z[7]];
  y[4] := [z[5],z[6],z[7],-z[4],n,n,n,n];
  y[5] := [z[8],n,n,z[1],n,-z[7],z[6],n];
  y[6] := [n,z[8],n,z[2],z[7],n,-z[5],n];
  y[7] := [n,n,z[8],z[3],-z[6],z[5],n,n];
  y[8] := [n,n,n,n,z[1],z[2],z[3],-z[8]];
  y := Filtered(y,x->not IsZero(x));
  spacevec2 := NullspaceMat(TransposedMat(y));
  return SumIntersectionMat(spacevec1, spacevec2)[2];
 end );

#############################################################################
# Constructor operations for the Classical Generalised Hexagons.
#############################################################################

#############################################################################
#O  SplitCayleyHexagon( <f> )
# returns the split cayley hexagon over <f>
##
InstallMethod( SplitCayleyHexagon,
 "for a finite field",
 [ IsField and IsFinite ],
 function( f )
    local geo, ty, repline, reppointvect, reppoint, replinevect, dist,
     hvm, ps, hvmform, form, nonzerof, x, w, listels, shadpoint, shadline;
    if IsOddInt(Size(f)) then
       ## the corresponding sesquilinear form here for
       ## q odd is the matrix
       ## [[0,0,0,0,1,0,0],[0,0,0,0,0,1,0],
       ## [0,0,0,0,0,0,1],[0,0,0,-2,0,0,0],
       ## [1,0,0,0,0,0,0],[0,1,0,0,0,0,0],[0,0,1,0,0,0,0]];

    ## this is Hendrik's form
  hvm := List([1..7], i -> [0,0,0,0,0,0,0]*One(f));
  hvm{[1..3]}{[5..7]} := IdentityMat(3, f);
  hvm{[5..7]}{[1..3]} := IdentityMat(3, f);
  hvm[4][4] := -2*One(f);
  hvmform := BilinearFormByMatrix(hvm, f);
  ps := PolarSpace(hvmform);
  # UnderlyingObject will return a cvec.
  reppointvect := UnderlyingObject(RepresentativesOfElements(ps)[1]);

       ## Hendrik's canonical line is <(1,0,0,0,0,0,0), (0,0,0,0,0,0,1)>
  replinevect := [[1,0,0,0,0,0,0], [0,0,0,0,0,0,1]] * One(f);
  TriangulizeMat(replinevect);
  #ConvertToMatrixRep(replinevect, f); #is useless now.
        shadpoint := function( pt )
            local planevec, flag, plane, f;
            f := BaseField( pt );
            planevec := SplitCayleyPointToPlane( Unpack(pt!.obj), f );
            plane := VectorSpaceToElement(PG(6,f),planevec);
            flag := FlagOfIncidenceStructure(PG(6,f),[pt,plane]);
            return List(ShadowOfFlag(PG(6,f),flag,2),x->Wrap(pt!.geo,2,Unwrap(x)));
        end;

        dist := function(el1,el2)
            local x,y;
            if el1=el2 then
                return 0;
            elif el1!.type = 1 and el2!.type = 1 then
                y := VectorSpaceToElement(PG(6,f), SplitCayleyPointToPlane(Unpack(el2!.obj),f)); #PG(5,f): avoids some unnecessary checks
                if el1 in y then
                    return 2;
                else
                    x := VectorSpaceToElement(PG(6,f), SplitCayleyPointToPlane(Unpack(el1!.obj),f));
                    if ProjectiveDimension(Meet(x,y)) = 0 then
                        return 4;
                    else
                        return 6;
                    fi;
                fi;
            elif el1!.type = 2 and el2!.type = 2 then
                if ProjectiveDimension(Meet(el1,el2)) = 0 then
                    return 2;
                fi;
                x := TangentSpace(ps,el1);
                if ProjectiveDimension(Meet(x,el2)) = 0 then
                    return 4;
                else
                    return 6;
                fi;
            elif el1!.type = 1 and el2!.type = 2 then
                if el1 in el2 then
                    return 1;
                fi;
                x := VectorSpaceToElement(PG(6,f), SplitCayleyPointToPlane(Unpack(el1!.obj),f));
                if ProjectiveDimension(Meet(x,el2)) = 0 then
                    return 3;
                else
                    return 5;
                fi;
            else
                return dist(el2,el1);
            fi;
        end;

    else
       ## Here we embed the hexagon in W(5,q)
       ## Hendrik's form
  hvm := List([1..6], i -> [0,0,0,0,0,0]*One(f));
  hvm{[1..3]}{[4..6]} := IdentityMat(3, f);
  hvm{[4..6]}{[1..3]} := IdentityMat(3, f);
  hvmform := BilinearFormByMatrix(hvm, f);
  ps := PolarSpace(hvmform);
  # UnderlyingObject will return a cvec.
  reppointvect := UnderlyingObject(RepresentativesOfElements(ps)[1]);

  ## Hendrik's canonical line is <(1,0,0,0,0,0), (0,0,0,0,0,1)>
  replinevect := [[1,0,0,0,0,0], [0,0,0,0,0,1]] * One(f);
  TriangulizeMat(replinevect);
  #ConvertToMatrixRep(replinevect, f); #is useless now.
        shadpoint := function( pt )
            local planevec, flag, plane, f;
            f := BaseField( pt );
            planevec := SplitCayleyPointToPlane5( Unpack(pt!.obj), f );
            plane := VectorSpaceToElement(PG(5,f),planevec);
            flag := FlagOfIncidenceStructure(PG(5,f),[pt,plane]);
            return List(ShadowOfFlag(PG(5,f),flag,2),x->Wrap(pt!.geo,2,Unwrap(x)));
        end;

        dist := function(el1,el2)
            local x,y;
            if el1=el2 then
                return 0;
            elif el1!.type = 1 and el2!.type = 1 then
                y := VectorSpaceToElement(PG(5,f), SplitCayleyPointToPlane5(Unpack(el2!.obj),f)); #PG(5,f): avoids some unnecessary checks
                if el1 in y then
                    return 2;
                else
                    x := VectorSpaceToElement(PG(5,f), SplitCayleyPointToPlane5(Unpack(el1!.obj),f));
                    if ProjectiveDimension(Meet(x,y)) = 0 then
                        return 4;
                    else
                        return 6;
                    fi;
                fi;
            elif el1!.type = 2 and el2!.type = 2 then
                if ProjectiveDimension(Meet(el1,el2)) = 0 then
                    return 2;
                fi;
                x := TangentSpace(ps,el1);
                if ProjectiveDimension(Meet(x,el2)) = 0 then
                    return 4;
                else
                    return 6;
                fi;
            elif el1!.type = 1 and el2!.type = 2 then
                if el1 in el2 then
                    return 1;
                fi;
                x := VectorSpaceToElement(PG(5,f), SplitCayleyPointToPlane5(Unpack(el1!.obj),f));
                if ProjectiveDimension(Meet(x,el2)) = 0 then
                    return 3;
                else
                    return 5;
                fi;
            else
                return dist(el2,el1);
            fi;
        end;

    fi;
 #now comes the cmatrixification of the replinevect
 replinevect := NewMatrix(IsCMatRep,f,Length(reppointvect),replinevect);

 listels := function(gp,j)
  local coll,reps;
  coll := CollineationGroup(gp);
  reps := RepresentativesOfElements( gp );
  return Enumerate(Orb(coll, reps[j], OnProjSubspaces));
 end;

 shadline := function( l )
  return List(Points(ElementToElement(AmbientSpace(l),l)),x->Wrap(l!.geo,1,x!.obj));
 end;

 #in the next line, we set the data fields for the geometry. We have to take into account that H(q) will also be
 #a Lie geometry, so it needs more data fields than a GP. But we can derive this information from ps.
 geo := rec( pointsobj := [], linesobj := [], incidence:= \*, listelements := listels, basefield := BaseField(ps),
  dimension := Dimension(ps), vectorspace := UnderlyingVectorSpace(ps), polarspace := ps,
  shadowofpoint := shadpoint, shadowofline := shadline, distance := dist);
    ty := NewType( GeometriesFamily, IsClassicalGeneralisedHexagon and IsGeneralisedPolygonRep );
    Objectify( ty, geo );
    SetAmbientSpace(geo, AmbientSpace(ps));
    SetAmbientPolarSpace(geo,ps);
    SetOrder(geo, [Size(f), Size(f)]);
    SetTypesOfElementsOfIncidenceStructure(geo, ["point","line"]);
    SetRankAttr(geo, 2);

    #now we are ready to pack the representatives of the elements, which are also elements of a polar space.
    #recall that reppointvect and replinevect are triangulized.
--> --------------------

--> maximum size reached

--> --------------------

[ Verzeichnis aufwärts0.66unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]