Esempio n. 1
0
class Tiling2D(object):
    def __init__(self, coxeter_diagram, init_dist):
        if len(coxeter_diagram) != 3 or len(init_dist) != 3:
            raise ValueError("Invalid input dimension")

        self.diagram = coxeter_diagram

        # Coxeter matrix and its rank
        self.cox_mat = helpers.make_symmetry_matrix(coxeter_diagram)
        self.rank = len(self.cox_mat)

        # generators of the symmetry group
        self.gens = tuple(range(self.rank))

        # symmetry group of this tiling
        self.G = CoxeterGroup(self.cox_mat)

        # a mirror is active iff the initial point is not on it
        self.active = tuple(bool(x) for x in init_dist)

        # reflection mirrors
        self.mirrors = self.get_mirrors(coxeter_diagram)

        # reflections (possibly affine) about the mirrors
        self.reflections = self.get_reflections()

        # coordinates of the initial point
        self.init_v = self.get_init_point(init_dist)

        # vertices of the fundamental triangle
        self.triangle_verts = self.get_fundamental_triangle_verts()

        # ----------------------
        # to be calculated later
        # ----------------------

        # holds the words in the symmetry group up to a given depth
        self.words = None

        # holds the coset representatives of the standard parabolic
        # subgroup of vertex-stabilizing subgroup
        self.vwords = None

        self.vertices_coords = []
        self.num_vertices = None
        self.num_edges = None
        self.num_faces = None
        self.edge_indices = {}
        self.face_indices = {}

    def vertex_at_mirrors(self, i, j):
        return 2 * (i + j) % 3

    def get_init_point(self, init_dist):
        raise NotImplementedError

    def get_mirrors(self, coxeter_diagram):
        raise NotImplementedError

    def get_fundamental_triangle_verts(self):
        raise NotImplementedError

    def build_geometry(self, depth=None, maxcount=20000):
        """Postpone the actual computations to this method.
        """
        self.G.init()
        self.words = tuple(self.G.traverse(depth, maxcount))
        self.get_vertices()
        self.get_edges()
        self.get_faces()
        return self

    def get_vertices(self):
        # generators of the vertex-stabilizing subgroup
        H = tuple(i for i, x in enumerate(self.active) if not x)
        # coset representatives of the vertex-stabilizing subgroup
        reps = set(self.G.get_coset_representative(w, H) for w in self.words)
        self.vwords = self.G.sort_words(reps)
        self.vtable = self.G.get_coset_table(self.vwords, H)
        self.num_vertices = len(self.vwords)
        self.vertices_coords = [
            self.transform(w, self.init_v) for w in self.vwords
        ]

    def get_edges(self):
        for i in self.gens:
            if self.active[i]:
                elist = []
                H = (i, )  # edge-stabilizing subgroup
                reps = set(
                    self.G.get_coset_representative(w, H) for w in self.words)
                reps = self.G.sort_words(reps)
                for word in reps:
                    v1 = self.G.move(self.vtable, 0, word)
                    v2 = self.G.move(self.vtable, 0, word + (i, ))
                    if v1 is not None and v2 is not None:
                        if (v1, v2) not in elist and (v2, v1) not in elist:
                            elist.append((v1, v2))

                self.edge_indices[i] = elist

        self.num_edges = sum(len(L) for L in self.edge_indices.values())

    def get_faces(self):
        for i, j in combinations(self.gens, 2):
            c0 = self.triangle_verts[self.vertex_at_mirrors(i, j)]
            f0 = []
            m = self.cox_mat[i][j]
            H = (i, j)
            type = 0
            if self.active[i] and self.active[j]:
                type = 1
                for k in range(m):
                    f0.append(self.G.move(self.vtable, 0, (i, j) * k))
                    f0.append(self.G.move(self.vtable, 0, (i, j) * k + (i, )))
            elif self.active[i] and m > 2:
                for k in range(m):
                    f0.append(self.G.move(self.vtable, 0, (j, i) * k))
            elif self.active[j] and m > 2:
                for k in range(m):
                    f0.append(self.G.move(self.vtable, 0, (i, j) * k))
            else:
                continue

            reps = set(
                self.G.get_coset_representative(w, H) for w in self.words)
            reps = self.G.sort_words(reps)
            flist = []
            for word in reps:
                f = tuple(self.G.move(self.vtable, v, word) for v in f0)
                if None not in f and not helpers.check_duplicate_face(
                        f, flist):
                    center = self.transform(word, c0)
                    coords = [self.vertices_coords[k] for k in f]
                    face = DihedralFace(word, f, center, coords, type)
                    flist.append(face)

            self.face_indices[(i, j)] = flist

        self.num_faces = sum(len(L) for L in self.face_indices.values())

    def get_reflections(self):
        def reflect(v, normal):
            return v - 2 * np.dot(v, normal) * normal

        return [partial(reflect, normal=n) for n in self.mirrors]

    def transform(self, word, v):
        for w in reversed(word):
            v = self.reflections[w](v)
        return v

    def get_info(self):
        """Return some statistics of the tiling.
        """
        pattern = "{}-{}-{}".format(*self.diagram).replace("/", "|")
        info = ""
        info += "name: triangle group {}\n".format(pattern)
        info += "cox_mat: {}\n".format(self.cox_mat)
        info += "vertices: {}\n".format(self.num_vertices)
        info += "edges: {}\n".format(self.num_edges)
        info += "faces: {}\n".format(self.num_faces)
        info += "states in the automaton: {}\n".format(self.G.dfa.num_states)
        info += "reflection table:\n{}\n".format(self.G.reftable)
        info += "the automaton is saved as {}_dfa.png".format(pattern)
        self.G.dfa.draw(pattern + "_dfa.png")
        return info

    def render(self, *arg, **kwargs):
        raise NotImplementedError
Esempio n. 2
0
class UniformTiling(object):
    def __init__(self, coxeter_diagram, init_dist):
        self.cox_mat = helpers.get_coxeter_matrix(coxeter_diagram)
        self.G = CoxeterGroup(self.cox_mat)
        self.active = tuple(bool(x) for x in init_dist)
        self.words = None

        self.mirrors = self.get_mirrors(coxeter_diagram)
        self.init_v = helpers.get_point_from_distance(self.mirrors, init_dist)
        self.reflections = self.get_reflections(init_dist)

        # to be calculated later
        self.vertices_coords = []
        self.num_vertices = None
        self.num_edges = None
        self.num_faces = None
        self.edge_indices = {}
        self.face_indices = {}

    def build_geometry(self, depth=None, maxcount=20000):
        self.G.init()
        self.words = tuple(self.G.traverse(depth, maxcount))
        self.get_vertices()
        self.get_edges()
        self.get_faces()

    def get_vertices(self):
        parabolic = tuple(i for i, x in enumerate(self.active) if not x)
        coset_reps = set([
            self.G.get_coset_representative(w, parabolic, True)
            for w in self.words
        ])
        self.vwords = self.G.sort_words(coset_reps)
        self.vtable = self.G.get_coset_table(self.vwords, parabolic)
        self.num_vertices = len(self.vwords)
        self.vertices_coords = [
            self.transform(word, self.init_v) for word in self.vwords
        ]

    def get_edges(self):
        for i in range(len(self.active)):
            if self.active[i]:
                elist = []
                coset_reps = set([
                    self.G.get_coset_representative(w, (i, ), True)
                    for w in self.words
                ])
                for word in self.G.sort_words(coset_reps):
                    v1 = self.G.move(self.vtable, 0, word)
                    v2 = self.G.move(self.vtable, 0, word + (i, ))
                    if v1 is not None and v2 is not None:
                        if (v1, v2) not in elist and (v2, v1) not in elist:
                            elist.append((v1, v2))

                self.edge_indices[i] = elist

        self.num_edges = sum(len(L) for L in self.edge_indices.values())

    def get_faces(self):
        for i, j in combinations(range(len(self.active)), 2):
            f0 = []
            m = self.cox_mat[i][j]
            parabolic = (i, j)
            if self.active[i] and self.active[j]:
                for k in range(m):
                    f0.append(self.G.move(self.vtable, 0, (i, j) * k))
                    f0.append(self.G.move(self.vtable, 0, (i, j) * k + (i, )))
            elif self.active[i] and m > 2:
                for k in range(m):
                    f0.append(self.G.move(self.vtable, 0, (j, i) * k))
            elif self.active[j] and m > 2:
                for k in range(m):
                    f0.append(self.G.move(self.vtable, 0, (i, j) * k))
            else:
                continue

            coset_reps = set([
                self.G.get_coset_representative(w, parabolic, True)
                for w in self.words
            ])
            flist = []
            for word in self.G.sort_words(coset_reps):
                f = tuple(self.G.move(self.vtable, v, word) for v in f0)
                if None not in f and not helpers.check_duplicate_face(
                        f, flist):
                    flist.append(f)

            self.face_indices[(i, j)] = flist

        self.num_faces = sum(len(L) for L in self.face_indices.values())

    def transform(self, word, v):
        for w in reversed(word):
            v = self.reflections[w](v)
        return v

    def get_reflections(self, init_dist):
        raise NotImplementedError

    def get_fundamental_triangle_vertices(self):
        raise NotImplementedError

    def project(self, v):
        raise NotImplementedError

    def get_mirrors(self, coxeter_diagram):
        raise NotImplementedError