GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#############################################################################
##
#W FundamentalDomainBieberbach.gi HAPcryst package Marc Roeder
##
##
##
#H @(#)$Id: FundamentalDomainBieberbach.gi, v 0.1.11 2013/10/27 18:31:09 gap Exp $
##
#Y Copyright (C) 2006 Marc Roeder
#Y
#Y This program is free software; you can redistribute it and/or
#Y modify it under the terms of the GNU General Public License
#Y as published by the Free Software Foundation; either version 2
#Y of the License, or (at your option) any later version.
#Y
#Y This program is distributed in the hope that it will be useful,
#Y but WITHOUT ANY WARRANTY; without even the implied warranty of
#Y MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#Y GNU General Public License for more details.
#Y
#Y You should have received a copy of the GNU General Public License
#Y along with this program; if not, write to the Free Software
#Y Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
##
Revision.("FundamentalDomainBieberbach_gi"):=
"@(#)$Id: FundamentalDomainBieberbach.gi, v 0.1.11 2013/10/27 18:31:09 gap Exp $";
#############################################################################
##
#O FundamentalDomainBieberbachGroupNC(<group>)
##
InstallMethod(FundamentalDomainBieberbachGroupNC,
[IsGroup],
function(group)
local center;
center:=0*[1..Size(Representative(group))-1];
return FundamentalDomainBieberbachGroupNC(center,group);
end);
#############################################################################
##
#O FundamentalDomainBieberbachGroup(<group>)
##
InstallMethod(FundamentalDomainBieberbachGroup,
[IsGroup],
function(group)
local center;
center:=0*[1..Size(Representative(group))-1];
return FundamentalDomainBieberbachGroup(center,group);
end);
#############################################################################
##
#O FundamentalDomainBieberbachGroupNC(<center>, <group>)
##
InstallMethod(FundamentalDomainBieberbachGroupNC,
[IsVector,IsGroup],
function(center,group)
local gram;
gram:=GramianOfAverageScalarProductFromFiniteMatrixGroup(PointGroup(group));
return FundamentalDomainBieberbachGroupNC(center,group,gram);
end);
#############################################################################
##
#O FundamentalDomainBieberbachGroup(<center>, <group>)
##
InstallMethod(FundamentalDomainBieberbachGroup,
[IsVector,IsGroup],
function(center,group)
local gram;
gram:=GramianOfAverageScalarProductFromFiniteMatrixGroup(PointGroup(group));
return FundamentalDomainBieberbachGroup(center,group,gram);
end);
#############################################################################
##
#O FundamentalDomainBieberbachGroup(<center>, <group>, <gram>)
##
InstallMethod(FundamentalDomainBieberbachGroup,
[IsVector,IsGroup,IsMatrix],
function(center,group,gram)
local needBieberbachTest, phi, dim, fd;
needBieberbachTest:=false;
if not (IsStandardSpaceGroup(group) and IsAffineCrystGroupOnRight(group))
then
Error("group must be a StandardSpaceGroup acting on right");
else
phi:=IsomorphismPcpGroup(group);
if phi=fail
then
Info(InfoHAPcryst,1,"Couldn't calculate pcp representation. Testing tortion freeness later");
needBieberbachTest:=true;
elif not IsAlmostBieberbachGroup(Image(phi))
then
Error("group must be a Bieberbach group");
fi;
fi;
dim:=Size(center);
if not (dim=Size(gram) and DimensionOfMatrixGroup(group)=dim+1)
then
Error("dimensions don't match");
fi;
if not IsTrivial(StabilizerOnSetsStandardSpaceGroup(group,[center]))
then
Error("group must be a Bieberbach group");
fi;
fd:=FundamentalDomainBieberbachGroupNC(center,group,gram);
if not needBieberbachTest or IsFundamentalDomainBieberbachGroup(fd,group)
then
return fd;
else
Error("group must be a Bieberbach group");
fi;
end);
#############################################################################
##
#O FundamentalDomainBieberbachGroupNC(<center>, <group>, <gram>)
##
InstallMethod(FundamentalDomainBieberbachGroupNC,
[IsVector,IsGroup,IsMatrix],
function(center,group,gram)
local initialInequalities, satisfiesAllInequalities,
newInequalitiesEuclidean, newInequalities, shuffledList,
dim, fdVol, ineqThreshold, isEuclidean, orbitpart,
partialFD, newinequalities, oldinequalities,
donevertices, allvertices, vertices, box, i, ilist,
inequalities, v, new;
###################
## A lot of helper functions:
###################
# This calculates the inequalities for the unit box around
initialInequalities:=function(center,gram)
local dim, directions, points, ineqs;
dim:=Size(center);
directions:=Union(IdentityMat(dim),-IdentityMat(dim));
points:=[];
points:=center+directions;
#points:=Set(ShiftedOrbitPart(center,orbitpart));
#UniteSet(points,center+directions);
# UniteSet(points,Union(List(directions,d->d+points)));
if gram<>IdentityMat(dim)
then
ineqs:=Set(points,
i->BisectorInequalityFromPointPair(center,i,gram));
else
ineqs:=Set(points,
i->BisectorInequalityFromPointPair(center,i));
fi;
RemoveSet(ineqs,fail);
return ineqs;
end;
satisfiesAllInequalities:=function(point,ineqs)
return ForAll(ineqs,i->WhichSideOfHyperplaneNC(point,i) in [0,1]);
end;
newInequalitiesEuclidean:=function(vertex,center,ineqs,vertices,box,group)
local dim, affinevertex, returnlist, g,
affimage, image, trans, t, gl, gli, gt;
dim:=Size(vertex);
affinevertex:=Concatenation(vertex,[1]);
returnlist:=[];
for g in PointGroupRepresentatives(group)
do
gl:=LinearPartOfAffineMatOnRight(g);
gli:=Inverse(gl);
gt:=g[dim+1]{[1..dim]};
affimage:=affinevertex*g;
image:=affimage{[1..dim]};
###
trans:=TranslationsToBox(image,box);
for t in trans
do
if not image+t in vertices
then
if satisfiesAllInequalities(image+t,ineqs)
then
Add(returnlist,center*gl+gt+t);
Add(returnlist,(center-gt-t)*gli);
fi;
fi;
od;
od;
if returnlist=[]
then
return [];
fi;
returnlist:=Set(returnlist);
RemoveSet(returnlist,center);
returnlist:=Set(returnlist,i->BisectorInequalityFromPointPair(center,i));
SubtractSet(returnlist,ineqs);
return Filtered(returnlist,i->ForAny(vertices,v->WhichSideOfHyperplaneNC(v,i)=-1));
end;
newInequalities:=function(vertex,center,ineqs,vertices,box,group,gram)
local dim, affinevertex, returnlist, g, gl, gli, gt,
affimage, image, trans, t;
dim:=Size(vertex);
affinevertex:=Concatenation(vertex,[1]);
returnlist:=[];
for g in PointGroupRepresentatives(group)
do
gl:=LinearPartOfAffineMatOnRight(g);
gli:=Inverse(gl);
gt:=g[dim+1]{[1..dim]};
affimage:=affinevertex*g;
image:=affimage{[1..dim]};
###
trans:=TranslationsToBox(image,box);
for t in trans
do
if not image+t in vertices
then
if satisfiesAllInequalities(image+t,ineqs)
then
Add(returnlist,center*gl+gt+t);
Add(returnlist,(center-gt-t)*gli);
fi;
fi;
od;
od;
if returnlist=[]
then
return [];
fi;
returnlist:=Set(returnlist);
RemoveSet(returnlist,center);
returnlist:=Set(returnlist,i->BisectorInequalityFromPointPair(center,i,gram));
SubtractSet(returnlist,ineqs);
return Filtered(returnlist,i->ForAny(vertices,v->WhichSideOfHyperplaneNC(v,i)=-1));
end;
shuffledList:=function(list)
local positionlist, indexlist, i, nextpos;
if Size(list)=1
then return list;
fi;
positionlist:=EmptyPlist(Size(list));
indexlist:=[1..Size(list)];
for i in [Size(list),Size(list)-1..1]
do
nextpos:=Random(1,i);
Add(positionlist,indexlist[nextpos]);
Remove(indexlist,nextpos);
od;
return list{positionlist};
end;
###################
## helper functions done. Let's go:
###################
dim:=Size(center);
## The volume of a fundamental domain is seemingly
## well-known:
#fdVol:=1/Order(PointGroup(group));
## This is only used in the first step.
## Polymake calculates a triangulation using the beneath-beyond
## algorithm for this.
## This seams to be inefficient in high dimensions, especially
## with complicated polyhedrae.
##
ineqThreshold:=ValueOption("ineqThreshold");
if ineqThreshold=fail
then
ineqThreshold:=200;
fi;
isEuclidean:=(gram=IdentityMat(dim));
orbitpart:=OrbitStabilizerInUnitCubeOnRight(group,center).orbit;;
newinequalities:=initialInequalities(center,gram);;
partialFD:=CreatePolymakeObject("partialFD",
POLYMAKE_DATA_DIR,
["polytope","2.3","RationalPolytope"]
);
AppendToPolymakeObject(partialFD,
ConvertMatrixToPolymakeString("FACETS",newinequalities)
);
# AppendInequalitiesToPolymakeObject(partialFD,newinequalities);
## slightly experimental: remove if this causes trouble:
Polymake(partialFD,"VERTICES FACETS");
newinequalities:=[];
oldinequalities:=[];
donevertices:=[];
allvertices:=[];
repeat
allvertices:=AsSet(Polymake(partialFD,"VERTICES"));
donevertices:=Set(donevertices);
vertices:=Difference(allvertices,donevertices);
##
box:=[1..dim];
for i in [1..dim]
do
ilist:=allvertices{[1..Size(allvertices)]}[i];
box[i]:=[Minimum(ilist),Maximum(ilist)];
od;
# Sort(donevertices);
# vertices:=(Filtered(Polymake(partialFD,"VERTICES"),v->not v in donevertices));
# vertices:=Difference(allvertices,donevertices);
if vertices=[]
then
Info(InfoHAPcryst,2,"out of vertices");
return partialFD;
fi;
inequalities:=Set(Polymake(partialFD,"FACETS"));
Info(InfoHAPcryst,3,"v: ",Size(allvertices),"/",Size(vertices)," f:", Size(inequalities)," \c");
newinequalities:=[];
repeat
v:=Remove(vertices,Random(1,Size(vertices)));
# v:=Remove(vertices);
Add(donevertices,v);
if satisfiesAllInequalities(v,newinequalities)
then
if isEuclidean
then
new:= newInequalitiesEuclidean(v,center,inequalities,
allvertices,box,group);
else
new:= newInequalities(v,center,inequalities,
allvertices,box,group,gram);
fi;
UniteSet(inequalities,new);
Append(newinequalities,new);
fi;
until vertices=[] or Size(newinequalities)>ineqThreshold;
Info(InfoHAPcryst,3,"new: ",Size(newinequalities));
if newinequalities<>[]
then
ClearPolymakeObject(partialFD,["polytope","2.3","RationalPolytope"]);
# AppendInequalitiesToPolymakeObject(partialFD,shuffledList(inequalities));;
AppendInequalitiesToPolymakeObject(partialFD,inequalities);;
Polymake(partialFD,"VERTICES FACETS");
fi;
until newinequalities=[];
Info(InfoHAPcryst,2,"out of inequalities");
return partialFD;
end);