Beispiel #1
0
def sum(R, S):

    T = R.triangulation()
    R_quads = quads_mat(R)
    S_quads = quads_mat(S)

    F_quads = R_quads + S_quads

    normal_coords = [
        int(F_quads[i][j]) for i in range(F_quads.dimensions()[0])
        for j in range(3)
    ]

    F = regina.NormalSurface(T, regina.NS_QUAD, normal_coords)

    return F
Beispiel #2
0
def is_connected(spun_normal_surface):
    S = spun_normal_surface
    T = S.triangulation()

    abst_nbhds = abstract_nbhds(S)
    quads_matrix = quads_mat(S)
    abst_nbhd_comps = [
        set([(abst_nbhds[k]['tets'][j], comp[j]) for j in range(len(comp))
             if comp[j] != -1]) for k in abst_nbhds
        for comp in abst_nbhds[k]['components']
    ]

    anc_dict = dict([(i, abst_nbhd_comps[i])
                     for i in range(len(abst_nbhd_comps))])

    G = Graph(len(anc_dict))

    for i in G.vertices():
        for j in range(i + 1, G.num_verts()):
            if len(anc_dict[i].intersection(anc_dict[j])) > 0:
                G.add_edge((i, j))

    if G.is_connected():
        return True

    else:
        return False
Beispiel #3
0
def unoriented_spinning_slopes(spun_surface,
                               peripheral_curve_mats,
                               quads_mat=None):
    s = spun_surface
    T = s.triangulation()

    intx_mat = matrices.UNORIENTED_INTERSECTION_MAT
    slopes = []  # on a surface affects boundary orientations.
    if quads_mat == None:
        quads_mat = matrices.quads_mat(s)

    intx_times_quad_mat = (intx_mat * quads_mat.transpose()).transpose()

    for c in range(T.countCusps()):
        periph_mat = peripheral_curve_mats[
            c]  # get the matrix that encodes meridian and longitude for cusp c.

        iota_lambda = 0
        iota_mu = 0

        for i in range(T.size()):
            iota_lambda += Integer(periph_mat[0][i] * intx_times_quad_mat[i])
            iota_mu += Integer(periph_mat[1][i] * intx_times_quad_mat[i])

        slopes.append((-iota_lambda, iota_mu))
    return slopes
Beispiel #4
0
def spinning_slopes(S):
    q_mat = quads_mat(S)
    T = S.triangulation()
    M = snappy.Manifold(T.snapPea())
    pc_mats = peripheral_curve_mats(M, T)
    slopes = unoriented_spinning_slopes(S, pc_mats, q_mat)
    return slopes
Beispiel #5
0
def connected_components(spun_normal_surface):
    S = spun_normal_surface
    T = S.triangulation()

    abst_nbhds = abstract_nbhds(S)
    quads_matrix = quads_mat(S)
    abst_nbhd_comps = [
        set([(abst_nbhds[k]['tets'][j], comp[j]) for j in range(len(comp))
             if comp[j] != -1]) for k in abst_nbhds
        for comp in abst_nbhds[k]['components']
    ]

    anc_dict = dict([(i, abst_nbhd_comps[i])
                     for i in range(len(abst_nbhd_comps))])

    G = Graph(len(anc_dict))

    for i in G.vertices():
        for j in range(i + 1, G.num_verts()):
            if len(anc_dict[i].intersection(anc_dict[j])) > 0:
                G.add_edge((i, j))

    components = []
    for C in G.connected_components():
        normal_coords = [int(0) for i in range(3 * T.size())]
        quads = anc_dict[C[0]]
        for i in range(1, len(C)):
            quads = quads.union(anc_dict[C[i]])
        for (k, j) in quads:
            for i in range(3):
                if quads_matrix[k][i] != 0:
                    normal_coords[3 * k + i] += 1
        F = regina.NormalSurface(T, regina.NS_QUAD, normal_coords)
        components.append(F)

    return components
Beispiel #6
0
def orient(spun_normal_surface):
    S = spun_normal_surface
    T = S.triangulation()

    # We'll create a dictionary that keeps track of quad orientations wrt tets. For a given tet,
    # with k quads, the quads are numbered from 0 to k-1, with the 0th quad being the one that is closest
    # to vertex 0 of tet. Then oriented_quads[tet] is a list of length k whose i^th entry is +1 if the
    # orientation of the i^th quad agrees with the local orientation ("alignment"), and -1 if it disagrees.
    # At first, all entries are 0 to indicate that orientation is unknown (or really, not yet determined).

    abs_nbhds = abstract_nbhds(S)

    # abs_nbhds stores quads grouped according to the tetrahedron they are in. For below, it will be more
    # useful to store them according to which connected component of the intersection of the surface and
    # the abstract neighborhood they are in.
    abstract_comps = []
    for e in abs_nbhds:
        N = abs_nbhds[e]
        for comp in N['components']:
            Qs = [i for i in range(len(comp)) if comp[i] != -1]
            abstract_comps.append({
                'tets': [N['tets'][i] for i in Qs],
                'slopes': [N['slopes'][i] for i in Qs],
                'align': [N['align'][i] for i in Qs],
                'components': [comp[i] for i in Qs]
            })

    # iterator for assigning orientations to quads. See below.
    def iterate(comp, abstract_comps, oriented_quads, orientn_wrt_nbd=1):
        orientable = True

        # we iterate through the normal quadrilateral disks in the component comp,
        # triangular disks are skips because we have already removed them from comp
        for i in range(len(comp['tets'])):

            # set orientation of this quad with respect to the tet
            orientn_wrt_tet = comp['align'][i] * orientn_wrt_nbd

            # if the orientation of the quad is not already set in "oriented_quads",
            # then set it to orientation found above
            if oriented_quads[comp['tets'][i]][comp['components'][i]] == 0:
                oriented_quads[comp['tets'][i]][comp['components']
                                                [i]] = orientn_wrt_tet

            # if there is already an orientation on the quad set in "oriented_quads",
            # then make sure it matches the orientation found above. If it doesn't,
            # then set orientalbe to False, and break.
            else:
                if oriented_quads[comp['tets'][i]][comp['components']
                                                   [i]] != orientn_wrt_tet:
                    orientable = False
                    break

            # for each quad in comp, look for other components that it appears in, and add each
            # of them, along with the orientation comp induces on them, to the list "new_comps"
            new_comps = []
            for other_comp in abstract_comps:
                for j in range(len(other_comp['tets'])):
                    if comp['tets'][i] == other_comp['tets'][j] and comp[
                            'components'][i] == other_comp['components'][j]:
                        new_orientn_wrt_nbd = orientn_wrt_tet * other_comp[
                            'align'][j]
                        new_comps.append((other_comp, new_orientn_wrt_nbd))
                        break

            # remove from abstract_comps all the components we just added to new_comps
            for new_comp in new_comps:
                abstract_comps.remove(new_comp[0])

            # for each component in new_comps, run iterate again. If new_comps is empty, then
            # we have exhausted this connected component, so we return
            for new_comp in new_comps:
                abstract_comps, oriented_quads, orientable = iterate(
                    new_comp[0], abstract_comps, oriented_quads, new_comp[1])
                if not orientable:
                    return abstract_comps, oriented_quads, orientable
        return abstract_comps, oriented_quads, orientable

    # pick a first abstract component, and impose a transverse orientation. A transverse orientation is
    # induced on each quad in the component. For each of these quads, we search for all remaining abstract
    # components in which they appear, and give that component the orientation induced by the orientation
    # on the quad. Iterate until we run out of components, or until we come to a component where the
    # orientation induced by the quad that brought us there disagrees with the orientation of another quad
    # which has already been oriented (in which cases the surface is not orientable).
    oriented_quads_matrices = []
    while len(abstract_comps) > 0:
        # get a component. When we call iterate() below, we stay in this call to iterate
        # until we get orientations that are not compatible, or the component containing
        # comp is completely oriented.
        oriented_quads = {}
        for i in range(T.size()):
            num_quads = regina_to_sage_int(
                S.quads(i, 0) + S.quads(i, 1) + S.quads(i, 2))
            oriented_quads[i] = [0] * num_quads

        comp = abstract_comps.pop()
        abstract_comps, oriented_quads, orientable = iterate(
            comp, abstract_comps, oriented_quads)
        if not orientable:
            break

        # if orientable is still set to True, then this component is orientable, so we
        # compute the oriented_quads_mat for the component and store it in oriented_quads_matrices.
        if orientable:
            quads = quads_mat(S)
            emb_oriented_quads_mat = []
            for i in range(T.size()):
                row = []
                for j in [0, 1, 2]:
                    if quads[i][j] != 0:
                        pos = sum([k for k in oriented_quads[i] if k == 1])
                        neg = -sum([k for k in oriented_quads[i] if k == -1])
                        #assert pos+neg == quads[i][j]
                        row.append(pos)
                        row.append(neg)
                    else:
                        row.append(0)
                        row.append(0)
                emb_oriented_quads_mat.append(row)
            oriented_quads_matrices.append(Matrix(emb_oriented_quads_mat))
    if orientable:
        return oriented_quads_matrices
    else:
        return False