Beispiel #1
0
def as_embedded_number_field_elements(algs):
    # number_field_elements_from_algebraics() now takes an embedded=...
    # argument, but doesn't yet support all cases we need
    nf, elts, emb = number_field_elements_from_algebraics(algs)
    if nf is not QQ:
        nf = NumberField(nf.polynomial(), nf.variable_name(),
                    embedding=emb(nf.gen()))
        elts = [elt.polynomial()(nf.gen()) for elt in elts]
        nf, hom = good_number_field(nf)
        elts = [hom(elt) for elt in elts]
    # assert [QQbar.coerce(elt) == alg for alg, elt in zip(algs, elts)]
    return nf, elts
Beispiel #2
0
def as_embedded_number_field_elements(algs):
    try:
        nf, elts, _ = number_field_elements_from_algebraics(algs, embedded=True)
    except NotImplementedError: # compatibility with Sage <= 9.3
        nf, elts, emb = number_field_elements_from_algebraics(algs)
        if nf is not QQ:
            nf = NumberField(nf.polynomial(), nf.variable_name(),
                        embedding=emb(nf.gen()))
            elts = [elt.polynomial()(nf.gen()) for elt in elts]
            nf, hom = good_number_field(nf)
            elts = [hom(elt) for elt in elts]
        assert [QQbar.coerce(elt) == alg for alg, elt in zip(algs, elts)]
    return nf, elts
Beispiel #3
0
def platonic_icosahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic icosahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_icosahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_icosahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices=[]
    phi=AA(1+sqrt(5))/2
    F=NumberField(phi.minpoly(),"phi",embedding=phi)
    phi=F.gen()
    for i in xrange(3):
        for s1 in xrange(-1,3,2):
            for s2 in xrange(-1,3,2):
                p=3*[None]
                p[i]=s1*phi
                p[(i+1)%3]=s2
                p[(i+2)%3]=0
                vertices.append(vector(F,p))
    p=Polyhedron(vertices=vertices)
    
    s,m = polyhedron_to_cone_surface(p)
    return p,s,m
Beispiel #4
0
def platonic_dodecahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic dodecahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_dodecahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_dodecahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices=[]
    phi=AA(1+sqrt(5))/2
    F=NumberField(phi.minpoly(),"phi",embedding=phi)
    phi=F.gen()
    for x in xrange(-1,3,2):
        for y in xrange(-1,3,2):
            for z in xrange(-1,3,2):
                vertices.append(vector(F,(x,y,z)))
    for x in xrange(-1,3,2):
        for y in xrange(-1,3,2):
            vertices.append(vector(F,(0,x*phi,y/phi)))
            vertices.append(vector(F,(y/phi,0,x*phi)))
            vertices.append(vector(F,(x*phi,y/phi,0)))
    scale=AA(2/sqrt(1+(phi-1)**2+(1/phi-1)**2))
    p=Polyhedron(vertices=vertices)
    s,m = polyhedron_to_cone_surface(p,scaling_factor=scale)
    return p,s,m
Beispiel #5
0
def number_field_elements_from_algebraics(elts, name='a'):
    r"""
    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])
    """
    from sage.rings.qqbar import number_field_elements_from_algebraics
    from sage.rings.number_field.number_field import NumberField
    field,elts,phi = number_field_elements_from_algebraics(elts, minimal=True)

    polys = [x.polynomial() for x in elts]
    K = NumberField(field.polynomial(), name, embedding=AA(phi(field.gen())))
    gen = K.gen()

    return K, [x.polynomial()(gen) for x in elts]
Beispiel #6
0
def platonic_icosahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic icosahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_icosahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_icosahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices = []
    phi = AA(1 + sqrt(5)) / 2
    F = NumberField(phi.minpoly(), "phi", embedding=phi)
    phi = F.gen()
    for i in range(3):
        for s1 in range(-1, 3, 2):
            for s2 in range(-1, 3, 2):
                p = 3 * [None]
                p[i] = s1 * phi
                p[(i + 1) % 3] = s2
                p[(i + 2) % 3] = 0
                vertices.append(vector(F, p))
    p = Polyhedron(vertices=vertices)

    s, m = polyhedron_to_cone_surface(p)
    return p, s, m
Beispiel #7
0
def platonic_dodecahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic dodecahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_dodecahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_dodecahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices = []
    phi = AA(1 + sqrt(5)) / 2
    F = NumberField(phi.minpoly(), "phi", embedding=phi)
    phi = F.gen()
    for x in range(-1, 3, 2):
        for y in range(-1, 3, 2):
            for z in range(-1, 3, 2):
                vertices.append(vector(F, (x, y, z)))
    for x in range(-1, 3, 2):
        for y in range(-1, 3, 2):
            vertices.append(vector(F, (0, x * phi, y / phi)))
            vertices.append(vector(F, (y / phi, 0, x * phi)))
            vertices.append(vector(F, (x * phi, y / phi, 0)))
    scale = AA(2 / sqrt(1 + (phi - 1)**2 + (1 / phi - 1)**2))
    p = Polyhedron(vertices=vertices)
    s, m = polyhedron_to_cone_surface(p, scaling_factor=scale)
    return p, s, m
Beispiel #8
0
    def _number_field_from_algebraics(self):
        r"""
        Given a projective point defined over ``QQbar``, return the same point, but defined
        over a number field.

        This is only implemented for points of projective space.

        OUTPUT: scheme point

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: P.<x,y> = ProjectiveSpace(QQbar,1)
            sage: Q = P([-1/2*QQbar(sqrt(2)) + QQbar(I), 1])
            sage: S = Q._number_field_from_algebraics(); S
            (1/2*a^3 + a^2 - 1/2*a : 1)
            sage: S.codomain()
            Projective Space of dimension 1 over Number Field in a with defining polynomial y^4 + 1 with a = 0.7071067811865475? + 0.7071067811865475?*I

        The following was fixed in :trac:`23808`::

            sage: R.<x> = PolynomialRing(QQ)
            sage: P.<x,y> = ProjectiveSpace(QQbar,1)
            sage: Q = P([-1/2*QQbar(sqrt(2)) + QQbar(I), 1]);Q
            (-0.7071067811865475? + 1*I : 1)
            sage: S = Q._number_field_from_algebraics(); S
            (1/2*a^3 + a^2 - 1/2*a : 1)
            sage: T = S.change_ring(QQbar) # Used to fail
            sage: T
            (-0.7071067811865475? + 1.000000000000000?*I : 1)
            sage: Q[0] == T[0]
            True
        """
        from sage.schemes.projective.projective_space import is_ProjectiveSpace
        if not is_ProjectiveSpace(self.codomain()):
            raise NotImplementedError("not implemented for subschemes")

        # Trac #23808: Keep the embedding info associated with the number field K
        # used below, instead of in the separate embedding map phi which is
        # forgotten.
        K_pre, P, phi = number_field_elements_from_algebraics(list(self))
        if K_pre is QQ:
            K = QQ
        else:
            from sage.rings.number_field.number_field import NumberField
            K = NumberField(K_pre.polynomial(),
                            embedding=phi(K_pre.gen()),
                            name='a')
            psi = K_pre.hom([K.gen()], K)  # Identification of K_pre with K
            P = [psi(p) for p in P]  # The elements of P were elements of K_pre
        from sage.schemes.projective.projective_space import ProjectiveSpace
        PS = ProjectiveSpace(K, self.codomain().dimension_relative(), 'z')
        return PS(P)
Beispiel #9
0
def as_embedded_number_field_element(alg):
    from sage.rings.number_field.number_field import NumberField
    nf, elt, emb = alg.as_number_field_element()
    if nf is QQ:
        res = elt
    else:
        embnf = NumberField(nf.polynomial(),
                            nf.variable_name(),
                            embedding=emb(nf.gen()))
        res = elt.polynomial()(embnf.gen())
    # assert QQbar.coerce(res) == alg
    return res
Beispiel #10
0
 def __init__(self,lambda_squared=None, field=None):
     if lambda_squared==None:
         from sage.rings.number_field.number_field import NumberField
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
         R=PolynomialRing(ZZ,'x')
         x = R.gen()
         from sage.rings.qqbar import AA
         field=NumberField(x**3-ZZ(5)*x**2+ZZ(4)*x-ZZ(1), 'r', embedding=AA(ZZ(4)))
         self._l=field.gen()
     else:
         if field is None:
             self._l=lambda_squared
             field=lambda_squared.parent()
         else:
             self._l=field(lambda_squared)
     Surface.__init__(self,field, ZZ.zero(), finite=False)
Beispiel #11
0
def polyhedron_to_cone_surface(polyhedron, use_AA=False, scaling_factor=ZZ(1)):
    r"""Construct the Euclidean Cone Surface associated to the surface of a polyhedron and a map
    from the cone surface to the polyhedron.
    
    INPUT:

    - ``polyhedron`` -- A 3-dimensional polyhedron, which should be define over something that coerces into AA

    - ``use_AA`` -- If True, the surface returned will be defined over AA. If false, the algorithm will find the smallest NumberField and write the field there.
    
    - ``scaling_factor`` -- The surface returned will have a metric scaled by multiplication by this factor (compared with the original polyhendron). This can be used to produce a surface defined over a smaller NumberField.
    
    OUTPUT:
    
    A pair consisting of a ConeSurface and a ConeSurfaceToPolyhedronMap.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import *
    sage: vertices=[]
    sage: for i in xrange(3):
    ....:     temp=vector([1 if k==i else 0 for k in xrange(3)])
    ....:     for j in xrange(-1,3,2):
    ....:         vertices.append(j*temp)
    sage: octahedron=Polyhedron(vertices=vertices)
    sage: surface,surface_to_octahedron = \
    ....:     polyhedron_to_cone_surface(octahedron,scaling_factor=AA(1/sqrt(2)))
    sage: TestSuite(surface).run()
    sage: TestSuite(surface_to_octahedron).run(skip="_test_pickling")
    sage: surface.num_polygons()
    8
    sage: surface.base_ring()
    Number Field in a with defining polynomial y^2 - 3
    sage: sqrt3=surface.base_ring().gen()
    sage: tangent_bundle=surface.tangent_bundle()
    sage: v=tangent_bundle(0,(0,0),(sqrt3,2))
    sage: traj=v.straight_line_trajectory()
    sage: traj.flow(10)
    sage: traj.is_saddle_connection()
    True
    sage: traj.combinatorial_length()
    8
    sage: surface_to_octahedron(traj)
    [(-1, 0, 0),
     (0.?e-18, -0.8000000000000000?, -0.2000000000000000?),
     (0.2500000000000000?, -0.750000000000000?, 0.?e-18),
     (0.4000000000000000?, 0.?e-19, 0.6000000000000000?),
     (0.?e-19, 0.500000000000000?, 0.500000000000000?),
     (-2/5, 3/5, 0),
     (-0.2500000000000000?, 0.?e-18, -0.750000000000000?),
     (0.?e-18, -0.2000000000000000?, -0.8000000000000000?),
     (1, 0, 0)]
    sage: surface_to_octahedron(traj.segment(0))
    ((-1, 0, 0), (0.?e-18, -0.8000000000000000?, -0.2000000000000000?))
    sage: surface_to_octahedron(traj.segment(0).start())
    ((-1, 0, 0), (2.886751345948129?, -2.309401076758503?, -0.5773502691896258?))
    sage: # octahedron.plot(wireframe=None,frame=False)+line3d(surface_to_octahedron(traj),radius=0.01)

    """
    assert polyhedron.dim()==3
    c=polyhedron.center()
    vertices=polyhedron.vertices()
    vertex_order={}
    for i,v in enumerate(vertices):
        vertex_order[v]=i
    faces=polyhedron.faces(2)
    face_order={}
    face_edges=[]
    face_vertices=[]
    face_map_data=[]
    for i,f in enumerate(faces):
        face_order[f]=i
        edges=f.as_polyhedron().faces(1)
        face_edges_temp = set()
        for edge in edges:
            edge_temp=set()
            for vertex in edge.vertices():
                v=vertex.vector()
                v.set_immutable()
                edge_temp.add(v)
            face_edges_temp.add(frozenset(edge_temp))

            
        last_edge = next(iter(face_edges_temp))
        v = next(iter(last_edge))
        face_vertices_temp=[v]
        for j in xrange(len(face_edges_temp)-1):
            for edge in face_edges_temp:
                if v in edge and edge!=last_edge:
                    # bingo
                    last_edge=edge
                    for vv in edge:
                        if vv!=v:
                            v=vv
                            face_vertices_temp.append(vv)
                            break
                    break


        v0=face_vertices_temp[0]
        v1=face_vertices_temp[1]
        v2=face_vertices_temp[2]
        n=(v1-v0).cross_product(v2-v0)
        if (v0-c).dot_product(n)<0:
            n=-n
            face_vertices_temp.reverse()
            v0=face_vertices_temp[0]
            v1=face_vertices_temp[1]
            v2=face_vertices_temp[2]

        face_vertices.append(face_vertices_temp)    
        n=n/AA(n.norm())
        w=v1-v0
        w=w/AA(w.norm())
        m=1/scaling_factor*matrix(AA,[w,n.cross_product(w),n]).transpose()
        mi=~m
        mis=mi.submatrix(0,0,2,3)
        face_map_data.append((
            v0, # translation to bring origin in plane to v0
            m.submatrix(0,0,3,2),
            -mis*v0,
            mis
        ))

        it=iter(face_vertices_temp)    
        v_last=next(it)
        face_edge_dict={}
        j=0
        for v in it:
            edge=frozenset([v_last,v])
            face_edge_dict[edge]=j
            j+=1
            v_last=v
        v=next(iter(face_vertices_temp))
        edge=frozenset([v_last,v])
        face_edge_dict[edge]=j
        face_edges.append(face_edge_dict)
        
    gluings={}
    for p1,face_edge_dict1 in enumerate(face_edges):
        for edge, e1 in face_edge_dict1.items():
            found=False
            for p2, face_edge_dict2 in enumerate(face_edges):
                if p1!=p2 and edge in face_edge_dict2:
                    e2=face_edge_dict2[edge]
                    gluings[(p1,e1)]=(p2,e2)
                    found=True
                    break
            if not found:
                print(p1)
                print(e1)
                print(edge)
                raise RuntimeError("Failed to find glued edge")
    polygon_vertices_AA=[]
    for p,vs in enumerate(face_vertices):
        trans=face_map_data[p][2]
        m=face_map_data[p][3]
        polygon_vertices_AA.append([trans+m*v for v in vs])
        
    
    if use_AA==True:
        Polys=Polygons(AA)
        polygons=[]
        for vs in polygon_vertices_AA:
            polygons.append(Polys(vertices=vs))
        S=ConeSurface(surface_list_from_polygons_and_gluings(polygons,gluings))
        return S, \
            ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)
    else:
        elts=[]
        for vs in polygon_vertices_AA:
            for v in vs:
                elts.append(v[0])
                elts.append(v[1])
                
        # Find the best number field:
        field,elts2,hom = number_field_elements_from_algebraics(elts,minimal=True)
        if field==QQ:
            # Defined over the rationals!
            polygon_vertices_field2=[]
            j=0
            for vs in polygon_vertices_AA:
                vs2=[]
                for v in vs:
                    vs2.append(vector(field,[elts2[j],elts2[j+1]]))
                    j=j+2
                polygon_vertices_field2.append(vs2)
            Polys=Polygons(field)
            polygons=[]
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S=ConeSurface(surface_list_from_polygons_and_gluings(polygons,gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)

        else:        
            # Unfortunately field doesn't come with an real embedding (which is given by hom!)
            # So, we make a copy of the field, and add the embedding.
            field2=NumberField(field.polynomial(),name="a",embedding=hom(field.gen()))
            # The following converts from field to field2:
            hom2=field.hom(im_gens=[field2.gen()])

            polygon_vertices_field2=[]
            j=0
            for vs in polygon_vertices_AA:
                vs2=[]
                for v in vs:
                    vs2.append(vector(field2,[hom2(elts2[j]),hom2(elts2[j+1])]))
                    j=j+2
                polygon_vertices_field2.append(vs2)
            Polys=Polygons(field2)
            polygons=[]
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S=ConeSurface(surface_list_from_polygons_and_gluings(polygons,gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)
class EInfinitySurface(Surface):
    r"""
    The surface based on the $E_\infinity$ graph.

     The biparite graph is shown below, with edges numbered:

      0   1   2  -2   3  -3   4  -4 
    *---o---*---o---*---o---*---o---*...
            |
            |-1
            o

    Here, black vertices are colored *, and white o. 
    Black nodes represent vertical cylinders and white nodes
    represent horizontal cylinders.
    """
    def __init__(self,lambda_squared=None, field=None):
        TranslationSurface_generic.__init__(self)
        if lambda_squared==None:
            from sage.rings.number_field.number_field import NumberField
            from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
            R=PolynomialRing(ZZ,'x')
            x = R.gen()
            from sage.rings.qqbar import AA
            self._field=NumberField(x**3-ZZ(5)*x**2+ZZ(4)*x-ZZ(1), 'r', embedding=AA(ZZ(4)))
            self._l=self._field.gen()
        else:
            if field is None:
                self._l=lambda_squared
                self._field=lambda_squared.parent()
            else:
                self._field=field
                self._l=field(lambda_squared)
        Surface.__init__(self)

    def _repr_(self):
        r"""
        String representation.
        """
        return "The E-infinity surface"

    def base_ring(self):
        r"""
        Return the rational field.
        """
        return self._field

    def base_label(self):
        return ZZ.zero()

    @cached_method
    def get_white(self,n):
        r"""Get the weight of the white endpoint of edge n."""
        l=self._l
        if n==0 or n==1:
            return l
        if n==-1:
            return l-1
        if n==2:
            return 1-3*l+l**2
        if n>2:
            x=self.get_white(n-1)
            y=self.get_black(n)
            return l*y-x
        return self.get_white(-n)

    @cached_method
    def get_black(self,n):
        r"""Get the weight of the black endpoint of edge n."""
        l=self._l
        if n==0:
            return self._field(1)
        if n==1 or n==-1 or n==2:
            return l-1
        if n>2:
            x=self.get_black(n-1)
            y=self.get_white(n-1)
            return y-x
        return self.get_black(1-n)

    def polygon(self, lab):
        r"""
        Return the polygon labeled by ``lab``.
        """
        if lab not in self.polygon_labels():
            raise ValueError("lab (=%s) not a valid label"%lab)
        from flatsurf.geometry.polygon import rectangle
        return rectangle(2*self.get_black(lab),self.get_white(lab))

    def polygon_labels(self):
        r"""
        The set of labels used for the polygons.
        """
        return ZZ

    def opposite_edge(self, p, e):
        r"""
        Return the pair ``(pp,ee)`` to which the edge ``(p,e)`` is glued to.
        """
        if p==0:
            if e==0:
                return (0,2)
            if e==1:
                return (1,3)
            if e==2:
                return (0,0)
            if e==3:
                return (1,1)
        if p==1:
            if e==0:
                return (-1,2)
            if e==1:
                return (0,3)
            if e==2:
                return (2,0)
            if e==3:
                return (0,1)
        if p==-1:
            if e==0:
                return (2,2)
            if e==1:
                return (-1,3)
            if e==2:
                return (1,0)
            if e==3:
                return (-1,1)
        if p==2:
            if e==0:
                return (1,2)
            if e==1:
                return (-2,3)
            if e==2:
                return (-1,0)
            if e==3:
                return (-2,1)
        if p>2:
            if e%2:
                return -p,(e+2)%4
            else:
                return 1-p,(e+2)%4
        else:
            if e%2:
                return -p,(e+2)%4
            else:
                return 1-p,(e+2)%4

    def is_finite(self):
        return False
Beispiel #13
0
def polyhedron_to_cone_surface(polyhedron, use_AA=False, scaling_factor=ZZ(1)):
    r"""Construct the Euclidean Cone Surface associated to the surface of a polyhedron and a map
    from the cone surface to the polyhedron.
    
    INPUT:

    - ``polyhedron`` -- A 3-dimensional polyhedron, which should be define over something that coerces into AA

    - ``use_AA`` -- If True, the surface returned will be defined over AA. If false, the algorithm will find the smallest NumberField and write the field there.
    
    - ``scaling_factor`` -- The surface returned will have a metric scaled by multiplication by this factor (compared with the original polyhendron). This can be used to produce a surface defined over a smaller NumberField.
    
    OUTPUT:
    
    A pair consisting of a ConeSurface and a ConeSurfaceToPolyhedronMap.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import *
    sage: vertices=[]
    sage: for i in range(3):
    ....:     temp=vector([1 if k==i else 0 for k in range(3)])
    ....:     for j in range(-1,3,2):
    ....:         vertices.append(j*temp)
    sage: octahedron=Polyhedron(vertices=vertices)
    sage: surface,surface_to_octahedron = \
    ....:     polyhedron_to_cone_surface(octahedron,scaling_factor=AA(1/sqrt(2)))
    sage: TestSuite(surface).run()
    sage: TestSuite(surface_to_octahedron).run(skip="_test_pickling")
    sage: surface.num_polygons()
    8
    sage: surface.base_ring()
    Number Field in a with defining polynomial y^2 - 3 with a = 1.732050807568878?
    sage: sqrt3=surface.base_ring().gen()
    sage: tangent_bundle=surface.tangent_bundle()
    sage: v=tangent_bundle(0,(0,0),(sqrt3,2))
    sage: traj=v.straight_line_trajectory()
    sage: traj.flow(10)
    sage: traj.is_saddle_connection()
    True
    sage: traj.combinatorial_length()
    8
    sage: path3d = surface_to_octahedron(traj)
    sage: len(path3d)
    9
    sage: # We will show that the length of the path is sqrt(42):
    sage: total_length = 0
    sage: for i in range(8):
    ....:     start = path3d[i]
    ....:     end = path3d[i+1]
    ....:     total_length += (vector(end)-vector(start)).norm()
    sage: ZZ(total_length**2)
    42
    """
    assert polyhedron.dim() == 3
    c = polyhedron.center()
    vertices = polyhedron.vertices()
    vertex_order = {}
    for i, v in enumerate(vertices):
        vertex_order[v] = i
    faces = polyhedron.faces(2)
    face_order = {}
    face_edges = []
    face_vertices = []
    face_map_data = []
    for i, f in enumerate(faces):
        face_order[f] = i
        edges = f.as_polyhedron().faces(1)
        face_edges_temp = set()
        for edge in edges:
            edge_temp = set()
            for vertex in edge.vertices():
                v = vertex.vector()
                v.set_immutable()
                edge_temp.add(v)
            face_edges_temp.add(frozenset(edge_temp))

        last_edge = next(iter(face_edges_temp))
        v = next(iter(last_edge))
        face_vertices_temp = [v]
        for j in range(len(face_edges_temp) - 1):
            for edge in face_edges_temp:
                if v in edge and edge != last_edge:
                    # bingo
                    last_edge = edge
                    for vv in edge:
                        if vv != v:
                            v = vv
                            face_vertices_temp.append(vv)
                            break
                    break

        v0 = face_vertices_temp[0]
        v1 = face_vertices_temp[1]
        v2 = face_vertices_temp[2]
        n = (v1 - v0).cross_product(v2 - v0)
        if (v0 - c).dot_product(n) < 0:
            n = -n
            face_vertices_temp.reverse()
            v0 = face_vertices_temp[0]
            v1 = face_vertices_temp[1]
            v2 = face_vertices_temp[2]

        face_vertices.append(face_vertices_temp)
        n = n / AA(n.norm())
        w = v1 - v0
        w = w / AA(w.norm())
        m = 1 / scaling_factor * matrix(
            AA, [w, n.cross_product(w), n]).transpose()
        mi = ~m
        mis = mi.submatrix(0, 0, 2, 3)
        face_map_data.append((
            v0,  # translation to bring origin in plane to v0
            m.submatrix(0, 0, 3, 2),
            -mis * v0,
            mis))

        it = iter(face_vertices_temp)
        v_last = next(it)
        face_edge_dict = {}
        j = 0
        for v in it:
            edge = frozenset([v_last, v])
            face_edge_dict[edge] = j
            j += 1
            v_last = v
        v = next(iter(face_vertices_temp))
        edge = frozenset([v_last, v])
        face_edge_dict[edge] = j
        face_edges.append(face_edge_dict)

    gluings = {}
    for p1, face_edge_dict1 in enumerate(face_edges):
        for edge, e1 in face_edge_dict1.items():
            found = False
            for p2, face_edge_dict2 in enumerate(face_edges):
                if p1 != p2 and edge in face_edge_dict2:
                    e2 = face_edge_dict2[edge]
                    gluings[(p1, e1)] = (p2, e2)
                    found = True
                    break
            if not found:
                print(p1)
                print(e1)
                print(edge)
                raise RuntimeError("Failed to find glued edge")
    polygon_vertices_AA = []
    for p, vs in enumerate(face_vertices):
        trans = face_map_data[p][2]
        m = face_map_data[p][3]
        polygon_vertices_AA.append([trans + m * v for v in vs])

    if use_AA == True:
        Polys = ConvexPolygons(AA)
        polygons = []
        for vs in polygon_vertices_AA:
            polygons.append(Polys(vertices=vs))
        S = ConeSurface(
            surface_list_from_polygons_and_gluings(polygons, gluings))
        return S, \
            ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)
    else:
        elts = []
        for vs in polygon_vertices_AA:
            for v in vs:
                elts.append(v[0])
                elts.append(v[1])

        # Find the best number field:
        field, elts2, hom = number_field_elements_from_algebraics(elts,
                                                                  minimal=True)
        if field == QQ:
            # Defined over the rationals!
            polygon_vertices_field2 = []
            j = 0
            for vs in polygon_vertices_AA:
                vs2 = []
                for v in vs:
                    vs2.append(vector(field, [elts2[j], elts2[j + 1]]))
                    j = j + 2
                polygon_vertices_field2.append(vs2)
            Polys = ConvexPolygons(field)
            polygons = []
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S = ConeSurface(
                surface_list_from_polygons_and_gluings(polygons, gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)

        else:
            # Unfortunately field doesn't come with an real embedding (which is given by hom!)
            # So, we make a copy of the field, and add the embedding.
            field2 = NumberField(field.polynomial(),
                                 name="a",
                                 embedding=hom(field.gen()))
            # The following converts from field to field2:
            hom2 = field.hom(im_gens=[field2.gen()])

            polygon_vertices_field2 = []
            j = 0
            for vs in polygon_vertices_AA:
                vs2 = []
                for v in vs:
                    vs2.append(
                        vector(field2, [hom2(elts2[j]),
                                        hom2(elts2[j + 1])]))
                    j = j + 2
                polygon_vertices_field2.append(vs2)
            Polys = ConvexPolygons(field2)
            polygons = []
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S = ConeSurface(
                surface_list_from_polygons_and_gluings(polygons, gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)