Quelle poset.gi
Sprache: unbekannt
|
|
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen] #############################################################################
##
#W poset.gi XGAP library Max Neunhoeffer
##
##
#Y Copyright 1998, Max Neunhoeffer, Aachen, Germany
##
## This file contains the implementations for graphs and posets
##
#############################################################################
##
## Declarations of representations:
##
#############################################################################
#############################################################################
##
#R IsGraphicGraphRep . . . . . . . . . . . . . . . representation for graph
##
if not IsBound(IsGraphicGraphRep) then
DeclareRepresentation( "IsGraphicGraphRep",
IsComponentObjectRep and IsAttributeStoringRep and IsGraphicSheet and
IsGraphicSheetRep,
# we inherit those components from the sheet:
[ "name", "width", "height", "gapMenu", "callbackName", "callbackFunc",
"menus", "objects", "free",
# now our own components:
"vertices","edges","selectedvertices","menutypes",
"menuenabled","rightclickfunction","color"],
IsGraphicSheet );
fi;
#############################################################################
##
#R IsGraphicPosetRep . . . . . . . . . . . . . . . representation for poset
##
if not IsBound(IsGraphicPosetRep) then
DeclareRepresentation( "IsGraphicPosetRep",
IsComponentObjectRep and IsAttributeStoringRep and
IsGraphicSheet and IsGraphicSheetRep and IsGraphicGraphRep,
# we inherit those components from the sheet:
[ "name", "width", "height", "gapMenu", "callbackName", "callbackFunc",
"menus", "objects", "free",
# now our own components:
"levels", # list of levels, stores current total ordering
"levelparams", # list of level parameters
"selectedvertices", # list of selected vertices
"menutypes", # one entry per menu which contains list of types
"menuenabled", # one entry per menu which contains list of flags
"rightclickfunction", # the current function which is called when
# user clicks right button
"color", # some color infos for the case of different models
"levelboxes", # little graphic boxes for the user to handle levels
"showlevelparams", # flag, if level parameters are shown
"showlevels"], # flag, if levelboxes are shown
IsGraphicSheet );
fi;
#############################################################################
##
#R IsGPLevel . . . . . . . . . . . . . . . . . . . representation for level
##
if not IsBound(IsGPLevel) then
DeclareRepresentation( "IsGPLevel",
IsComponentObjectRep,
[ "top", # y coordinate of top of level, relative to sheet
"height", # height in pixels
"classes", # list of classes, which are lists of vertices
"classparams", # list of class parameters
"poset" # poset to which level belongs
],
IsGraphicObject );
fi;
#############################################################################
##
#R IsGGVertex . . . . . . . . . . . . . . . . . . representation for vertex
##
if not IsBound(IsGGVertex) then
DeclareRepresentation( "IsGGVertex",
IsComponentObjectRep and IsGraphicObject,
[ "data", # the mathematical data
"obj", # real graphic object
"x","y", # coordinates of graphic object within sheet
"serial", # a serial number for comparison
"label" # the label of the vertex or false
],
IsGraphicObject );
fi;
#############################################################################
##
#R IsGPVertex . . . . . . . . . . . . . . . . . . representation for vertex
##
if not IsBound(IsGPVertex) then
DeclareRepresentation( "IsGPVertex",
IsComponentObjectRep and IsGraphicObject,
[ "data", # the mathematical data
"obj", # real graphic object
"levelparam", # level parameter
"classparam", # class parameter
"maximals", # list of vertices which are maximal subobjects
"maximalin", # list of vertices where this one is maximal in
"x","y", # coordinates of graphic object within level
"serial", # a serial number for comparison
"label" # the label of the vertex or false
],
IsGraphicObject );
fi;
#############################################################################
##
## Some global things we all need:
##
#############################################################################
## We count all vertices:
PosetLastUsedSerialNumber := 0;
## The following function is installed as a LeftPBDown in every graph or
## poset. It calls the operation PosetLeftClick.
PosetLeftClickCallback := function(poset,x,y)
PosetLeftClick(poset,x,y);
end;
## The following function is installed as a RightPBDown in every graph or
## poset. It calls the operation PosetRightClick.
PosetRightClickCallback := function(poset,x,y)
PosetRightClick(poset,x,y);
end;
## The following function is installed as a CtrlLeftPBDown and
## ShiftLeftPBDown in every graph or poset. It calls the operation
## PosetCtrlLeftClick.
PosetCtrlLeftClickCallback := function(poset,x,y)
PosetCtrlLeftClick(poset,x,y);
end;
## The following is a for a menu entry and just calls another method:
PosetDoRedraw := function(poset,menu,entry)
DoRedraw(poset);
end;
## Our menu which goes in all poset sheets:
PosetMenuEntries :=
["Redraw","Show Levels","Show Level Parameters",,
"Delete Vertices","Delete Edge","Merge Classes",,
"Magnify Lattice", "Shrink Lattice", "Resize Lattice", "Resize Sheet",
"Move Lattice",,
"Change Labels","Average Y Positions","Average X Positions",
"Rearrange Classes"];
PosetMenuTypes :=
["forany","forany","forany",,
"forsubset","foredge","forsubset",,
"forany","forany","forany","forany","forany",,
"forsubset","forany","forsubset","forsubset"];
PosetMenuFunctions :=
[ PosetDoRedraw,PosetShowLevels,PosetShowLevelparams,,
UserDeleteVerticesOp, UserDeleteEdgeOp, UserMergeClassesOp,,
UserMagnifyLattice,UserShrinkLattice,UserResizeLattice,UserResizeSheet,
UserMoveLattice,,
UserChangeLabels,UserAverageY,UserAverageX,UserRearrangeClasses];
#############################################################################
##
## Constructors:
##
#############################################################################
## we need this to set up the colors in a sheet:
BindGlobal( "GPMakeColors",
function( sheet )
# set up color information:
if sheet!.color.model = "color" then
if COLORS.red <> false then
sheet!.color.unselected := COLORS.black;
sheet!.color.selected := COLORS.red;
else
sheet!.color.unselected := COLORS.dimGray;
sheet!.color.selected := COLORS.black;
fi;
if COLORS.green <> false then
sheet!.color.result := COLORS.green;
else
sheet!.color.result := COLORS.black; # COLORS.lightGray;
fi;
else
sheet!.color.selected := COLORS.black;
sheet!.color.unselected := COLORS.black;
sheet!.color.result := false;
fi;
end);
#############################################################################
##
#M GraphicGraph( <name>, <width>, <height> ) . . . . . . a new graphic graph
##
## creates a new graphic graph which is a graphic sheet representation
## with knowledge about vertices and edges and infrastructure for user
## interfaces.
##
InstallMethod( GraphicGraph,
"for a string, and two integers",
true,
[ IsString,
IsInt,
IsInt ],
0,
function( name, width, height )
#local ...;
end);
#############################################################################
##
#M GraphicPoset( <name>, <width>, <height> ) . . . . . . a new graphic poset
##
## creates a new graphic poset which is a specialization of a graphic graph
## mainly because per definition a poset comes in "layers" or "levels". This
## leads to some algorithms that are more efficient than the general ones
## for graphs.
##
InstallMethod( GraphicPoset,
"for a string, and two integers",
true,
[ IsString,
IsInt,
IsInt ],
0,
function( name, width, height )
local poset, tmpEntries, tmpTypes, tmpFuncs, m;
poset := GraphicSheet(name,width,height);
SetFilterObj(poset,IsGraphicGraphRep);
SetFilterObj(poset,IsGraphicPosetRep);
poset!.levels := [];
poset!.levelparams := [];
poset!.selectedvertices := [];
# think of the GAP menu:
poset!.menutypes := [List(poset!.menus[1]!.entries,x->"forany")];
poset!.menuenabled := [List(poset!.menus[1]!.entries,x->true)];
poset!.rightclickfunction := Ignore;
# set up color information:
poset!.color := rec();
if COLORS.red <> false or COLORS.lightGray <> false then
poset!.color.model := "color";
# note: if you rename this, think of the "use black&white" below!
else
poset!.color.model := "monochrome";
fi;
GPMakeColors(poset);
poset!.levelboxes := [];
poset!.showlevels := false;
poset!.lptexts := [];
poset!.showlevelparams := true;
InstallCallback(poset,"LeftPBDown",PosetLeftClickCallback);
InstallCallback(poset,"ShiftLeftPBDown",PosetCtrlLeftClickCallback);
InstallCallback(poset,"CtrlLeftPBDown",PosetCtrlLeftClickCallback);
InstallCallback(poset,"RightPBDown",PosetRightClickCallback);
tmpEntries := ShallowCopy(PosetMenuEntries);
tmpTypes := ShallowCopy(PosetMenuTypes);
tmpFuncs := ShallowCopy(PosetMenuFunctions);
if poset!.color.model = "color" then
Append(tmpEntries,["-","Use Black&White"]);
Append(tmpTypes,["-","forany"]);
Append(tmpFuncs,["-",UserUseBlackWhite]);
fi;
m := Menu(poset,"Poset",tmpEntries,tmpTypes,tmpFuncs);
Check(m,"Show Level Parameters",true);
return poset;
end);
#############################################################################
##
#M CreateLevel(<poset>, <levelparam>) . . . . . . creates new level in poset
#M CreateLevel(<poset>, <levelparam>, <lptext>) . creates new level in poset
##
## A level in a graphic poset can be thought of as a horizontal slice of
## the poset. It has a y coordinate of the top of the level relatively to
## the graphic sheet and a height. Every class of vertices in a graphic
## poset is in a level. The levels are totally ordered by their y
## coordinate. No two vertices which are included in each other are in the
## same level. A vertex containing another one is always "higher" on the
## screen, meaning in a "higher" level. Every level has a unique
## levelparam, which can be any {\GAP} object. The user is responsible for
## all methods where a levelparam occurs as parameter and is not just an
## integer. There is NO {\GAP} object representing a level which is visible
## for the user of posets. All communication about levels goes via the
## levelparam. Returns fail if there is already a level with a level
## parameter which is considered "equal" by CompareLevels or levelparam if
## everything went well.
## The second method allows to specify which text appears for the level at
## the right edge of the sheet.
##
InstallMethod( CreateLevel,
"for a graphic poset, a level parameter, and a string",
true,
[ IsGraphicPosetRep, IsObject, IsString ],
0,
function( poset, levelparam, lpstr )
local level, box, str, strlen, text, l, firstpos, before, look,
compare, i, cl, v;
# does this level parameter exist already?
if Position(poset!.levelparams,levelparam) <> fail then
return fail;
fi;
# create a level object:
level := rec(classes := [],
classparams := [],
poset := poset);
Objectify(NewType(GraphicObjectFamily,IsGPLevel),level);
# is it the first level:
if poset!.levelparams = [] then
poset!.levelparams := [levelparam];
poset!.levels := [level];
level!.top := 0;
level!.height := 2 * VERTEX.diameter;
# make a level box:
box := Box(poset,0,level!.top+level!.height-8,8,8);
if COLORS.blue <> false then
Recolor(box,COLORS.blue);
fi;
if not poset!.showlevels then
Destroy(box);
fi;
poset!.levelboxes := [ box ];
# make a text for level parameter:
if lpstr <> "" then
str := lpstr;
else
str := String(levelparam);
fi;
strlen := Length(str);
text := Text(poset,FONTS.normal,
poset!.width - 24 - strlen*FontInfo(FONTS.normal)[3],
level!.top + QuoInt(level!.height,2),str);
if COLORS.blue <> false then
Recolor(text,COLORS.blue);
fi;
if not poset!.showlevelparams then
Destroy(text);
fi;
poset!.lptexts := [ text ];
return levelparam;
fi;
# now find the position, we choose the last position where the new level
# can be according to the partial order defined by CompareLevels we do a
# binary search, we insert not before "firstpos" and before "before".
# Attention: We cannot decide at a level which is not comparable to the
# new level, so we have to search linearly for a comparable level!
l := Length(poset!.levelparams);
firstpos := 1;
before := l + 1;
while firstpos < before do
look := QuoInt(firstpos + before,2);
repeat # search first backward up to firstpos, then down
compare := CompareLevels(poset,levelparam,poset!.levelparams[look]);
if compare = 0 then
return fail;
elif compare = fail then # not comparable
look := look-1;
fi;
until compare <> fail or look < firstpos;
if compare = fail then
# search now forward down to before
look := QuoInt(firstpos + before,2)+1;
if look = before then
firstpos := before; # we insert right HERE!
compare := 0;
fi;
while compare = fail do
compare := CompareLevels(poset,levelparam,poset!.levelparams[look]);
if compare = 0 then
return fail;
elif compare = fail then # not comparable
look := look+1;
if look = before then # nothing comparable in between!
firstpos := before; # we insert right HERE!
compare := 0; # this does exactly that!
fi;
fi;
od;
fi;
if compare < 0 then
before := look;
elif compare > 0 then
firstpos := look+1;
fi;
od;
# we now insert at position firstpos = before:
poset!.levelparams{[firstpos+1..l+1]} := poset!.levelparams{[firstpos..l]};
poset!.levelparams[firstpos] := levelparam;
poset!.levels{[firstpos+1..l+1]} := poset!.levels{[firstpos..l]};
poset!.levels[firstpos] := level;
poset!.levelboxes{[firstpos+1..l+1]} := poset!.levelboxes{[firstpos..l]};
poset!.lptexts{[firstpos+1..l+1]} := poset!.lptexts{[firstpos..l]};
if firstpos = 1 then
level!.top := 0;
else
level!.top := poset!.levels[firstpos-1]!.top +
poset!.levels[firstpos-1]!.height;
fi;
level!.height := 2 * VERTEX.diameter;
# move all lower levels down:
FastUpdate(poset,true);
for i in [firstpos+1..l+1] do
poset!.levels[i]!.top := poset!.levels[i]!.top + level!.height;
for cl in poset!.levels[i]!.classes do
for v in cl do
MoveDelta(v!.obj,0,level!.height);
od;
od;
if poset!.showlevels then
MoveDelta(poset!.levelboxes[i],0,level!.height);
fi;
if poset!.showlevelparams then
MoveDelta(poset!.lptexts[i],0,level!.height);
fi;
od;
FastUpdate(poset,false);
# has the graphic sheet become higher?
l := l + 1; # this means: l := Length(poset!.levels);
i := poset!.levels[l]!.top + poset!.levels[l]!.height;
if i > poset!.height then
Resize(poset,poset!.width,i);
fi;
# create a level box:
box := Box(poset,0,level!.top+level!.height-8,8,8);
if COLORS.blue <> false then
Recolor(box,COLORS.blue);
fi;
if not poset!.showlevels then
Destroy(box);
fi;
poset!.levelboxes[firstpos] := box;
# create a level parameter text:
if lpstr <> "" then
str := lpstr;
else
str := String(levelparam);
fi;
strlen := Length(str);
text := Text(poset,FONTS.normal,
poset!.width - 24 - strlen*FontInfo(FONTS.normal)[3],
level!.top + QuoInt(level!.height,2),str);
if COLORS.blue <> false then
Recolor(text,COLORS.blue);
fi;
if not poset!.showlevelparams then
Destroy(text);
fi;
poset!.lptexts[firstpos] := text;
return levelparam;
end);
InstallOtherMethod( CreateLevel,
"for a graphic poset, and a level parameter",
true,
[ IsGraphicPosetRep, IsObject ],
0,
function( poset, levelparam )
return CreateLevel(poset,levelparam,"");
end);
#############################################################################
##
#M CreateClass(<poset>,<levelparam>,<classparam>) . . . . creates new class
##
## A class in a graphic poset is a collection of vertices within a level
## which belong together in some sense. Every vertex in a graphic poset
## is in a class, which in turn belongs to a level. Every class in a level
## has a unique classparam, which can be any {\GAP} object. The user is
## responsible for all methods where a classparam occurs as parameter and
## is not just an integer. There is NO {\GAP} object representing a class
## which is visible to the user of posets. All communication about classes
## goes via the classparam. Returns fail if there is no level with
## parameter levelparam or there is already a class in this level with
## parameter classparam. Returns classparam otherwise.
##
InstallMethod( CreateClass,
"for a graphic poset, a level parameter, and a class parameter",
true,
[ IsGraphicPosetRep, IsObject, IsObject ],
0,
function( poset, levelparam, classparam )
local nr, level;
nr := Position(poset!.levelparams,levelparam);
if nr = fail then
return fail;
fi;
level := poset!.levels[nr];
nr := Position(level!.classparams,classparam);
if nr <> fail then
return fail;
fi;
Add(level!.classparams,classparam);
Add(level!.classes,[]);
return classparam;
end);
#############################################################################
##
#M Vertex(<graph>,<data>[,<inf>]) . . . . . . . . . . . . creates new vertex
##
## Creates a new vertex. <inf> is a record in which additional info can be
## supplied for the new vertex. For general graphic graphs only the
## "label", "color", "shape", "x" and "y" components are applicable, they
## contain a short label which will be attached to the vertex, the color,
## the shape ("circle", "diamond", or "rectangle") and the coordinates
## relative to the graphic sheet respectively. For graphic posets also the
## components "levelparam" and "classparam" are evaluated. If the component
## "hints" is bound it must be a list of x coordinates which will be
## delivered to ChoosePosition to help placement. Those x coordinates will
## be the coordinates of other vertices related to the new one. All values of
## record components which are not specified will be determined by calling
## some methods for graphic graphs or posets. Those are:
## ChooseLabel for the label,
## ChooseColor for the color,
## ChooseShape for the shape,
## ChoosePosition for the position,
## ChooseLevel for the levelparam, and
## ChooseClass for the classparam.
## ChooseWidth for the line width of the vertex
## Returns fail no vertex was created. This happens only, if one of the
## choose functions return fail or no possible value, for example a
## non-existing level or class parameter.
## Returns vertex object if everything went well.
##
InstallOtherMethod( Vertex,
"for a graphic poset, an object, and a record",
true,
[ IsGraphicPosetRep, IsObject, IsRecord ],
0,
function( poset, data, info )
local lp, lnr, level, cp, cnr, class, vertex, label, shape,
color, position, width;
# first determine levelparam:
if not IsBound(info.levelparam) then
lp := ChooseLevel(poset,data);
else
lp := info.levelparam;
fi;
if lp = fail then
return fail;
fi;
# we search for the level:
lnr := Position(poset!.levelparams,lp);
if lnr = fail then
return fail;
fi;
level := poset!.levels[lnr];
# now determine class:
if not IsBound(info.classparam) then
cp := ChooseClass(poset,data,lp);
else
cp := info.classparam;
fi;
if cp = fail then
return fail;
fi;
# we search for the class:
cnr := Position(level!.classparams,cp);
if cnr = fail then
return fail;
fi;
class := level!.classes[cnr];
# create a new vertex object:
PosetLastUsedSerialNumber := PosetLastUsedSerialNumber + 1;
vertex := rec(data := data,
levelparam := lp,
classparam := cp,
maximals := [],
maximalin := [],
serial := PosetLastUsedSerialNumber);
Objectify(NewType(GraphicObjectFamily,IsGPVertex),vertex);
SetFilterObj(vertex,IsGGVertex);
SetFilterObj(vertex,IsAlive);
# choose label, shape, color and position:
if not IsBound(info.label) then
label := ChooseLabel(poset,data);
if label = fail then
return fail;
fi;
else
label := info.label;
fi;
if not IsBound(info.shape) then
shape := ChooseShape(poset,data);
if shape = fail then
return fail;
fi;
else
shape := info.shape;
fi;
if not IsBound(info.color) then
color := ChooseColor(poset,data);
if color = fail then
return fail;
fi;
else
color := info.color;
fi;
if not (IsBound(info.x) and IsBound(info.y)) then
if IsBound(info.hints) then
position := ChoosePosition(poset,data,level,class,info.hints);
else
position := ChoosePosition(poset,data,level,class,[]);
fi;
if IsBound(info.x) then # this takes precedence!
vertex!.x := info.x;
else
vertex!.x := position[1];
fi;
if IsBound(info.y) then # this takes precedence!
vertex!.y := info.y;
else
vertex!.y := position[2];
fi;
else
vertex!.x := info.x;
vertex!.y := info.y;
fi;
if not IsBound(info.width) then
width := ChooseWidth(poset,data);
if width = fail then
return fail;
fi;
fi;
vertex!.label := label;
# create the graphic object:
vertex!.obj := Vertex(poset,vertex!.x,level!.top + vertex!.y,
rec(label := label,color := color,width := width));
if shape = "diamond" then
Reshape(vertex!.obj,VERTEX.diamond);
elif shape = "rectangle" then
Reshape(vertex!.obj,VERTEX.rectangle);
fi;
# put it into the class:
Add(class,vertex);
return vertex;
end);
#############################################################################
##
## The following function is only internal:
##
## Use it on your own risk and only if you know what you are doing!
##
GPSearchWay := function(poset,v1,v2,l2)
local v, p;
for v in v1!.maximals do
if v = v2 then
return true;
fi;
if Position(poset!.levelparams,v!.levelparam) < l2 then
if GPSearchWay(poset,v,v2,l2) then
return true;
fi;
fi;
od;
return false;
end;
#############################################################################
##
#M Edge(<poset>,<vertex1>,<vertex2>) . . . . . . . . . . . . adds a new edge
#M Edge(<poset>,<vertex1>,<vertex2>,<def>) . . . . . . . . . adds a new edge
##
## Adds a new edge from <vertex1> to <vertex2>. For posets this puts one
## of the vertices into the other as a maximal subvertex. So either
## <vertex1> must lie in a "higher" level than <vertex2> or the other way
## round. There must be no vertex "between" <vertex1> and <vertex2>. If
## the two vertices are in the same level or one is already indirectly
## included in the other fail is returned, otherwise true. That means,
## that in the case where one of the two vertices is already a maximal
## subobject of the other, then the method does nothing and returns true.
## The variation with a defaults record just hands this over to the lower
## levels, meaning that the line width and color are modified.
##
InstallOtherMethod( Edge,
"for a graphic poset, two vertices, and a defaults record",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsRecord ],
0,
function( poset, v1, v2, def )
local l1, l2, dummy, l, p;
# we permute v1 and v2 such that v1 is in higher level:
if CompareLevels(poset,v1!.levelparam,v2!.levelparam) = 0 then
return fail;
fi;
l1 := Position(poset!.levelparams,v1!.levelparam);
l2 := Position(poset!.levelparams,v2!.levelparam);
if l1 > l2 then
dummy := v1;
v1 := v2;
v2 := dummy;
dummy := l1;
l1 := l2;
l2 := dummy;
fi;
# first we have to perform a few checks:
if Position(v1!.maximals,v2) <> fail then
return true;
fi;
if GPSearchWay(poset,v1,v2,l2) then
return fail;
fi;
# let's think about color, label and width:
if not IsBound(def.color) then
def.color := ChooseColor(poset,v1!.data,v2!.data);
if def.color = fail then
return fail;
fi;
fi;
if not IsBound(def.label) then
def.label := ChooseLabel(poset,v1!.data,v2!.data);
if def.label = fail then
return fail;
fi;
fi;
if not IsBound(def.width) then
def.width := ChooseWidth(poset,v1!.data,v2!.data);
if def.width = fail then
return fail;
fi;
fi;
# now we know that there is no direct or indirect inclusion of v2 in v1.
# we can safely put v2 "into" v1.
Add(v1!.maximals,v2);
Add(v2!.maximalin,v1);
Connection(v1!.obj,v2!.obj,def);
return true;
end);
InstallOtherMethod( Edge,
"for a graphic poset, and two vertices",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex ],
0,
function( poset, v1, v2 )
return Edge(poset,v1,v2,rec());
end);
#############################################################################
##
## Destructors:
##
#############################################################################
#############################################################################
##
## Set this variable temporarily to false if you delete many things!
##
GGDeleteModifiesMenu := true;
#############################################################################
##
#M Delete(<graph>,<obj>) . . . . . . . . . . . . . remove something in graph
##
## This operation already exists in {\XGAP} for the graphic objects!
## Applicable for edges, vertices, classes.
##
## The following method applies to an edge, given by two vertices. It returns
## fail if not one of the vertices is maximal in the other and true
## otherwise.
InstallOtherMethod( Delete,
"for a graphic poset, and two vertices",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex ],
0,
function( poset, v1, v2 )
local p, dummy, l;
# determine which is the "bigger one":
p := Position(v2!.maximals,v1);
if p = fail then
p := Position(v1!.maximals,v2);
if p = fail then
return fail;
fi;
# swap the vertices:
dummy := v1;
v1 := v2;
v2 := dummy;
fi;
# v1 is now maximal in v2 at position p in v2!.maximals
Disconnect(v1!.obj,v2!.obj);
l := Length(v2!.maximals);
v2!.maximals[p] := v2!.maximals[l];
Unbind(v2!.maximals[l]);
p := Position(v1!.maximalin,v2);
# fail is not an option here! If that happens we bomb out!
l := Length(v1!.maximalin);
v1!.maximalin[p] := v1!.maximalin[l];
Unbind(v1!.maximalin[l]);
# think about the menus:
if GGDeleteModifiesMenu then
ModifyEnabled(poset,1,Length(poset!.menus));
fi;
return true;
end);
## The following method applies to a vertex. It returns fail if the vertex
## is not in the poset. The vertex is deleted and all connections to other
## vertices are also deleted! Returns true if vertex is successfully deleted.
InstallOtherMethod( Delete,
"for a graphic poset, and a vertex",
true,
[ IsGraphicPosetRep, IsGPVertex ],
0,
function( poset, v )
local lp, l, cp, cl, p, savemaximals, savemaximalin, noerror,
v1, v2, store;
lp := Position(poset!.levelparams,v!.levelparam);
if lp = fail then
return fail;
fi;
l := poset!.levels[lp];
cp := Position(l!.classparams,v!.classparam);
if cp = fail then
return fail;
fi;
cl := l!.classes[cp];
p := Position(cl,v);
if p = fail then
return fail;
fi;
# Remember all connections:
savemaximals := ShallowCopy(v!.maximals);
savemaximalin := ShallowCopy(v!.maximalin);
# Delete all connections:
noerror := true;
store := GGDeleteModifiesMenu;
GGDeleteModifiesMenu := false;
while v!.maximals <> [] do
if Delete(poset,v,v!.maximals[1]) = fail then
noerror := fail;
fi;
od;
while v!.maximalin <> [] do
if Delete(poset,v,v!.maximalin[1]) = fail then
noerror := fail;
fi;
od;
GGDeleteModifiesMenu := store;
# was it selected?
RemoveSet(poset!.selectedvertices,v);
# now delete vertex:
Delete(v!.obj);
ResetFilterObj(v,IsAlive);
l := Length(cl);
cl[p] := cl[l];
Unbind(cl[l]);
# now we have to add new inclusions from the maximal subobjects to those
# where our vertex was maximal in. We should not do that however, if there is
# already a way. This ensures that the diagram will be again a Hasse diagram
# of the remaining vertices with the inclusions induced by the poset
# before deletion.
for v1 in savemaximals do
for v2 in savemaximalin do
if not GPSearchWay(poset,v2,v1,
Position(poset!.levelparams,v1!.levelparam)) then
Edge(poset,v2,v1);
fi;
od;
od;
# think about the menus:
if GGDeleteModifiesMenu then
ModifyEnabled(poset,1,Length(poset!.menus));
fi;
return noerror;
end);
## The following method applies to a class. It returns fail if the class
## is not in the poset. The class is deleted and all vertices including
## their connections to other vertices are also deleted! Returns true
## if class is successfully deleted.
## The two parameters are a level parameter and a class parameter.
InstallOtherMethod( Delete,
"for a graphic poset, and two objects",
true,
[ IsGraphicPosetRep, IsObject, IsObject ],
0,
function( poset, levelparam, classparam )
local lp, l, cp, noerror, v, store;
lp := Position(poset!.levelparams,levelparam);
if lp = fail then
return fail;
fi;
l := poset!.levels[lp];
cp := Position(l!.classparams,classparam);
if cp = fail then
return fail;
fi;
# delete all vertices:
noerror := true;
store := GGDeleteModifiesMenu;
GGDeleteModifiesMenu := false;
for v in l!.classes[cp] do
if Delete(poset,v) = fail then
noerror := fail;
fi;
od;
GGDeleteModifiesMenu := store;
lp := Length(l!.classes);
l!.classes[cp] := l!.classes[lp];
Unbind(l!.classes[lp]);
l!.classparams[cp] := l!.classparams[lp];
Unbind(l!.classparams[lp]);
# think about the menus:
if GGDeleteModifiesMenu then
ModifyEnabled(poset,1,Length(poset!.menus));
fi;
return noerror;
end);
#############################################################################
##
#M DeleteLevel(<poset>,<levelparam>) . . . . . . . . . remove level in poset
##
## The following method applies to a level. It returns `fail' if no level
## with level parameter <levelparam> is in the poset. Otherwise the level
## is deleted and all classes within it are also deleted! `DeleteLevel'
## returns `true' if the level is successfully deleted.
##
InstallOtherMethod( DeleteLevel,
"for a graphic poset, and an object",
true,
[ IsGraphicPosetRep, IsObject ],
0,
function( poset, levelparam )
local lp, noerror, cl, v, l, lev, store;
lp := Position(poset!.levelparams,levelparam);
if lp = fail then
return fail;
fi;
# delete all vertices:
noerror := true;
store := GGDeleteModifiesMenu;
GGDeleteModifiesMenu := false;
for cl in poset!.levels[lp]!.classes do
while cl <> [] do
if Delete(poset,cl[1]) = fail then
noerror := fail;
fi;
od;
od;
GGDeleteModifiesMenu := store;
l := Length(poset!.levels);
# now we have to move all lower levels up:
FastUpdate(poset,true);
for lev in [lp+1..l] do
poset!.levels[lev]!.top := poset!.levels[lev]!.top
- poset!.levels[lp]!.height;
for cl in poset!.levels[lev]!.classes do
for v in cl do
Move(poset,v,v!.x,v!.y);
od;
od;
if IsAlive(poset!.levelboxes[lev]) then
MoveDelta(poset!.levelboxes[lev],0,-poset!.levels[lp]!.height);
fi;
if IsAlive(poset!.lptexts[lev]) then
MoveDelta(poset!.lptexts[lev],0,-poset!.levels[lp]!.height);
fi;
od;
FastUpdate(poset,false);
poset!.levels{[lp..l-1]} := poset!.levels{[lp+1..l]};
Unbind(poset!.levels[l]);
poset!.levelparams{[lp..l-1]} := poset!.levelparams{[lp+1..l]};
Unbind(poset!.levelparams[l]);
if IsAlive(poset!.levelboxes[lp]) then
Delete(poset,poset!.levelboxes[lp]);
fi;
poset!.levelboxes{[lp..l-1]} := poset!.levelboxes{[lp+1..l]};
Unbind(poset!.levelboxes[l]);
if IsAlive(poset!.lptexts[lp]) then
Delete(poset,poset!.lptexts[lp]);
fi;
poset!.lptexts{[lp..l-1]} := poset!.lptexts{[lp+1..l]};
Unbind(poset!.lptexts[l]);
# think about the menus:
if GGDeleteModifiesMenu then
ModifyEnabled(poset,1,Length(poset!.menus));
fi;
return noerror;
end);
#############################################################################
##
## Modification methods:
##
#############################################################################
#############################################################################
##
#M ResizeLevel(<poset>,<levelparam>,<height>) . . . change height of level
##
## Changes the height of a level. The y coordinate can only be changed by
## permuting levels, see below.
## Attention: can increase the size of the sheet!
## Returns fail if no level with parameter levelparam exists and true
## otherwise.
##
InstallOtherMethod( ResizeLevel,
"for a graphic poset, an object, and an integer",
true,
[ IsGraphicPosetRep, IsObject, IsInt ],
0,
function( poset, levelparam, height )
local lp, l, cl, v, dist, len;
lp := Position(poset!.levelparams,levelparam);
if lp = fail then
return fail;
fi;
l := poset!.levels[lp];
if height < VERTEX.diameter then
height := VERTEX.diameter;
fi;
if height = l!.height then
return true;
elif height < l!.height then
# move all vertices within level into the new range
FastUpdate(poset,true);
for cl in l!.classes do
for v in cl do
if v!.y > height-VERTEX.radius then
v!.y := height-VERTEX.radius;
Move(v!.obj,v!.x,v!.y + l!.top);
fi;
od;
od;
# now move all lower levels up:
dist := height - l!.height;
l!.height := height;
# move level box and text:
if poset!.showlevels then
Move(poset!.levelboxes[lp],0,l!.top + l!.height - 8);
fi;
if poset!.showlevelparams then
Move(poset!.lptexts[lp],poset!.lptexts[lp]!.x,
l!.top + QuoInt(l!.height,2));
fi;
FastUpdate(poset,false);
else # height > l!.height
dist := height - l!.height;
l!.height := height;
# do we have to increase height of sheet?
len := Length(poset!.levels);
if poset!.levels[len]!.top + poset!.levels[len]!.height + dist
> poset!.height then
Resize(poset,poset!.width,
poset!.levels[len]!.top + poset!.levels[len]!.height + dist);
fi;
if poset!.showlevels then
Move(poset!.levelboxes[lp],0,l!.top + l!.height - 8);
fi;
if poset!.showlevelparams then
Move(poset!.lptexts[lp],poset!.lptexts[lp]!.x,
l!.top + QuoInt(l!.height,2));
fi;
# next move down all the levels below the increased level:
fi;
FastUpdate(poset,true);
for l in [lp+1..Length(poset!.levels)] do
poset!.levels[l]!.top := poset!.levels[l]!.top + dist;
for cl in poset!.levels[l]!.classes do
for v in cl do
MoveDelta(v!.obj,0,dist);
od;
od;
# move level box:
if poset!.showlevels then
MoveDelta(poset!.levelboxes[l],0,dist);
fi;
if poset!.showlevelparams then
MoveDelta(poset!.lptexts[l],0,dist);
fi;
od;
FastUpdate(poset,false);
end);
#############################################################################
##
#M MoveLevel(<poset>,<levelparam>,<position>) move level to another position
##
## Moves a level to another position. <position> is an absolute index in
## the list of levels. The level with parameter <levelparam> will be at the
## position <position> after the operation. This is only allowed if the
## new ordering is compatible with the partial order given by CompareLevels
## and if there is no connection of a vertex in the moving level with
## another level with which it is interchanged.
## So <levelparam> is compared with all levelparams between the old and
## the new position. If there is a contradiction nothing happens and the
## method returns fail. If everything works the operation returns true.
## This operation already exists in {\XGAP} for graphic objects.
##
InstallOtherMethod( MoveLevel,
"for a graphic poset, an object, and an integer",
true,
[ IsGraphicPosetRep, IsObject, IsInt ],
0,
function( poset, levelparam, position )
local lp, i, compare, cl, v, v2, p, list;
# nonsense position?
if position < 1 or position > Length(poset!.levels) then
return fail;
fi;
# does level exist?
lp := Position(poset!.levelparams,levelparam);
if lp = fail then
return fail;
fi;
# nothing to do?
if position = lp then
return true; # we are done
fi;
if position < lp then # move level UP
# check with partial ordering:
for i in [position..lp-1] do
compare := CompareLevels(poset,poset!.levelparams[i],levelparam);
if compare <> fail and compare < 0 then
# that would contradict the partial order
return fail;
fi;
od;
# now check vertices:
for cl in poset!.levels[lp]!.classes do
for v in cl do
for v2 in v!.maximalin do
p := Position(poset!.levelparams,v2!.levelparam);
if p >= position then # < lp is a MUST!
return fail;
fi;
od;
od;
od;
# OK, we can do it:
FastUpdate(poset,true);
list := Concatenation([lp],[position..lp-1]);
poset!.levels{[position..lp]} := poset!.levels{list};
poset!.levelparams{[position..lp]} := poset!.levelparams{list};
poset!.levelboxes{[position..lp]} := poset!.levelboxes{list};
poset!.lptexts{[position..lp]} := poset!.lptexts{list};
poset!.levels[position]!.top := poset!.levels[position+1]!.top;
if poset!.showlevels then
Move(poset!.levelboxes[position],0,poset!.levels[position]!.top
+ poset!.levels[position]!.height - 8);
fi;
if poset!.showlevelparams then
Move(poset!.lptexts[position],poset!.lptexts[position]!.x,
poset!.levels[position]!.top +
QuoInt(poset!.levels[position]!.height,2));
fi;
for cl in poset!.levels[position]!.classes do
for v in cl do
Move(poset,v,v!.x,v!.y);
od;
od;
for i in [position+1..lp] do
poset!.levels[i]!.top := poset!.levels[i]!.top
+ poset!.levels[position]!.height;
if poset!.showlevels then
Move(poset!.levelboxes[i],0,poset!.levels[i]!.top
+ poset!.levels[i]!.height - 8);
fi;
if poset!.showlevelparams then
Move(poset!.lptexts[i],poset!.lptexts[i]!.x,
poset!.levels[i]!.top + QuoInt(poset!.levels[i]!.height,2));
fi;
for cl in poset!.levels[i]!.classes do
for v in cl do
Move(poset,v,v!.x,v!.y);
od;
od;
od;
# in case another one has overwritten our box:
if poset!.showlevels then
Draw(poset!.levelboxes[position]);
fi;
if poset!.showlevelparams then
Draw(poset!.lptexts[position]);
fi;
FastUpdate(poset,false);
# we did it.
else # position > lp, move level DOWN
# check with partial ordering:
for i in [lp+1..position] do
compare := CompareLevels(poset,poset!.levelparams[i],levelparam);
if compare <> fail and compare > 0 then
# that would contradict the partial order
return fail;
fi;
od;
# now check vertices:
for cl in poset!.levels[lp]!.classes do
for v in cl do
for v2 in v!.maximals do
p := Position(poset!.levelparams,v2!.levelparam);
if p <= position then # > lp is a MUST!
return fail;
fi;
od;
od;
od;
# OK, we can do it:
FastUpdate(poset,true);
list := Concatenation([lp+1..position],[lp]);
poset!.levels{[lp..position]} := poset!.levels{list};
poset!.levelparams{[lp..position]} := poset!.levelparams{list};
poset!.levelboxes{[lp..position]} := poset!.levelboxes{list};
poset!.lptexts{[lp..position]} := poset!.lptexts{list};
poset!.levels[position]!.top := poset!.levels[position-1]!.top
- poset!.levels[position]!.height
+ poset!.levels[position-1]!.height;
if poset!.showlevels then
Move(poset!.levelboxes[position],0,poset!.levels[position]!.top
+ poset!.levels[position]!.height - 8);
fi;
if poset!.showlevelparams then
Move(poset!.lptexts[position],poset!.lptexts[position]!.x,
poset!.levels[position]!.top +
QuoInt(poset!.levels[position]!.height,2));
fi;
for cl in poset!.levels[position]!.classes do
for v in cl do
Move(poset,v,v!.x,v!.y);
od;
od;
for i in [lp..position-1] do
poset!.levels[i]!.top := poset!.levels[i]!.top
- poset!.levels[position]!.height;
if poset!.showlevels then
Move(poset!.levelboxes[i],0,poset!.levels[i]!.top
+ poset!.levels[i]!.height - 8);
fi;
if poset!.showlevelparams then
Move(poset!.lptexts[i],poset!.lptexts[i]!.x,
poset!.levels[i]!.top + QuoInt(poset!.levels[i]!.height,2));
fi;
for cl in poset!.levels[i]!.classes do
for v in cl do
Move(poset,v,v!.x,v!.y);
od;
od;
od;
# in case another one has overwritten our box:
if poset!.showlevels then
Draw(poset!.levelboxes[position]);
fi;
if poset!.showlevelparams then
Draw(poset!.lptexts[position]);
fi;
FastUpdate(poset,false);
# we did it.
fi;
return true;
end);
#############################################################################
##
#M Relabel(<graph>,<vertex>,<label>) . . . . . . . . change label of vertex
#M Relabel(<graph>,<vertex>) . . . . . . . . . . . . change label of vertex
#M Relabel(<poset>,<vertex1>,<vertex2>,<label>) . . . . change label of edge
#M Relabel(<poset>,<vertex1>,<vertex2>) . . . . . . . . change label of edge
##
## Changes the label of the vertex <vertex> or the edge between <vertex1>
## and <vertex2>. This must be a short string. In the method where no
## label is specified the new label is chosen functionally: the operation
## `ChooseLabel' is called. `Relabel' returns `fail' if an error occurs
## and `true' otherwise. This operations already exists in {\XGAP} for
## graphic objects.
##
InstallOtherMethod( Relabel,
"for a graphic graph, a vertex, and a string",
true,
[ IsGraphicGraphRep, IsGGVertex, IsString ],
0,
function( graph, vertex, label )
if label = "" then
label := false;
fi;
# we just call the low level routines:
vertex!.label := label;
Relabel(vertex!.obj,label);
end);
InstallOtherMethod( Relabel,
"for a graphic graph, and a vertex",
true,
[ IsGraphicGraphRep, IsGGVertex ],
0,
function( graph, vertex)
local label;
label := ChooseLabel( graph, vertex!.data );
if label = "" then
label := false;
fi;
# we just call the low level routines:
vertex!.label := label;
Relabel(vertex!.obj,label);
end);
InstallOtherMethod( Relabel,
"for a graphic poset, two vertices, and a string",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsString ],
0,
function( poset, v1, v2, label )
local p;
p := Position(v1!.maximals,v2);
if p = fail then
p := Position(v2!.maximals,v1);
if p = fail then
return fail;
fi;
fi;
# we know now that there is a connection!
p := Position(v1!.obj!.connections,v2!.obj);
if label = "" then
label := false;
fi;
# now we just call the low level routines:
Relabel(v1!.obj!.connectingLines[p],label);
end);
InstallOtherMethod( Relabel,
"for a graphic poset, and two vertices",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex ],
0,
function( poset, v1, v2)
local label;
label := ChooseLabel( poset, v1!.data, v2!.data );
if label = "" then
label := false;
fi;
# we just call the low level routines:
Relabel(poset,v1,v2,label);
end);
#############################################################################
##
#M Move(<graph>,<vertex>,<x>,<y>) . . . . . . . . . . . . . . . move vertex
#M Move(<graph>,<vertex>) . . . . . . . . . . . . . . . . . . . move vertex
##
## Moves vertex <vertex>. For posets coordinates are relative to the level
## of the vertex. <vertex> must be a vertex object in <graph>. If no
## coordinates are specified the operation `ChoosePosition' is
## called. Returns `fail' if an error occurs and `true' otherwise. This
## operations already exists in {\XGAP} for graphic objects.
##
InstallOtherMethod( Move,
"for a graphic poset, a vertex, and two integers",
true,
[ IsGraphicPosetRep, IsGPVertex, IsInt, IsInt ],
0,
function( poset, vertex, x, y )
local l;
if x < VERTEX.radius then
x := VERTEX.radius;
elif x > poset!.width-VERTEX.radius then
x := poset!.width-VERTEX.radius;
fi;
l := Position(poset!.levelparams,vertex!.levelparam);
l := poset!.levels[l];
if y < VERTEX.radius then
y := VERTEX.radius;
elif y > l!.height-VERTEX.radius then
y := l!.height-VERTEX.radius;
fi;
vertex!.x := x;
vertex!.y := y;
Move(vertex!.obj,x,y+l!.top);
return true;
end);
InstallOtherMethod( Move,
"for a graphic poset, and a vertex",
true,
[ IsGraphicPosetRep, IsGPVertex ],
0,
function( poset, vertex )
local position;
position := ChoosePosition(poset, vertex!.data, vertex!.levelparam,
vertex!.classparam);
Move(poset,vertex,position[1],position[2]);
end);
#############################################################################
##
#M Reshape(<graph>,<vertex>,<shape>) . . . . . . . . change shape of vertex
#M Reshape(<graph>,<vertex>) . . . . . . . . . . . . change shape of vertex
##
## Changes the shape of the vertex <vertex>. <vertex> must be a vertex
## object in the graph or poset <graph>. For the method where no shape is
## specified the new shape is chosen functionally: `ChooseShape` is called
## for the corresponding data. `Reshape' returns `fail' if an error
## occurs and `true' otherwise. This operations already exists in {\XGAP}
## for graphic objects.
##
InstallOtherMethod( Reshape,
"for a graphic graph, a vertex, and a string",
true,
[ IsGraphicGraphRep, IsGGVertex, IsString ],
0,
function( graph, vertex, shape )
if shape = "circle" then
Reshape(vertex!.obj,VERTEX.circle);
elif shape = "diamond" then
Reshape(vertex!.obj,VERTEX.diamond);
else
Reshape(vertex!.obj,VERTEX.rectangle);
fi;
return true;
end);
InstallOtherMethod( Reshape,
"for a graphic graph, and a vertex",
true,
[ IsGraphicGraphRep, IsGGVertex ],
0,
function( graph, vertex )
local shape;
shape := ChooseShape( graph, vertex!.data );
Reshape(graph, vertex, shape);
return true;
end);
#############################################################################
##
#M Recolor(<graph>,<vertex>,<color>) . . . . . . . . change color of vertex
#M Recolor(<graph>,<vertex>) . . . . . . . . . . . . change color of vertex
#M Recolor(<poset>,<vertex1>,<vertex2>,<color>) . . change color of an edge
#M Recolor(<poset>,<vertex1>,<vertex2>) . . . . . . change color of an edge
##
## Changes the color of the vertex <vertex> or the edge between <vertex1>
## and <vertex2>. <vertex> must be a vertex object in <graph>. For the
## method where no color is specified the new color is chosen
## functionally: `ChooseColor' is called for the corresponding
## data. `Recolor' returns `fail' if an error occurs and `true'
## otherwise. This operation already exists in {\XGAP} for graphic objects.
##
InstallOtherMethod( Recolor,
"for a graphic graph, a vertex, and a color",
true,
[ IsGraphicGraphRep, IsGGVertex, IsColor ],
0,
function( graph, vertex, color )
Recolor(vertex!.obj,color);
return true;
end);
InstallOtherMethod( Recolor,
"for a graphic graph, and a vertex",
true,
[ IsGraphicGraphRep, IsGGVertex ],
0,
function( graph, vertex )
local color;
color := ChooseColor( graph, vertex!.data );
Recolor(graph, vertex, color);
return true;
end);
InstallOtherMethod( Recolor,
"for a graphic poset, two vertices, and a color",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsColor ],
0,
function( poset, vertex1, vertex2, color )
local p;
p := Position(vertex1!.maximals,vertex2);
if p = fail then
p := Position(vertex2!.maximals,vertex1);
if p = fail then
return fail;
fi;
fi;
# we know now that there is a connection!
p := Position(vertex1!.obj!.connections,vertex2!.obj);
Recolor(vertex1!.obj!.connectingLines[p],color);
return true;
end);
InstallOtherMethod( Recolor,
"for a graphic poset, and two vertices",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex ],
0,
function( poset, vertex1, vertex2 )
local color;
color := ChooseColor( poset, vertex1!.data, vertex2!.data );
return Recolor(poset, vertex1, vertex2, color);
end);
#############################################################################
##
#M SetWidth(<graph>,<vertex1>,<vertex2>,<width>) . change line width of edge
#M SetWidth(<graph>,<vertex1>,<vertex2>) . . . . . change line width of edge
##
## Changes the line width of an edge. <vertex1> and <vertex2> must be
## vertices in the graph <graph>. For the method where no line width is
## specified the width is chosen functionally: `ChooseWidth' is called for
## the corresponding data pair. Returns `fail' if an error occurs and
## `true' otherwise. This operation already exists in {\XGAP} for graphic
## objects.
##
InstallOtherMethod( SetWidth,
"for a graphic poset, two vertices, and an integer",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsInt ],
0,
function( poset, vertex1, vertex2, width )
local p;
p := Position(vertex1!.maximals,vertex2);
if p = fail then
p := Position(vertex2!.maximals,vertex1);
if p = fail then
return fail;
fi;
fi;
# we know now that there is a connection!
p := Position(vertex1!.obj!.connections,vertex2!.obj);
SetWidth(vertex1!.obj!.connectingLines[p],width);
return true;
end);
InstallOtherMethod( SetWidth,
"for a graphic poset, and two vertices",
true,
[ IsGraphicPosetRep, IsGPVertex, IsGPVertex ],
0,
function( poset, vertex1, vertex2 )
local width;
width := ChooseWidth( poset, vertex1!.data, vertex2!.data );
return SetWidth(poset, vertex1, vertex2, width);
end);
#############################################################################
##
#M Highlight(<graph>,<vertex>) . . . . . . . change highlighting of vertex
#M Highlight(<graph>,<vertex>,<flag>) . . . . change highlighting of vertex
##
## Changes the highlighting status of the vertex <vertex>. <vertex> must
## be a vertex object in <graph>. For the method where no flag is
## specified the new status is chosen functionally: `ChooseHighlight' is
## called for the corresponding data. Returns `fail' if an error occurs
## and `true' otherwise. This operation already exists in {\XGAP} for
## graphic objects.
##
InstallOtherMethod( Highlight,
"for a graphic graph, a vertex, and a flag",
true,
[ IsGraphicGraphRep, IsGGVertex, IsBool ],
0,
function( graph, vertex, flag )
Highlight(vertex!.obj,flag);
return true;
end);
InstallOtherMethod( Highlight,
"for a graphic graph, and a vertex",
true,
[ IsGraphicGraphRep, IsGGVertex ],
0,
function( graph, vertex )
local flag;
flag := ChooseHighlight( graph, vertex!.data );
Highlight(graph, vertex, flag);
return true;
end);
#############################################################################
##
## Set this variable temporarily to false if you change many selections!
##
GGSelectModifiesMenu := true;
#############################################################################
##
#M Select(<graph>,<vertex>,<flag>) . . . . . . . . . . (de-)selects a vertex
#M Select(<graph>,<vertex>) . . . . . . . . . . . . . . . selects a vertex
##
## Changes the selection state of the vertex <vertex>. <vertex> must be a
## vertex object in <graph>. The flag determines whether the vertex
## should be selected or deselected. This operation already exists in
## {\XGAP} for graphic objects. The method without flags assumes `true'.
##
InstallOtherMethod( Select,
"for a graphic graph, a vertex, and a flag",
true,
[ IsGraphicGraphRep, IsGGVertex, IsBool ],
0,
function(graph,vertex,flag)
local p, l;
p := PositionSet(graph!.selectedvertices,vertex);
if flag then
if p <> fail then
return;
fi;
Highlight(graph,vertex,true);
Recolor(graph,vertex,graph!.color.selected);
AddSet(graph!.selectedvertices,vertex);
else
if p = fail then
return;
fi;
Highlight(graph,vertex,false);
Recolor(graph,vertex,graph!.color.unselected);
RemoveSet(graph!.selectedvertices,vertex);
fi;
if GGSelectModifiesMenu then
ModifyEnabled(graph,1,Length(graph!.menus));
fi;
return;
end);
InstallOtherMethod( Select,
"for a graphic graph, and a vertex",
true,
[ IsGraphicGraphRep, IsGGVertex ],
0,
function(graph,vertex)
Select(graph,vertex,true);
end);
#############################################################################
##
#M DeselectAll(<graph>) . . . . . . . . . . . . . . . deselects all vertices
##
## Deselects all vertices in graph.
##
InstallOtherMethod( DeselectAll,
"for a graphic graph",
true,
[ IsGraphicGraphRep ],
0,
function(graph)
local v;
for v in graph!.selectedvertices do
Highlight(graph,v,false);
Recolor(graph,v,graph!.color.unselected);
od;
graph!.selectedvertices := [];
end);
#############################################################################
##
#M Selected(<graph>) . . . . . . . . . returns set of all selected vertices
##
## Returns a (shallow-)copy of the set of all selected vertices.
##
InstallOtherMethod( Selected,
"for a graphic graph",
true,
[ IsGraphicGraphRep ],
0,
function(graph)
return ShallowCopy(graph!.selectedvertices);
end);
#############################################################################
##
## Methods for functional decisions:
##
#############################################################################
#############################################################################
##
#M CompareLevels(<poset>,<levelp1>,<levelp2>) . . . compares two levelparams
##
## Compare two levelparams. -1 means that levelp1 is "higher", 1 means
## that levelp2 is "higher", 0 means that they are equal. fail means that
## they are not comparable. This method is for the case if level
## parameters are integers and lower values mean higher levels like in the
## case of group lattices and subgroup indices.
##
InstallMethod( CompareLevels,
"for a graphic poset, and two integers",
true,
[ IsGraphicPosetRep, IsInt, IsInt ],
0,
function( poset, l1, l2 )
if l1 < l2 then
return -1;
elif l1 > l2 then
return 1;
else
return 0;
fi;
end);
#############################################################################
##
#M ChooseLabel(<graph>,<data>) . . . . . . . is called while vertex creation
#M ChooseLabel(<graph>,<data>,<data>) . . . . is called while edge creation
##
## This operation is called while vertex or edge creation, if the caller
## didn't specify a label for the vertex or edge. It has to return a short
## string which will be attached to the vertex. If it returns fail the new
## vertex is not generated! This method just returns the empty string, so
## no label is generated.
## This method is also called in the Relabel method without label parameter.
##
InstallMethod( ChooseLabel,
"for a graphic graph, and an object",
true,
[ IsGraphicGraphRep, IsObject ],
0,
function( graph, data )
return "";
end);
InstallOtherMethod( ChooseLabel,
"for a graphic graph, and two objects",
true,
[ IsGraphicGraphRep, IsObject, IsObject ],
0,
function( poset, data1, data2 )
return "";
end);
#############################################################################
##
#M ChooseLevel(<poset>,<data>) . . . . . . . is called while vertex creation
##
## This operation is called while vertex creation, if the caller didn't
## specify a level where the vertex belongs to. It has to return a
## levelparam which exists in the poset. If it returns fail the new vertex
## is not generated!
## This method just chooses the last, lowest level or fail, if there is no
## level in the poset.
##
InstallMethod( ChooseLevel,
"for a graphic poset, and an object",
true,
[ IsGraphicPosetRep, IsObject ],
0,
function( poset, data )
local l;
l := Length(poset!.levelparams);
if l > 0 then
return poset!.levelparams[Length(poset!.levelparams)];
else
return fail;
fi;
end);
#############################################################################
##
#M ChooseClass(<poset>,<data>,<levelp>) . . is called while vertex creation
##
## This operation is called while vertex creation, if the caller didn't
## specify a class where the vertex belongs to. It has to return a
## classparam which exists in the poset in levelp. If it returns fail the
## new vertex is not generated!
## This method just generates a new class in the level with classparam one
## bigger than the maximum of all (integer) classparams. It returns fail if
## this maximum is no integer.
##
InstallMethod( ChooseClass,
"for a graphic graph, and two objects",
true,
[ IsGraphicPosetRep, IsObject, IsObject ],
0,
function( poset, data, levelparam )
local l,m;
l := Position(poset!.levelparams,levelparam);
if l = fail then
return fail;
fi;
l := poset!.levels[l];
if l!.classparams = [] then
return CreateClass(poset,levelparam,1);
fi;
m := Maximum(l!.classparams);
if not IsInt(m) then
return fail;
fi;
return CreateClass(poset,levelparam,m+1);
end);
#############################################################################
##
#M ChooseShape(<graph>,<data>) . . . . . . . is called while vertex creation
##
## This operation is called while vertex creation.
## It has to return a string out of the following list:
## "circle", "diamond", "rectangle"
## If it returns fail the new vertex is not generated!
## This method just returns "circle".
##
InstallMethod( ChooseShape,
"for a graphic graph, and an object",
true,
[ IsGraphicGraphRep, IsObject ],
0,
function( graph, data )
return "circle";
end);
#############################################################################
##
#M ChooseWidth(<graph>,<data>) . . . . . . . is called while vertex creation
#M ChooseWidth(<graph>,<data1>,<data2>) . . . is called while edge creation
##
## This operation is called while vertex or edge creation.
## It has to return a line width.
## If it returns fail the new vertex or edge is not generated!
## This is also called by the SetWidth operation without width parameter.
## This method just returns 1.
##
InstallOtherMethod( ChooseWidth,
"for a graphic graph, and an object",
true,
[ IsGraphicGraphRep, IsObject ],
0,
function( graph, data )
return 1;
end);
InstallOtherMethod( ChooseWidth,
"for a graphic graph, and two objects",
true,
[ IsGraphicGraphRep, IsObject, IsObject ],
0,
function( graph, data1, data2 )
return 1;
end);
#############################################################################
##
#M ChooseColor(<graph>,<data>) . . . . . . . is called while vertex creation
#M ChooseColor(<graph>,<data1>,<data2>). . . . is called while edge creation
##
## This operation is called while vertex or edge creation. It has to return a
## color. If it returns fail the new vertex is not generated!
## It is also called in the Recolor method without color parameter.
## This method just returns black.
##
InstallMethod( ChooseColor,
"for a graphic graph, and an object",
true,
[ IsGraphicGraphRep, IsObject ],
0,
function( graph, data )
return COLORS.black;
end);
InstallOtherMethod( ChooseColor,
"for a graphic graph, and two objects",
true,
[ IsGraphicGraphRep, IsObject, IsObject ],
0,
function( graph, data1, data2 )
return COLORS.black;
end);
#############################################################################
##
#M ChooseHighlight(<graph>,<data>) . . . . . is called while vertex creation
##
## This operation is called while vertex creation. It has to return a
## flag which indicates, whether the vertex is highlighted or not. If it
## returns fail the new vertex is not generated!
## It is also called in the Highlight method without flag parameter.
##
## The following method just returns false.
InstallMethod( ChooseHighlight,
"for a graphic graph, and an object",
true,
[ IsGraphicGraphRep, IsObject ],
0,
function( graph, data )
return false;
end);
#############################################################################
##
#M ChoosePosition(<poset>,<data>,<level>,<class>) . . . . . . . . . . . . .
#M ChoosePosition(<graph>,<data>) . . . . . is called while vertex creation
##
## This operation is called while vertex creation. It has to return a
## list with two integers: the coordinates. For posets those are relative
## to the level the vertex resides in. If it returns fail the new vertex
## is not generated!
## This method positions a new vertex in a nonempty class next to the last
## member in the class and a new vertex in a new class halfway to the
## right end of the sheet from the rightmost vertex in the level or
## halfway to the left end of the sheet from the leftmost vertex in the
## class, depending where there is more space.
##
InstallMethod( ChoosePosition,
"for a graphic poset, an object, a level object, a list, and a list",
true,
[ IsGraphicPosetRep, IsObject, IsGPLevel, IsList, IsList ],
0,
function( poset, data, level, class, hints )
local position, ranges, cl, gaps, maxindex, i;
position := [];
# not first in class:
if class <> [] then
# just near the others in the class:
position[2] := class[Length(class)]!.y;
position[1] := class[Length(class)]!.x + VERTEX.diameter + 2;
else
# collect all x ranges where classes reside:
ranges := [[0,0]];
for cl in level!.classes do
if cl <> [] then
Add(ranges,[cl[1]!.x-VERTEX.radius,cl[Length(cl)]!.x+VERTEX.radius]);
fi;
od;
Add(ranges,[poset!.width,poset!.width]);
ranges := Set(ranges);
gaps := List([1..Length(ranges)-1],x->ranges[x+1][1]-ranges[x][2]);
# search largest gap:
maxindex := 1;
for i in [2..Length(gaps)] do
if gaps[i] > gaps[maxindex] then
maxindex := i;
fi;
od;
position[1] := QuoInt(ranges[maxindex][2]+ranges[maxindex+1][1],2);
position[2] := QuoInt(level!.height,2);
fi;
return position;
end);
#############################################################################
##
## Methods for getting information:
##
#############################################################################
#############################################################################
##
--> --------------------
--> maximum size reached
--> --------------------
[ zur Elbe Produktseite wechseln0.163Quellennavigators
]
|
2026-03-28
|