|
#############################################################################
##
## 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
]
|