Example #1
0
def test_L_with_slit_mpq():
    import cppyy

    mpq = cppyy.gbl.mpq_class
    R2 = flatsurf.Vector[mpq]
    surface = surfaces.L(R2)
    slit = R2(mpq(5, 3), mpq(4, 3))
    e = flatsurf.HalfEdge(1)
    surface = surface.insertAt(e, slit).surface()
    assert e != flatsurf.HalfEdge(
        1), "HalfEdge& not updated correctly in " + repr(surface)
    e = surface.nextAtVertex(e)
    surface = surface.slit(e).surface()

    connections = surface.connections().bound(16).sector(flatsurf.HalfEdge(1))
    assert len([1 for c in connections]) == 15
Example #2
0
def test_hexagon_eantic():
    surface = surfaces.hexagon()
    decompositions = {(1, 0): 0, (2, 0): 0}

    for connection in surface.connections().bound(16).sector(
            flatsurf.HalfEdge(1)):
        decomposition = flatsurf.makeFlowDecomposition(surface,
                                                       connection.vector())
        assert repr(decomposition).startswith("FlowDecomposition")
        assert str(decomposition).startswith("FlowDecomposition")
        decomposition.decompose(-1)
        n_cylinders = 0
        n_without_periodic_trajectory = 0
        for component in decomposition.components():
            n_cylinders += bool(component.cylinder() == True)
            n_without_periodic_trajectory += bool(
                component.withoutPeriodicTrajectory() == True)

            if component.cylinder():
                # 3 ways to compute area
                area1 = component.area()

                h = component.circumferenceHolonomy()
                p0 = [p for p in component.perimeter()][0]
                sc = p0.saddleConnection()
                p0 = sc.vector()
                vertical = component.vertical()
                assert vertical.projectPerpendicular(h) == 0
                assert vertical.project(h) > 0
                area2 = p0.x() * h.y() - p0.y() * h.x()

                v = vertical.vertical()
                vx = v.x()
                vy = v.y()
                area3 = vertical.projectPerpendicular(p0) * vertical.project(h)

                assert area1 == 2 * area2
                assert area3 == area2 * (vx * vx + vy * vy)

        assert all(component.cylinder()
                   for component in decomposition.cylinders())
        assert len(decomposition.cylinders()) == n_cylinders

        assert all(component.withoutPeriodicTrajectory()
                   for component in decomposition.minimalComponents())
        assert len(
            decomposition.minimalComponents()) == n_without_periodic_trajectory

        assert len(decomposition.undeterminedComponents()) == 0

        t = (n_cylinders, n_without_periodic_trajectory)
        decompositions[t] += 1

        if n_without_periodic_trajectory == 0:
            assert decomposition.parabolic()

    assert decompositions == {(1, 0): 7, (2, 0): 3}
Example #3
0
def test_square_longlong():
    surface = surfaces.square(flatsurf.Vector['long long'])
    connections = surface.saddleConnections(flatsurf.Bound(16), flatsurf.HalfEdge(1))
    # https://bitbucket.org/wlav/cppyy/issues/103/std-distance-returns-random-output
    # assert len(connections) == 60
    # This does not work, the iterator that backs connections returns
    # references that are only valid until the iterator is advanced, so the
    # conversion to list does not work at the moment.
    # assert len(list(connections))
    assert len([1 for c in connections]) == 60
    async def path(self):
        r"""
        The path drawn by the user or explicitly set.

        EXAMPLES::

            >>> from flatsurf import translation_surfaces
            >>> S = translation_surfaces.square_torus();

            >>> from ipyvue_flatsurf import Widget
            >>> W = Widget(S)

        Unfortunately, this cannot be tested withuot an actual notebook
        running, see https://github.com/flatsurf/ipyvue-async/issues/2::

            >>> await W.path  # doctest: +SKIP
            [...]

        Note that the path is not re-requested once it has been determined. To
        clear the path, you need to set it to `None`::

            >>> W.path = None
            >>> await W.path  # doctest: +SKIP

        The path can be given as a flatsurf path or as a list of flatsurf
        saddle connections::

            >>> import asyncio
            >>> W.path = []
            >>> asyncio.run(W.path)
            []

        """
        if self._path is None:
            self.action = "path"

            import asyncio

            path = await self.poll(self.query("flatsurf", "path", "completed", return_when=asyncio.FIRST_COMPLETED))

            # TODO: Unfortunately, we have to query explicitly for the layout,
            # see https://github.com/flatsurf/vue-flatsurf/issues/55. Also we
            # cannot be sure that we are getting the layout from the one that
            # gave us the path, see
            # https://github.com/flatsurf/ipyvue-async/issues/1.
            layout = await self.poll(self.query("flatsurf", "layout", "now", return_when=asyncio.FIRST_COMPLETED))

            S = self.triangulation

            inner = [edge.positive().id() for edge in S.edges() if layout['halfEdges'][str(edge)]['inner']]

            if len(path) < 2:
                raise NotImplementedError("Cannot represent trivial paths yet.")
            if 'vertex' not in path[0]:
                raise NotImplementedError("Cannot represent path that does not start at a vertex yet.")
            if 'vertex' not in path[-1]:
                raise NotImplementedError("Cannot represent path that does not end at a vertex yet.")

            from pyflatsurf import flatsurf

            path = [{
                'vertex': [flatsurf.HalfEdge(x) for x in p['vertex']]
            } if 'vertex' in p else {
                'halfEdge': flatsurf.HalfEdge(p['halfEdge'])
            } for p in path]

            connections = []

            # The input path consists of a list of points that are either at a
            # vertex or somewhere on a half edge.  Connections between vertex
            # points are in principle easy since we can exactly represent them
            # in libflatsurf as saddle connections.  However, a connection that
            # starts or ends inside a half edge has no correspondence in
            # libflatsurf (yet) so we need to rewrite it as a homotopic
            # sequence of connections of the first kind. Actually, we rewrite
            # it as a sequence of half edges, the simplest saddle connections.
            # To that end, we treat every half edge point as a point at the
            # vertex where this half edge starts.

            # The half edges that the path is crossing, i.e., the half edges
            # that we are allowed to cross when reconstructing an equivalent
            # representation of the path.
            inner = [flatsurf.HalfEdge(e) for e in inner] + [flatsurf.HalfEdge(-e) for e in inner]

            for source, target in zip(path, path[1:]):
                def source_faces(x):
                    if 'halfEdge' in x:
                        return [S.previousAtVertex(x['halfEdge'])]
                    else:
                        return x['vertex']

                def target_faces(x):
                    if 'halfEdge' in x:
                        return [x['halfEdge']]
                    else:
                        return x['vertex']

                # We now pretend that we start in one of the faces attached to
                # "start" and search for a path to a face attached to "target".
                paths = {}
                queue = []

                def enqueue_face(face, partial):
                    if face in paths:
                        return

                    paths[face] = partial
                    queue.append(face)

                    next = S.nextInFace(face)
                    enqueue_face(next, partial + [face])

                for source_face in source_faces(source):
                    enqueue_face(source_face, [])

                while queue:
                    face = queue.pop()
                    if face in inner:
                        enqueue_face(-face, paths[face] + [face])

                for target_face in target_faces(target):
                    if target_face in paths:
                        connections.extend(paths[target_face])
                        break
                else:
                    raise ValueError(f"Could not reconstruct the partial path from {source} to {target} that was reported by the frontend.")

            self._path = flatsurf.Path[type(S)]([flatsurf.SaddleConnection[type(S)](S, halfEdge) for halfEdge in connections])
        return self._path
Example #5
0
def test_hexagon_exactreal():
    from pyexactreal import exactreal
    surface = surfaces.random_hexagon()
    connections = surface.saddleConnections(flatsurf.Bound(16), flatsurf.HalfEdge(1))
Example #6
0
def test_hexagon_eantic():
    surface = surfaces.hexagon()
    connections = surface.saddleConnections(flatsurf.Bound(16), flatsurf.HalfEdge(1))
    assert len([1 for c in connections]) == 10
Example #7
0
def test_deformation_square(capsys):
    Edge = flatsurf.Edge

    vector = flatsurf.Vector['mpq_class']

    # A square of size (3, 3)
    square = surfaces.square(vector).scale(3)

    # Insert an extra vertex at (2, 1) that is easier to move around without
    # having to change the entire surface.
    square = square.insertAt(flatsurf.HalfEdge(1), vector(2, 1)).surface()

    # A forbidden shift, collapsing a half edge during the shift; this is
    # supposed to fail but it should fail silently.
    shift = lambda e: vector(-2, -4) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(0, 0)

    capsys.readouterr()

    import cppyy
    with pytest.raises(cppyy.gbl.std.invalid_argument):
        square + [shift(e) for e in square.edges()]

    # Verify that #179 has been fixed, i.e., no warnings are printed
    output = capsys.readouterr()
    assert output.out == ""
    assert output.err == ""

    # A much smaller shift in the same direction is allowed
    square + [shift(e) / 128 for e in square.edges()]

    # A shift half the length collapses the extra vertex
    square + [shift(e) / 2 for e in square.edges()]

    # Another shift with a vertex ending up on the interior of a half edge, i.e., requires a flip.
    shift = lambda e: vector(-1, 0) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(0, 0)
    square + [shift(e) for e in square.edges()]

    # Another shift with a vertex crossing over the interior of a half edge, i.e., requires a flip.
    shift = lambda e: vector(-2, 0) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(0, 0)
    square + [shift(e) for e in square.edges()]

    # Another shift with a vertex crossing over the interior of a half edge but
    # then ending up on another vertex, i.e., requires a flip and a collapse.
    shift = lambda e: vector(-4, -2) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(0, 0)
    square + [shift(e) for e in square.edges()]

    # Another shift with a vertex crossing lots of half edges, i.e., requiring many flips.
    shift = lambda e: vector(-23, 0) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(0, 0)
    square + [shift(e) for e in square.edges()]

    # Insert a vertex in the other triangle so we can move both simultaneously
    square = square.insertAt(flatsurf.HalfEdge(3), vector(1, 2)).surface()

    # Shift both inserted vertices towards the same vertex simultaneously
    shift = lambda e: vector(-1, -2) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(
            -2, -1) if e in [Edge(7), Edge(8), Edge(9)] else vector(0, 0)
    square + [shift(e) / 2 for e in square.edges()]

    # Shift both inserted vertices onto the same vertex simultaneously
    square + [shift(e) for e in square.edges()]

    # Shift both inserted vertices a long way across the surface in the same direction
    shift = lambda e: vector(-23, 0) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(
            -23, 0) if e in [Edge(7), Edge(8), Edge(9)] else vector(0, 0)
    square + [shift(e) for e in square.edges()]

    # Shift both inserted vertices a long way across the surface in different directions (invalid because it the two marked vertices meet at some point.)
    shift = lambda e: vector(-23, 0) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(
            0, -23) if e in [Edge(7), Edge(8), Edge(9)] else vector(0, 0)
    with pytest.raises(cppyy.gbl.std.invalid_argument):
        square + [shift(e) for e in square.edges()]

    # Shift both inserted vertices a long way across the surface in different directions
    shift = lambda e: vector(-23, 0) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(
            -1, -23) if e in [Edge(7), Edge(8), Edge(9)] else vector(0, 0)
    square + [shift(e) for e in square.edges()]

    # Shift both inserted vertices a long way across the surface in different directions and at different velocities
    shift = lambda e: vector(-23, 0) if e in [Edge(
        4), Edge(5), Edge(6)] else vector(
            0, -47) if e in [Edge(7), Edge(8), Edge(9)] else vector(0, 0)
    square + [shift(e) for e in square.edges()]
Example #8
0
def test_printing():
    surface = surfaces.hexagon(flatsurf.Vector['eantic::renf_elem_class'])
    assert str(surface.fromHalfEdge(flatsurf.HalfEdge(1))) == "(2, 0)"
    assert repr(surface.fromHalfEdge(flatsurf.HalfEdge(1))) == "(2, 0)"
Example #9
0
def test_edge():
    half_edge = flatsurf.HalfEdge(1)
    assert half_edge.edge().positive() == half_edge
Example #10
0
def test_printing():
    surface = surfaces.hexagon()
    assert str(surface.fromEdge(flatsurf.HalfEdge(1))) == "(2, 0)"
    assert repr(surface.fromEdge(flatsurf.HalfEdge(1))) == "(2, 0)"
Example #11
0
def test_hexagon_exactreal():
    from pyexactreal import exactreal
    surface = surfaces.random_hexagon()
    connections = surface.connections().bound(16).sector(flatsurf.HalfEdge(1))
    assert len([1 for c in connections]) >= 10
Example #12
0
def test_hexagon_eantic():
    surface = surfaces.hexagon()
    connections = surface.connections().bound(16).sector(flatsurf.HalfEdge(1))
    assert len([1 for c in connections]) == 10
Example #13
0
def test_L_mpq():
    surface = surfaces.L(flatsurf.Vector['mpq_class'])
    connections = surface.connections().bound(16).sector(flatsurf.HalfEdge(1))
    assert len([1 for c in connections]) == 60