# The Geometry Package¶

This package contains modules for working with basic geometric objects relating to translation surfaces and more generally to similarity surfaces.

## Polygons¶

Convex polygons in the plane (R^2)

This file implements convex polygons with

• action of matrices in GL^+(2,R)
• conversion between ground fields

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons

sage: K.<sqrt2> = NumberField(x^2 - 2, embedding=AA(2).sqrt())
sage: p = polygons((1,0), (-sqrt2,1+sqrt2), (sqrt2-1,-1-sqrt2))
sage: p
Polygon: (0, 0), (1, 0), (-sqrt2 + 1, sqrt2 + 1)

sage: M = MatrixSpace(K,2)
sage: m = M([[1,1+sqrt2],[0,1]])
sage: m * p
Polygon: (0, 0), (1, 0), (sqrt2 + 4, sqrt2 + 1)

class flatsurf.geometry.polygon.ConvexPolygon(parent, edges=None, vertices=None, translation=None)[source]

A convex polygon in the plane RR^2 defined up to translation.

angle(e)[source]

Return the angle at the begining of the start point of the edge e.

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons
sage: polygons.square().angle(0)
1/4
sage: polygons.regular_ngon(8).angle(0)
3/8

area()[source]

Return the area of this polygon.

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons
sage: polygons.regular_ngon(8).area()
2*a + 2
sage: _ == 2*AA(2).sqrt() + 2
True

sage: AA(polygons.regular_ngon(11).area())
9.36563990694544?

sage: polygons.square().area()
1
sage: (2*polygons.square()).area()
4

base_ring()[source]
contains_point(point, translation=None)[source]

Return true if the point is within the polygon (after the polygon is possibly translated)

edge(i)[source]

Return a vector representing the i-th edge of the polygon.

edges()[source]

Return the list of edges as vectors.

field()
flow(point, holonomy, translation=None)[source]

Flow a point in the direction of holonomy for the length of the holonomy, or until the point leaves the polygon. Note that ValueErrors may be thrown if the point is not in the polygon, or if it is on the boundary and the holonomy does not point into the polygon.

INPUT:

• point – a point in the closure of the polygon (vector over the underlying base_ring())
• holonomy – direction and magnitude of motion (vector over the underlying base_ring())
• translation – optional translation to applied to the polygon (vector over the underlying base_ring())

OUTPUT:

• The point within the polygon where the motion stops (or leaves the polygon)
• The amount of holonomy left to flow
• a PolygonPosition object representing the combinatorial position of the stopping point

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons
sage: s = polygons.square()
sage: V=s.parent().vector_space()
sage: p=V((1/2,1/2))
sage: w=V((2,0))
sage: s.flow(p,w)
((1, 1/2), (3/2, 0), point positioned on interior of edge 1 of polygon)

flow_to_exit(point, direction)[source]

Flow a point in the direction of holonomy until the point leaves the polygon. Note that ValueErrors may be thrown if the point is not in the polygon, or if it is on the boundary and the holonomy does not point into the polygon.

INPUT:

• point – a point in the closure of the polygon (as a vector)
• holonomy – direction of motion (a vector of non-zero length)

OUTPUT:

• The point in the boundary of the polygon where the trajectory exits
• a PolygonPosition object representing the combinatorial position of the stopping point
get_point_position(point, translation=None)[source]

Get a combinatorial position of a points position compared to the polygon

INPUT:

• point – a point in the plane (vector over the underlying base_ring())
• translation – optional translation to applied to the polygon (vector over the underlying base_ring())

OUTPUT:

• a PolygonPosition object

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons
sage: s = polygons.square()
sage: V = s.parent().vector_space()
sage: s.get_point_position(V((1/2,1/2)))
point positioned in interior of polygon
sage: s.get_point_position(V((1,0)))
point positioned on vertex 1 of polygon
sage: s.get_point_position(V((1,1/2)))
point positioned on interior of edge 1 of polygon
sage: s.get_point_position(V((1,3/2)))
point positioned outside polygon

num_edges()[source]
plot(translation=None)[source]

Plot the polygon with the origin at translation.

vector_space()[source]

Return the vector space containing the vertices.

vertex(index)[source]
vertices(translation=None)[source]

Return the set of vertices as vectors.

class flatsurf.geometry.polygon.ConvexPolygons(field)[source]
Element

alias of ConvexPolygon

base_ring()[source]
field()
has_coerce_map_from(other)[source]
vector_space[source]

CachedMethodCallerNoArgs(inst, f, cache=None, name=None) File: sage/misc/cachefunc.pyx (starting at line 2098)

Utility class that is used by CachedMethod to bind a cached method to an instance, in the case of a method that does not accept any arguments except self.

Note

The return value None would not be cached. So, if you have a method that does not accept arguments and may return None after a lengthy computation, then @cached_method should not be used.

EXAMPLE:

sage: P.<a,b,c,d> = QQ[]
sage: I = P*[a,b]
sage: I.gens
Cached version of <function gens at 0x...>
sage: type(I.gens)
<type 'sage.misc.cachefunc.CachedMethodCallerNoArgs'>
sage: I.gens is I.gens
True
sage: I.gens() is I.gens()
True


AUTHOR:

• Simon King (2011-04)
class flatsurf.geometry.polygon.MatrixActionOnPolygons(polygons)[source]
class flatsurf.geometry.polygon.PolygonCreator(field=Rational Field)[source]

Class for iteratively constructing a polygon over the field.

Add a vertex to the polygon. Returns 1 if successful and 0 if not, in which case the resulting polygon would not have been convex.

get_polygon()[source]

Return the polygon. Raises a ValueError if less than three vertices have been accepted.

vector_space()[source]

Return the vector space in which self naturally embeds.

class flatsurf.geometry.polygon.PolygonPosition(position_type, edge=None, vertex=None)[source]

Class for describing the position of a point within or outside of a polygon.

EDGE_INTERIOR = 2
INTERIOR = 1
OUTSIDE = 0
VERTEX = 3
get_edge()[source]
get_position_type()[source]
get_vertex()[source]
is_in_boundary()[source]

Return true if the position is in the boundary of the polygon (either the interior of an edge or a vertex).

is_in_edge_interior()[source]
is_in_interior()[source]
is_inside()[source]

Return true if the position is not outside the closure of the polygon

is_outside()[source]
is_vertex()[source]
flatsurf.geometry.polygon.Polygons

alias of ConvexPolygons

class flatsurf.geometry.polygon.PolygonsConstructor[source]
rectangle(width, height, **kwds)[source]

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons

sage: polygons.rectangle(1,2)
Polygon: (0, 0), (1, 0), (1, 2), (0, 2)

sage: polygons.rectangle(1,sqrt2)
Polygon: (0, 0), (1, 0), (1, sqrt2), (0, sqrt2)
sage: _.parent()
polygons with coordinates in Number Field in sqrt2 with defining
polynomial x^2 - 2

static regular_ngon(n)[source]

Return a regular n-gon.

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons

sage: p = polygons.regular_ngon(17)
sage: p
Polygon: (0, 0), (1, 0), ..., (-1/2*a^14 + 15/2*a^12 - 45*a^10 + 275/2*a^8 - 225*a^6 + 189*a^4 - 70*a^2 + 15/2, 1/2*a)

square(side=1, **kwds)[source]

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons

sage: polygons.square()
Polygon: (0, 0), (1, 0), (1, 1), (0, 1)
sage: polygons.square(field=QQbar).parent()
polygons with coordinates in Algebraic Field

flatsurf.geometry.polygon.is_opposite_direction(v, w)[source]

EXAMPLES:

sage: from flatsurf.geometry.polygon import is_opposite_direction
sage: V = QQ**2

sage: is_opposite_direction(V((0,1)), V((0,-2)))
True
sage: is_opposite_direction(V((1,-1)), V((-2,2)))
True
sage: is_opposite_direction(V((4,-2)), V((-2,1)))
True
sage: is_opposite_direction(V((-1,-2)), V((2,4)))
True

sage: is_opposite_direction(V((1,1)), V((1,2)))
False
sage: is_opposite_direction(V((1,2)), V((2,1)))
False
sage: is_opposite_direction(V((0,2)), V((0,1)))
False
sage: is_opposite_direction(V((1,2)), V((1,-2)))
False
sage: is_opposite_direction(V((1,2)), V((-1,2)))
False
sage: is_opposite_direction(V((2,-1)), V((-2,-1)))
False

sage: is_opposite_direction(V((1,0)), V.zero())
Traceback (most recent call last):
...
TypeError: zero vector has no direction

sage: for _ in range(100):
....:    v = V.random_element()
....:    if not v: continue
....:    assert not is_opposite_direction(v, v)
....:    assert not is_opposite_direction(v,2*v)
....:    assert is_opposite_direction(v, -v)

flatsurf.geometry.polygon.is_same_direction(v, w, zero=None)[source]

EXAMPLES:

sage: from flatsurf.geometry.polygon import is_same_direction
sage: V = QQ**2

sage: is_same_direction(V((0,1)), V((0,2)))
True
sage: is_same_direction(V((1,-1)), V((2,-2)))
True
sage: is_same_direction(V((4,-2)), V((2,-1)))
True
sage: is_same_direction(V((1,2)), V((2,4)))
True
sage: is_same_direction(V((0,2)), V((0,1)))
True

sage: is_same_direction(V((1,1)), V((1,2)))
False
sage: is_same_direction(V((1,2)), V((2,1)))
False
sage: is_same_direction(V((1,2)), V((1,-2)))
False
sage: is_same_direction(V((1,2)), V((-1,-2)))
False
sage: is_same_direction(V((2,-1)), V((-2,1)))
False

sage: is_same_direction(V((1,0)), V.zero())
Traceback (most recent call last):
...
TypeError: zero vector has no direction

sage: for _ in range(100):
....:    v = V.random_element()
....:    if not v: continue
....:    assert is_same_direction(v, 2*v)
....:    assert not is_same_direction(v, -v)

flatsurf.geometry.polygon.number_field_elements_from_algebraics(elts, name='a')[source]

The native Sage function number_field_elements_from_algebraics currently returns number field without embedding. This function return field with embedding!

EXAMPLES:

sage: from flatsurf.geometry.polygon import number_field_elements_from_algebraics
sage: z = QQbar.zeta(5)
sage: c = z.real()
sage: s = z.imag()
sage: number_field_elements_from_algebraics((c,s))
(Number Field in a with defining polynomial y^4 - 5*y^2 + 5,
[1/2*a^2 - 3/2, 1/2*a])

flatsurf.geometry.polygon.regular_octagon(field=None)[source]
flatsurf.geometry.polygon.wedge_product(v, w)[source]

## Surfaces¶

Translation surfaces.

class flatsurf.geometry.similarity_surface.AbstractOrigami[source]

Abstract base class for origamis. Realization needs just to define a _domain and four cardinal directions.

base_ring()[source]
down(label)[source]
left(label)[source]
num_polygons()[source]

Returns the number of polygons.

opposite_edge(p, e)[source]
polygon(lab)[source]
polygon_labels()[source]
right(label)[source]
up(label)[source]
class flatsurf.geometry.similarity_surface.ConicSurface[source]

A conic surface.

angles()[source]

Return the set of angles around the vertices of the surface.

EXAMPLES:

sage: import flatsurf.geometry.similarity_surface_generators as sfg
sage: sfg.translation_surfaces.regular_octagon().angles()


class flatsurf.geometry.similarity_surface.MinimalTranslationCover(similarity_surface)[source]

We label copy by cartesian product (polygon from bot, matrix).

base_label()[source]
base_ring()[source]
opposite_edge(p, e)[source]
polygon(lab)[source]
polygon_labels()[source]

Return the set of polygons used for the labels.

class flatsurf.geometry.similarity_surface.Origami(r, u, rr=None, uu=None, domain=None)[source]
down(label)[source]
left(label)[source]
opposite_edge(p, e)[source]
right(label)[source]
up(label)[source]
class flatsurf.geometry.similarity_surface.SimilaritySurface_generic[source]

An oriented surface built from a set of polygons and edges identified with similarities (i.e. composition of homothety, rotations and translations).

Each polygon is identified with a unique key (its label). The choice of the label of the polygons is done at startup. If the set is finite then by default the labels are the first non-negative integers 0,1,...

The edge are identified by a couple (polygon label, edge number).

Note

This class is abstract and should not be called directly. Instead you can either use SimilaritySurface_from_polygons_and_identifications or inherit from it and implement the methods:

• num_polygons(self): the number of polygons in that surface
• base_ring(self): the base ring in which coordinates lives
• polygon(self, lab): the polygon associated to the label lab

It might also be good to implement

• base_polygon(self): a couple (label, polygon) that is a somewhat fixed polygon
• opposite_edge(self, lab, edege): a couple (other_lab, other_edge)
area()[source]
base_label()[source]
base_ring()[source]

The field on which the coordinates of self live.

This method must be overriden in subclasses!

edge_dict()[source]
edge_iterator()[source]
edge_matrix(p, e=None)[source]

Return the edge to which this edge is identified and the matrix to be applied.

edge_transformation(p, e)[source]

Return the similarity bringing the provided edge to the opposite edge.

EXAMPLES:

sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators
sage: s = SimilaritySurfaceGenerators.example()
sage: print(s.polygon(0))
Polygon: (0, 0), (2, -2), (2, 0)
sage: print(s.polygon(1))
Polygon: (0, 0), (2, 0), (1, 3)
sage: print(s.opposite_edge(0,0))
(1, 1)
sage: g = s.edge_transformation(0,0)
sage: g((0,0))
(1, 3)
sage: g((2,-2))
(2, 0)

edit()[source]

Launch the tk editor to interactively modify self.

fundamental_group_basis()[source]

Return a basis for the fundamental group as a sequence of paths:

[vertex0, edge0, vertex1, edge1, ...].

get_bundle()[source]

Return a pair (sm,sb), where sm is the active SurfaceManipulator, and sb is the surface bundle for this surface (which is added if neccessary to the SurfaceManipulator). If necessary, we create one or both objects.

graphical_surface()[source]

Return a GraphicalSurface representing this surface.

is_finite()[source]
minimal_translation_cover()[source]

Return the minimal translation cover.

Be careful that if the surface is not built from one polygon, this is not the smallest translation cover of the surface.

EXAMPLES:

sage: from flatsurf import *
sage: S = similarity_surfaces.example()
sage: T = S.minimal_translation_cover()
sage: T
Translation surface built from +Infinity polygons
sage: T.polygon(T.polygon_labels().an_element())
Polygon: (0, 0), (8/5, -4/5), (6/5, 2/5)

num_edges()[source]

Return the number of edges.

num_polygons()[source]

Return the number of polygons.

opposite_edge(p, e)[source]

Given the label p of a polygon and an edge e in that polygon returns the pair (pp, ee) to which this edge is glued.

This method must be overriden in subclasses.

polygon(lab)[source]

Return the polygon with label lab.

This method must be overriden in subclasses.

polygon_iterator()[source]

Iterator over the polygons.

polygon_labels()[source]

The set of labels used by the polygons.

This method must be overriden in subclasses.

tangent_bundle(ring=None)[source]

Return the tangent bundle

INPUT:

• ring – an optional field (defaults to the coordinate field of the surface)
tangent_vector(lab, p, v, ring=None)[source]

Return a tangent vector.

INPUT:

• lab – label of a polygon
• p – coordinates of a point in the polygon
• v – coordinates of a vector in R^2

EXAMPLES:

sage: from flatsurf.geometry.chamanara import ChamanaraSurface
sage: S = ChamanaraSurface(1/2)
sage: S.tangent_vector(0, (1/2,1/2), (1,1))
SimilaritySurfaceTangentVector in polygon 1 based at (-1/2, 3/2) with vector
(-1, -1)
sage: S.tangent_vector(0, (1/2,1/2), (1,sqrt2))
SimilaritySurfaceTangentVector in polygon 1 based at (-1/2, 3/2) with vector
(-1, -sqrt2)

sage: S = ChamanaraSurface(sqrt2/2)
sage: S.tangent_vector(1, (0,1), (1,1))
SimilaritySurfaceTangentVector in polygon 0 based at (-sqrt2, sqrt2
+ 1) with vector (-1, -1)

vector_space()[source]

Return the vector space in which self naturally embeds.

class flatsurf.geometry.similarity_surface.SimilaritySurface_polygons_and_gluings(polygons=None, identifications=None)[source]

Similarity surface build from a list of polygons and gluings.

base_ring()[source]
num_polygons()[source]
opposite_edge(p, e)[source]
polygon(lab)[source]

Return the polygon with label lab.

polygon_labels()[source]
class flatsurf.geometry.similarity_surface.TranslationSurface_generic[source]

A surface with a flat metric and conical singularities (not necessarily multiple angle of pi or 2pi).

• polygon = polygon + vertex (or equivalently, canonical ordering)

A translation surface is:

• field embedded in R
• index set for the (convex) polygons + favorite polygon
• edges: ((t1,e1),(t2,e2))

For finite case:

• canonical labelings of polygons
• Delaunay triangulation
edge_matrix(p, e=None)[source]
minimal_translation_cover()[source]
plot()[source]
stratum()[source]

EXAMPLES:

sage: import flatsurf.geometry.similarity_surface_generators as sfg
sage: sfg.translation_surfaces.octagon_and_squares().stratum()
H(4)

class flatsurf.geometry.similarity_surface.TranslationSurface_polygons_and_gluings(polygons=None, identifications=None)[source]

## Matrices (2x2)¶

Some tools for 2x2 matrices and planar geometry.

flatsurf.geometry.matrix_2x2.angle(u, v, assume_rational=False)[source]

Return the angle between the vectors u and v divided by 2 pi.

INPUT:

• u, v - vectors
• assume_rational - whether we assume that the angle is a multiple rational of pi. By default it is False but if it is known in advance that the result is rational then setting it to True might be much faster.

EXAMPLES:

sage: from flatsurf.geometry.matrix_2x2 import angle


As the implementation is dirty, we at least check that it works for all denominator up to 20:

sage: u = vector((AA(1),AA(0)))
sage: for n in xsrange(1,20):       # long time  (10 sec)
....:     for k in xsrange(1,n):
....:         v = vector((AA(cos(2*k*pi/n)), AA(sin(2*k*pi/n))))
....:         assert angle(u,v) == k/n


And we test up to 50 when setting assume_rational to True:

sage: for n in xsrange(1,50):       # long time  (25 sec)
....:     for k in xsrange(1,n):
....:         v = vector((AA(cos(2*k*pi/n)), AA(sin(2*k*pi/n))))
....:         assert angle(u,v,assume_rational=True) == k/n


If the angle is not rational, then the method returns an element in the real lazy field:

sage: v = vector((AA(sqrt(2)), AA(sqrt(3))))
sage: a = angle(u,v)
sage: a
0.1410235542122437?
sage: exp(2*pi.n()*CC(0,1)*a.n())
0.632455532033676 + 0.774596669241483*I
sage: v / v.norm()
(0.6324555320336758?, 0.774596669241484?)

flatsurf.geometry.matrix_2x2.homothety_rotation_decomposition(m)[source]

Return a couple composed of the homothety and a rotation matrix.

The coefficients of the returned pair are either in the ground field of m or in the algebraic field AA.

EXAMPLES:

sage: from flatsurf.geometry.matrix_2x2 import homothety_rotation_decomposition

sage: R.<x> = PolynomialRing(QQ)
sage: K.<sqrt2> = NumberField(x^2 - 2, embedding=1.4142)
sage: m = matrix([[sqrt2, -sqrt2],[sqrt2,sqrt2]])
sage: a,rot = homothety_rotation_decomposition(m)
sage: a
2
sage: rot
[ 1/2*sqrt2 -1/2*sqrt2]
[ 1/2*sqrt2  1/2*sqrt2]

flatsurf.geometry.matrix_2x2.is_cosine_sine_of_rational(c, s)[source]

Check whether the given pair is a cosine and sine of a same rational angle.

EXAMPLES:

sage: from flatsurf.geometry.matrix_2x2 import is_cosine_sine_of_rational

sage: c = s = AA(sqrt(2))/2
sage: is_cosine_sine_of_rational(c,s)
True
sage: c = AA(sqrt(3))/2; s = AA(1/2)
sage: is_cosine_sine_of_rational(c,s)
True

sage: c = AA(sqrt(5)/2); s = (1 - c**2).sqrt()
sage: c**2 + s**2
1.000000000000000?
sage: is_cosine_sine_of_rational(c,s)
False

sage: c = (AA(sqrt(5)) + 1)/4; s = (1 - c**2).sqrt()
sage: is_cosine_sine_of_rational(c,s)
True

flatsurf.geometry.matrix_2x2.is_similarity(m)[source]

Return True if m is a similarity and False otherwise.

EXAMPLES:

sage: from flatsurf.geometry.matrix_2x2 import is_similarity

sage: is_similarity(matrix([[0,1],[1,0]]))
True
sage: is_similarity(matrix([[0,-2],[2,0]]))
True
sage: is_similarity(matrix([[1,1],[0,1]]))
False

flatsurf.geometry.matrix_2x2.number_field_to_AA(a)[source]

It is a mess to convert an element of a number field to the algebraic field AA. This is a temporary fix.

flatsurf.geometry.matrix_2x2.rotation_matrix_angle(r, check=False)[source]

Return the angle of the rotation matrix r divided by 2 pi.

EXAMPLES:

sage: from flatsurf.geometry.matrix_2x2 import rotation_matrix_angle

sage: def rot_matrix(p, q):
....:     z = QQbar.zeta(q) ** p
....:     c = z.real()
....:     s = z.imag()
....:     return matrix(AA, 2, [c,-s,s,c])
sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)]
[1/5, 2/5, 3/5, 4/5]
sage: [rotation_matrix_angle(rot_matrix(i,7)) for i in range(1,7)]
[1/7, 2/7, 3/7, 4/7, 5/7, 6/7]


Some random tests:

sage: for _ in range(100):
....:     r = QQ.random_element(x=0,y=500)
....:     r -= r.floor()
....:     m = rot_matrix(r.numerator(), r.denominator())
....:     assert rotation_matrix_angle(m) == r


Note

This is using floating point arithmetic and might be wrong.

flatsurf.geometry.matrix_2x2.similarity_from_vectors(u, v)[source]

Return the unique similarity matrix that maps u to v.

EXAMPLES:

sage: from flatsurf.geometry.matrix_2x2 import similarity_from_vectors

sage: V = VectorSpace(QQ,2)
sage: u = V((1,0))
sage: v = V((0,1))
sage: m = similarity_from_vectors(u,v); m
[ 0 -1]
[ 1  0]
sage: m*u == v
True

sage: u = V((2,1))
sage: v = V((1,-2))
sage: m = similarity_from_vectors(u,v); m
[ 0  1]
[-1  0]
sage: m * u == v
True


An example built from the Pythagorean triple 3^2 + 4^2 = 5^2:

sage: u2 = V((5,0))
sage: v2 = V((3,4))
sage: m = similarity_from_vectors(u2,v2); m
[ 3/5 -4/5]
[ 4/5  3/5]
sage: m * u2 == v2
True


Some test over number fields:

sage: K.<sqrt2> = NumberField(x^2-2, embedding=1.4142)
sage: V = VectorSpace(K,2)
sage: u = V((sqrt2,0))
sage: v = V((1, 1))
sage: m = similarity_from_vectors(u,v); m
[ 1/2*sqrt2 -1/2*sqrt2]
[ 1/2*sqrt2  1/2*sqrt2]
sage: m*u == v
True

sage: m = similarity_from_vectors(u, 2*v); m
[ sqrt2 -sqrt2]
[ sqrt2  sqrt2]
sage: m*u == 2*v
True


## Similarities and Translations¶

class flatsurf.geometry.similarity.Similarity(parent, a, b, s, t)[source]

Class for a similarity of the plane.

derivative()[source]

Return the 2x2 matrix corresponding to the derivative of the similarity of the plane.

flatsurf.geometry.similarity.SimilarityGroup[source]

Group representing all similarities in the plane. This is the group generated by rotations, translations and dilations.

class flatsurf.geometry.translation.Translation(parent, *args)[source]

Class for a translation of the plane. This is an element of a group written multiplicatively (for composition, and compatibility with Similarity).

matrix()[source]
s()[source]
t()[source]
flatsurf.geometry.translation.TranslationGroup[source]

Group representing translations in the plane with a multiplicative group operation.

## Tangent Bundle¶

class flatsurf.geometry.tangent_bundle.SimilaritySurfaceTangentBundle(similarity_surface, ring=None)[source]

Construct the tangent bundle of a given similarity surface.

Needs work: We should check for coersion from the base_ring of the surface

base_ring()[source]
clockwise_edge(polygon_label, edge_index)[source]

Return the vector leaving a vertex of the polygon which under straight-line flow travels clockwise around the boundary of the polygon along the edge with the provided index. The length of the vector matches the length of the indexed edge. Note that the point will be based in the polgon opposite the provided edge.

EXAMPLES:

sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators
sage: s = SimilaritySurfaceGenerators.example()
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentBundle
sage: tb = SimilaritySurfaceTangentBundle(s)
sage: print("Polygon 0 is "+str(s.polygon(0)))
Polygon 0 is Polygon: (0, 0), (2, -2), (2, 0)
sage: print("Polygon 1 is "+str(s.polygon(1)))
Polygon 1 is Polygon: (0, 0), (2, 0), (1, 3)
sage: print("Opposite edge to (0,0) is "+repr(s.opposite_edge(0,0)))
Opposite edge to (0,0) is (1, 1)
sage: print(tb.clockwise_edge(0,0))
SimilaritySurfaceTangentVector in polygon 1 based at (2, 0) with vector (-1, 3)

edge(polygon_label, edge_index)[source]

Return the vector leaving a vertex of the polygon which under straight-line flow travels counterclockwise around the boundary of the polygon along the edge with the provided index. The length of the vector matches the length of the indexed edge.

EXAMPLES:

sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators
sage: s = SimilaritySurfaceGenerators.example()
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentBundle
sage: tb = SimilaritySurfaceTangentBundle(s)
sage: print(s.polygon(0))
Polygon: (0, 0), (2, -2), (2, 0)
sage: print(tb.edge(0,0))
SimilaritySurfaceTangentVector in polygon 0 based at (0, 0) with vector (2, -2)

field()
surface()[source]

Return the surface this bundle is over.

vector_space()[source]

Return the vector space over the field of the bundle.

class flatsurf.geometry.tangent_bundle.SimilaritySurfaceTangentVector(tangent_bundle, polygon_label, point, vector)[source]
bundle()[source]

Return the tangent bundle containing this vector.

differs_by_scaling(another_tangent_vector)[source]

Returns true if the other vector just differs by scaling. This means they should lie in the same polygon, be based at the same point, and point in the same direction.

edge_pointing_along()[source]

Returns the pair of (p,e) where p is the polygon label at the base point, and e is the edge this vector points along or none if it does not point along an edge. Here pointing along means that the vector is based at a vertex and represents the vector joining this edge to the next vertex.

forward_to_polygon_boundary()[source]

Flows forward (in the direction of the tangent vector) until the end of the polygon is reached. Returns the tangent vector based at the endpoint which point backward along the trajectory.

NOTES:

We return the backward trajectory, because continuing forward does not make sense if a
singularity is reached. You can obtain the forward vector by subsequently applying invert().


EXAMPLES:

sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators
sage: s = SimilaritySurfaceGenerators.example()
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentBundle
sage: tb = SimilaritySurfaceTangentBundle(s)
sage: print("Polygon 0 is "+str(s.polygon(0)))
Polygon 0 is Polygon: (0, 0), (2, -2), (2, 0)
sage: print("Polygon 1 is "+str(s.polygon(1)))
Polygon 1 is Polygon: (0, 0), (2, 0), (1, 3)
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentVector
sage: V = tb.surface().vector_space()
sage: v = SimilaritySurfaceTangentVector(tb, 0, V((0,0)), V((3,-1)))
sage: print(v)
SimilaritySurfaceTangentVector in polygon 0 based at (0, 0) with vector (3, -1)
sage: v2 = v.forward_to_polygon_boundary()
sage: print(v2)
SimilaritySurfaceTangentVector in polygon 0 based at (2, -2/3) with vector (-3, 1)
sage: print(v2.invert())
SimilaritySurfaceTangentVector in polygon 1 based at (2/3, 2) with vector (4, -3)

invert()[source]

Returns the negation of this tangent vector. Raises a ValueError if the vector is based at a singularity.’

is_based_at_singularity()[source]

Return the truth value of the statement ‘the base point for this vector is a singularity.’

is_in_boundary_of_polygon()[source]

Return the truth value of the statement ‘the base point for this vector lies on the boundary of one of the polygons making up the surface.’

point()[source]

Return the coordinates of the basepoint of the vector within the assigned polygon.

polygon()[source]
polygon_label()[source]
singularity()[source]

Return the index of the vertex.

straight_line_trajectory()[source]

Convert this tangent vector to a StraightLineTrajectory.

surface()[source]

Return the underlying surface.

vector()[source]

Return the coordinates of this vector within the assigned polygon.

## Straight-line Flow¶

class flatsurf.geometry.straight_line_trajectory.SegmentInPolygon(tangent_vector, end_vector=None)[source]

Stores a maximal segment in a polygon of a translation surface.

edge()[source]
end()[source]

Return a TangentVector associated to the end of a trajectory, pointed backward.

end_direction()[source]
end_is_singular()[source]
end_point()[source]
invert()[source]
is_edge()[source]
next()[source]

Return the next segment obtained by continuing straight through the end point.

EXAMPLES:

sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators
sage: s = SimilaritySurfaceGenerators.example()
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentBundle
sage: tb = SimilaritySurfaceTangentBundle(s)
sage: print("Polygon 0 is "+str(s.polygon(0)))
Polygon 0 is Polygon: (0, 0), (2, -2), (2, 0)
sage: print("Polygon 1 is "+str(s.polygon(1)))
Polygon 1 is Polygon: (0, 0), (2, 0), (1, 3)
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentVector
sage: V = tb.surface().vector_space()
sage: v = SimilaritySurfaceTangentVector(tb, 0, V((0,0)), V((3,-1)))
sage: from flatsurf.geometry.straight_line_trajectory import *
sage: seg = SegmentInPolygon(v)
sage: print(seg)
Segment in polygon 0 starting at (0, 0) and ending at (2, -2/3)
sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators
sage: s = SimilaritySurfaceGenerators.example()
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentBundle
sage: tb = SimilaritySurfaceTangentBundle(s)
sage: print("Polygon 0 is "+str(s.polygon(0)))
Polygon 0 is Polygon: (0, 0), (2, -2), (2, 0)
sage: print("Polygon 1 is "+str(s.polygon(1)))
Polygon 1 is Polygon: (0, 0), (2, 0), (1, 3)
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentVector
sage: V = tb.surface().vector_space()
sage: v = SimilaritySurfaceTangentVector(tb, 0, V((0,0)), V((3,-1)))
sage: from flatsurf.geometry.straight_line_trajectory import *
sage: seg = SegmentInPolygon(v)
sage: print(seg)
Segment in polygon 0 starting at (0, 0) and ending at (2, -2/3)
sage: print(seg.next())
Segment in polygon 1 starting at (2/3, 2) and ending at (14/9, 4/3)

polygon_label()[source]
previous()[source]
start()[source]

Return a TangentVector associated to the start of a trajectory pointed forward.

start_direction()[source]
start_is_singular()[source]
start_point()[source]
class flatsurf.geometry.straight_line_trajectory.StraightLineTrajectory(tangent_vector)[source]

Abstract class for a straight-line trajectory.

combinatorial_length()[source]
flow(steps)[source]

Append or preprend segments to the trajectory. If steps is positive, attempt to append this many segments. If steps is negative, attempt to prepent this many segments. Will fail gracefully the trajectory hits a singularity or closes up.

EXAMPLES:

sage: from flatsurf.geometry.similarity_surface_generators import SimilaritySurfaceGenerators
sage: s = SimilaritySurfaceGenerators.example()
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentBundle
sage: tb = SimilaritySurfaceTangentBundle(s)
sage: print("Polygon 0 is "+str(s.polygon(0)))
Polygon 0 is Polygon: (0, 0), (2, -2), (2, 0)
sage: print("Polygon 1 is "+str(s.polygon(1)))
Polygon 1 is Polygon: (0, 0), (2, 0), (1, 3)
sage: from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentVector
sage: V = tb.surface().vector_space()
sage: v = SimilaritySurfaceTangentVector(tb, 0, V((1,-0.5)), V((3,-1)))
sage: from flatsurf.geometry.straight_line_trajectory import *
sage: traj = StraightLineTrajectory(v)
sage: print(traj)
StraightLineTrajectorydeque([Segment in polygon 0 starting at (1/4, -1/4) and ending at (2, -5/6)])
sage: traj.flow(1)
sage: print(traj)
StraightLineTrajectorydeque([Segment in polygon 0 starting at (1/4, -1/4) and ending at (2, -5/6), Segment in polygon 1 starting at (7/12, 7/4) and ending at (61/36, 11/12)])
sage: traj.flow(-1)
sage: print(traj)
StraightLineTrajectorydeque([Segment in polygon 1 starting at (15/16, 45/16) and ending at (9/8, 21/8), Segment in polygon 0 starting at (1/4, -1/4) and ending at (2, -5/6), Segment in polygon 1 starting at (7/12, 7/4) and ending at (61/36, 11/12)])

graphical_trajectory(graphical_surface)[source]

Returns a GraphicalStraightLineTrajectory corresponding to this trajectory in the provided GraphicalSurface.

initial_segment()[source]
initial_tangent_vector()[source]
is_backward_separatrix()[source]
is_closed()[source]
is_forward_separatrix()[source]
segments()[source]
terminal_segment()[source]
terminal_tangent_vector()[source]

## Homology¶

This module contains a lazy implementation of a relative homology, $H_1(S,Sigma; R)$, where $S$ is a similarity surface, $Sigma$ is the singularities or vertices, and $R$ is a ring.

This implementation works for finite or infinite surfaces. For infinite surfaces, we define relative homology formally. It is simply $R^E$ where $E$ is the edge set modulo equivalences of two types: 1) If $e$ is an edge, and $e’$ is its opposite edge oriented counterclockwise from the polygon they bound then $e+e’=0$ in homology. 2) The sum of edges around a polygon is zero.

class flatsurf.geometry.relative_homology.RelativeHomology(surface, base_ring=Integer Ring)[source]
Element

alias of RelativeHomologyClass

base_ring()[source]
edge(label, e)[source]

Return the homology class of the edge with the provided polygon label and edge index oriented counter-clockwise around the polygon.

zero()[source]
class flatsurf.geometry.relative_homology.RelativeHomologyClass(parent, d)[source]
edges_with_weights()[source]

Returns a list of items of the form ((label,e),w) where (label,e) represents and edge and w represents the non-zero weight assigned.

weight(label, e)[source]

Return the weight of the indexed edge.

weighted_edges()[source]

Return the set of pairs (label,e) representing edges with non-zero weights.