| Drawing |
Code |
|
These show three different tilings of the upper half plane with a
fundamental domain for Gamma0(2).
|
 |
 |
 |
|
G := GammaUpper0(2);
H< i,r> := UpperHalfPlaneWithCusps();
generators := Generators(G);
M := generators cat [g^(-1) : g in generators] cat [G!1];
tri1 := [H|Infinity(),r-1,0,r,r+1];
tri2 := [H|Infinity(),i-1,0,i+1];
tri3 := FundamentalDomain(G);
X := [1..#M];
L := [G!m : m in Set([Matrix(M[i]*M[j]*M[k]*M[l]*M[m]) :
i in X, j in X, k in X, l in X, m in X])];
DisplayPolygons([g*tri1 : g in L],"/tmp/pic1.ps": Show := true,
Size:=[-2,2,1.5,100]);
DisplayPolygons([g*tri2 : g in L],"/tmp/pic2.ps": Show := true,
Size:=[-2,2,1.5,100]);
DisplayPolygons([g*tri3 : g in L],"/tmp/pic3.ps": Show := true,
Size:=[-2,2,1.5,100]);
|
|
|
This picture gives some explanation of the previous tilings.
In this diagram, any choice of 6 triangles, one of each colour,
gives a fundamental domain for Gamma0(2). Different
ways of choosing these 6 triangles give the above different kinds
of tilings.
|
|
|
G := GammaUpper0(2);
H< i,r> := UpperHalfPlaneWithCusps();
generators := Generators(G);
M := generators cat [g^(-1) : g in generators] cat [G!1];
X := [1..#M];
L := [G!m : m in Set([Matrix(M[i]*M[j]*M[k]*M[l]*M[m]) :
i in X, j in X, k in X, l in X, m in X])];
C := CosetRepresentatives(GammaUpper0(2));
tri1:=[H|Infinity(),i,r];
tri2:=[H|0,i,r];
Pols1:=[g*c*tri1 : c in C, g in L];
Pols2:=[g*c*tri2 : c in C, g in L];
pols := Pols1 cat Pols2;
Colours := &cat[[[0.5,0.5,1],[1,0,0],[0,0.8,0]] : i in L];
Colours2 := &cat[[[0,0,1],[1,0.6,0.2],[0.5,1,0.5]] : i in L];
cols:=Colours cat Colours2;
DisplayPolygons(pols,"/tmp/picture1.ps": Show := true,Size:=[-2,2,1.5,150],
Colours:=cols,Outline:=false);
|
|
|
Fundamental domain for Gamma0(400) in terms of
domains for Gamma0(2), coloured according to at what stage
they are added to the picture.
|
|
|
frac := func<a | a[1]/a[2]>;
function FareyValue(m)
mat := Matrix(m);
Denominators := [mat[2,1],mat[2,2],mat[2,1]+mat[2,2]];
values := [Abs(v) : v in Denominators];
return &+ContinuedFraction(frac(Sort(values)));
end function;
procedure drawDomain(cosets)
H< i,r> := UpperHalfPlaneWithCusps();
tri := [H|Infinity(),0,r];
cols := [[0.08*FareyValue(c),1-0.08*FareyValue(c),1-0.2*FareyValue(c)]
: c in cosets];
trans := [g*tri : g in cosets];
DisplayPolygons(trans,"/tmp/pic.ps":
Outline := false, Colours := cols, Show := true, Size:=[0,1,1.5,450]);
end procedure;
C := CosetRepresentatives(Gamma0(400));
drawDomain(C);
|
|
|
To complete the modular curves defined by quotienting by congruence subgroups,
the cusps (rationals and infinity) are adjoined to the upper half plane.
The topology is defined in such a way that neighborhoods of cusps
include discs which touch the real line at the cusp, if the cusp is a
rational. For infinity, sets of points with Imaginary part greater than
some number give open sets about infinity. This picture shows some of
these discs, which are drawn just by taking images of a neighborhood of
infinity. The discs have a pattern in 3 colours, just to give a better
feeling for how the transformation works.
|
|
|
P:=PSL2(Integers());
function find_matrix(x)
if x eq 0
then return P![0,-1,1,0];
end if;
a:=Numerator(x);
c:=Denominator(x);
g,d,b:=Xgcd(a,c);
return P![a,-b,c,d];
end function;
fractions:=[0] cat [a/b : a,b in [1..6] | a le 2*b and Gcd(a,b) eq 1];
matrices:=[P!1] cat [find_matrix(x) : x in fractions];
area1:=[H!Infinity()]
cat [H | i - (1+1/4)^n : n in Reverse([-5..16])]
cat [H|i]
cat [H|i+(1+1/4)^n : n in [-5..16]];
area2:=[H!Infinity()]
cat [H | 5/4*i - (1+1/4)^n : n in Reverse([-5..16])]
cat [H|5/4*i]
cat [H|5/4*i+(1+1/4)^n : n in [-5..16]];
area3:=[H|Infinity(),i+1/2,i+5/4,i+3/2];
polys:=[g*p : g in matrices, p in [area1,area2,area3]];
yellow:=[1,1,0];
orange:=[1,0.5,0];
green:=[0.5,0.9,0.2];
brown:=[0.4,0,0];
colours:=[c : i in matrices, c in [yellow,orange,green]];
pencolours:=[c : i in matrices, c in [brown,orange,green]];
DisplayPolygons(polys ,"/tmp/pic.ps":
Show:=true,Size:=[0,2,1.5,200],
Colours:=colours,PenColours:=pencolours);
|
|
In the above examples, we've used a well known fundamental domain for
SL(2,Z) to draw fundamental domains for other groups.
Of course, there are infinitely many possible fundamental domains for
SL(2,Z). In this example, I've given code for creating more of them,
with some random parameters. We're still just using examples associated
to the choice of generators S=PSL(2,Z)![0,-1,1,0]; and
R:=Gamma0(1)![0,-1,1,-1]; so these examples
are still all very closely related.
The first picture shows one of these
domains for SL(2,Z).
The second shows a tiling of the upper half plane using images
of this domain, and random colouring.
|
 |
 |
|
Here is another choice of domain for SL(2,Z). The union of 6 copies
of this domain, in the second picture, is a domain for Gamma(2).
In the third picture, a tiling of the upper half plane is created by
translating these 6 triangles by elements of Gamma(2).
|
 |
 |
 |
|
WARNING: Not all regions created by the method on the right give
domains for SL(2,Z); you need to check that the edges of the polygon
formed by this code do not intersect each other, apart from at their
ends.
|
|
H< i,r>:=UpperHalfPlaneWithCusps();
S:=Gamma0(1)![0,-1,1,0];
R:=Gamma0(1)![0,-1,1,-1];
T:=Gamma0(1)![1,1,0,1];
function domain_for_SL()
edge1:=[H|Infinity()]
cat [H|((Random(1)+(8-r))/2)*i + (Random(2)-1)/2 : r in [1..5]]
cat [H|i];
edge2:=edge1;
edge2[7]:=H!r;
pol:=edge1 cat Reverse(S*edge1) cat (R*edge2) cat Reverse(edge2);
return pol;
end function;
// draw a domain found using the above function:
pol:=domain_for_SL();
size:=DisplayPolygons(pol,"/tmp/pic.ps":Show:=true);
// draw lots of translates of this domain, with random colours:
// lazy way to get a lot of matrices:
matrices:=
[T^j*g : g in CosetRepresentatives(CongruenceSubgroup(5)), j in [-1,0,1]]
cols:=[[Random(5)/5.0 : i in [1..3]] : g in matrices];
size:=DisplayPolygons([g*pol: g in matrices],"/tmp/pic.ps":
Show:=true,Colours:=cols,Size:=[-0.5,1.5,4,200]);
// draw another domain:
pol:=domain_for_SL();
size:=DisplayPolygons(pol,"/tmp/pic.ps":Show:=true);
// draw a nice fundamental domain for Gamma(2) in terms of this:
// define Gamma(2)
G2:=CongruenceSubgroup(2);
C2:=CosetRepresentatives(G2);
// we modify the list of coset representatives,
// to get an alternative list of representatives:
C3:=C2;
g:=Generators(G2)[1]^(-1)*T^(-2);
C3[3]:=g*C2[3];
// choose some nice colours!
yellow:=[1,0.8,0];
orange:=[1,0.5,0];
blue:=[0,0,1];
lightblue:=[0.4,0.4,1];
green:=[0.1,0.9,0.1];
darkgreen:=[0.1,0.7,0.1];
colours:=[blue,darkgreen,yellow,lightblue,orange,green];
DisplayPolygons([g*pol : g in C3],"/tmp/pic.ps":
Show:=true,Colours:=colours,Size:=[-0.5,2.5,4,200]);
// draw translates of the above domain for Gamma(2):
mats:=[G2!1,G2!(T^2)]
cat [(G2!(T^2)^j)*g^(i) : g in Generators(G2),
i in [-2,-1,1,2],j in [0,1]];
colours2:=&cat[colours : i in mats];
size:=DisplayPolygons([h*g*pol : g in C2,h in mats],"/tmp/pic.ps":
Show:=true,Colours:=colours2,Size:=[-0.5,2.5,4,200]);
// make the above example into a function:
procedure gamma2picture()
pol:=domain_for_SL();
size:=DisplayPolygons([h*g*pol : g in C2,h in mats],"/tmp/pic.ps":
Show:=true,Colours:=colours2,Size:=[-0.5,2.5,4,200]);
end procedure;
gamma2picture();
|
|
|
Pretty picture related to Gamma0(16).
(no particular significance)
|
|
|
G:=Gamma0(16);
C:=CosetRepresentatives(G);
H< i,r>:=UpperHalfPlaneWithCusps();
Edge1:=[H|0,2];
Edge2:=[H|i,1/2*(i+1)];
point:=GeodesicsIntersection(Edge1,Edge2,H)[1];
triangle1:=[H|Infinity(),i,r];
triangle3:=[H|i,point,r];
triangle2:=[H|0,i,point];
Par:=Parent(triangle1);
t:=G![1,1,0,1];
Polygons:=[Par|g*tri : g in C,tri in [triangle1,triangle2,triangle3]];
Polygons2:=[Par|t*g*tri : g in C,tri in [triangle3]];
Polygons3:=[Par|t^(-1)*g*tri : g in C,tri in [triangle3]];
purple:=[0.5,0,0.8];
blue:=[0.6,0.6,0.9];
yellow:=[1,0.8,0];
Colours:=[blue : i in C] cat [purple : i in C] cat [yellow : i in C]
cat [purple : i in C] cat [yellow : i in C];
DisplayPolygons(Polygons cat Polygons2 cat
Polygons3,"/tmp/pic.ps":Show:=true,
Colours:=Colours,Size:=[-1,2,1.5,150]);
|
|