Example #1
0
	def check_edge_validity(self): 
		"""
		Checks to make sure that the number of endpoints of edges is
		the same as the number of vertices.
		"""
		spacelike_edges = self.get_spacelike_edges()
		timelike_edges = self.get_timelike_edges()
		spacelike_endpoints = [e.get_vertex_ids() for e in spacelike_edges]
		timelike_endpoints = [e.get_vertex_ids() for e in timelike_edges]
		spacelike_endpoint_union = ut.set_union(spacelike_endpoints)
		timelike_endpoint_union = ut.set_union(timelike_endpoints)
		endpoint_union = spacelike_endpoint_union.union(timelike_endpoint_union)
		assert endpoint_union == self.get_vertex_ids()
Example #2
0
 def check_edge_validity(self):
     """
     Checks to make sure that the number of endpoints of edges is
     the same as the number of vertices.
     """
     edges = self.get_edges()
     endpoints = [e.get_vertex_ids() for e in edges]
     endpoint_union = ut.set_union([e.get_vertex_ids() for e in edges])
     assert endpoint_union == self.get_vertex_ids()
Example #3
0
    def extract_vertices(self):
        """
		Extract the vertices from two triangles.
		"""
        # Boundary of two triangles
        endpoints = self.extract_timelike_edges()
        # Extracted all the vertices of all the timelike edges.
        extracted_vertices_ids = ut.set_union(
            [e.get_vertex_ids() for e in endpoints])
        extracted_vertices = [
            vertex.instances[i] for i in extracted_vertices_ids
        ]
        return extracted_vertices
Example #4
0
def build_triangle_and_edges(edge_list):
    """
	ONLY USEFUL AT INITIALIZATION. AND USES TTS TRIANGLE

	Builds a triangle by creating the triangle object. 
	"""
    # local constants
    triangle_length = 3  # Total no. of edges in a triangle.

    # Make sure we actually have a collection of 3 triangle edges.
    assert len(edge_list) == triangle_length

    # Make a sets of points that is belongs to a triangle.
    points = ut.set_union(edge_list)

    #Make sure we actually have a collection of 3 triangle vertices.
    assert len(points) == triangle_length

    # Generate a list of point ids.
    points = [vertex.parse_input(t).get_id() for t in points]

    # Type-cast to eliminate duplicates.
    vertices = set(points)

    # Build the timelike and spacelike edges contained by triangle of any
    # and return their ids.
    # build_sub_edges_of_triangle runs some error checking too.
    timelike_edge_ids, spacelike_edge_ids = build_sub_edges_of_triangle(
        edge_list)

    # RIGHT NOW, WE ARE ONLY USING TTS TRIANGLE FOR INTIALIZATION OF OUR LATTICE
    # Check to see if the triangle we want to build already exists.
    tts_duplicates = tts_triangle.find_duplicates(vertices, spacelike_edge_ids,
                                                  timelike_edge_ids)

    # If there is one duplicate, work with it. If there is more than
    # one, raise an error. If there are no duplicates, make that
    # triangle!
    if len(tts_duplicates) == 0:
        # Make a triangle of tts type:
        t = tts_triangle(vertices, spacelike_edge_ids, timelike_edge_ids)
        tts_triangle_id = t.id  # Ensure we have the id for this triangle
        tts_triangle.add(t)  # Add this triangle to its hash table
    elif len(tts_duplicates) == 1:
        triangle_id = tts_duplicates[0]  # The id for our triangle
    else:  #If len(tts_duplicates)>1, something went very wrong.
        assert error.checking.too_many_duplicates('tts_triangle', vertices,
                                                  tts_duplicates, 1,
                                                  'build_triangle_and_edges')

    return tts_triangle_id
Example #5
0
File: moves.py Project: raylee/CDT
def complex_3_to_1(simplex_id_or_simplex):
    """
    Takes a simplex or simplex id as input and calculates what, if
    any, complices are topologically acceptable to operate on.

    The 3->1 move requires a vertex that is attached to 3
    simplices. There is a slight danger that volume decreasing moves
    can make a system topologically unacceptable. If this is the case,
    then the function returns False.

    If there is more than one acceptable complex, returns one at
    random.
    """
    volume_decrease = 2
    if not check_area_decreasing_validity(volume_decrease):
        return False

    # Extract triangle
    triangle = extract_triangle(simplex_id_or_simplex)

    # Extract vertices
    vertices = triangle.get_vertices()

    # If a vertex has only three triangles, consider it
    ids = lambda x: x.get_triangle_ids() # For convenience
    possibilities = [ids(v) for v in vertices if len(ids(v)) == 3]
    
    # Each boundary point on a possible complex must be attached to at
    # least 4 triangles
    # Function to extract vertex class objects from a triangle id
    obj = lambda i: sd.triangle.instances[i].get_vertices()
    # function to extract the boundary points of a complex possibility
    boundaries = lambda c: ut.set_union([set(obj(t)) for t in c]) \
        - ut.set_intersection([set(obj(t)) for t in c])
    # Function that tells us if every boundary vertex of a possibility
    # is connected to greater than 3 simplex
    acceptable = lambda p: len([b for b in boundaries(p) if len(b) > 3]) == 3

    # Only accept a possibility if each boundary vertex has 4 or more
    # triangles.
    complices = [complex(p) for p in possibilities if acceptable(p)]

    if len(complices) == 1:
        return complices[0]
    elif len(complices) > 1:
        return random.choice(complices)
    else:
        return False
Example #6
0
File: moves.py Project: raylee/CDT
def move_3_to_1(cmpx):
    "Applies a 3->1 move to the input complex, cmpx."

    # Extract the complex, which contains three triangles.
    if len(cmpx.get_triangles()) == 3:
        original_triangles = [sd.triangle.instances[i] \
                                  for i in cmpx.get_triangles()]
    else:
        raise ValueError("There should be exactly 3 triangles for the " +
                         "3->1 complex.")

    # Extract the boundary vertices
    original_vertices = [set(t.get_vertices()) for t in original_triangles]
    central_vertex = list(ut.set_intersection(original_vertices))[0]
    boundary_vertices = ut.set_union(original_vertices) \
        - set([central_vertex])
    boundary_vertex_ids = [v.get_id() for v in boundary_vertices]

    # Extract the edges to be removed (there are 3)
    # Lambda functions for clarity
    get_edges = lambda i: set(sd.triangle.instances[i].get_edges())
    intersected_element = lambda L: ut.only_element(ut.set_intersection(L))
    # Nested list comprehensions: take the intersection of the set of
    # edges associated with pairs of the triangles we care
    # about. These edges are flagged for deleteion.
    shared_edges = [intersected_element([get_edges(i) for i in c]) \
                        for c in ut.k_combinations(cmpx.get_triangles())]
    # There should only be 3 shared edges. If there are more, we messed up.
    assert len(shared_edges) == 3
    
    # Make the new triangle
    new_triangle = sm.build_triangle_and_edges(boundary_vertex_ids)

    # Clean up
    for t in original_triangles: # Delete the old triangles:
        sm.remove_triangle(t)
    for e in shared_edges: # Delete the old edges.
        sm.remove_edge(e)
    sd.vertex.delete(central_vertex) # Delete the old vertex

    # Set triangles, neihgbors, and check topology
    set_neighbors_and_triangles(boundary_vertices,[new_triangle])

    return True
Example #7
0
def find_opposite_vertices_in_complex(triangle_complex):
    """
    Similar to find_opposite_vertices, but looks vertices that don't
    share a triangle contained in the triangle complex.
    """
    # Parse input
    triangle_objects = set([sd.triangle.parse_input(t) \
                                for t in triangle_complex])
    # Extract vertices
    vertices = ut.set_union([set(t.get_vertices()) for t in triangle_objects])
    # Vertices that don't share triangles are:
    shared = [set([v1,v2]) for v1 in vertices for v2 in vertices\
                  if not shares_triangles_in_complex(v1,v2,triangle_objects)]
    # Filter out duplicates
    filtered = []
    for vertex_pair in shared:
        if vertex_pair not in filtered:
            filtered.append(vertex_pair)

    return filtered
Example #8
0
def find_opposite_vertices(triangle_set):
    """ 
    A function that looks for a pair of vertices in a set of triangles
    that don't share a triangle. Returns all such vertex pairs. Takes
    ids or instances as input. But only takes collections.
    """
    # Parse input
    triangle_objects = set([sd.triangle.parse_input(t) for t in triangle_set])
    # Extract vertices
    vertices = ut.set_union([set(t.get_vertices()) for t in triangle_objects])
    # Finds pairs of vertices that don't share a triangle
    opposite_vertices = [set([v1,v2]) for v1 in vertices \
                             for v2 in vertices \
                             if not v1.shares_a_triangle_with(v2)]
    # We need to remove duplicates from the list of opposite vertices
    for vertex_pair in opposite_vertices:
        if vertex_pair not in filtered_vertices:
            filtered_vertices.append(vertex_pair)

    return filtered_vertices
Example #9
0
File: output.py Project: raylee/CDT
def reindex_sphere_data_list(sphere_data_list):
    """
    Takes an input list of the form [set([v1,v2,v3]),...] and ensures
    that the list of vertices has no hooes. i.e., if the maximum
    vertex id is n, then the set of vertices is
    set(range(1,n+1)). Returns a reindex list. Used for output so that
    the boundary file contains a list we can give to
    2p1-fixed-boundaries as a boundary.
    """
    # Generate a sorted list of all the vertex ids. The reindexed id
    # of each vertex is just the id of the vertex in the list.
    vertex_ids = list(ut.set_union(sphere_data_list))
    vertex_ids.sort()
    # It's troublesome to find the index of the id in the list this
    # way. A better data structure is a dictionary:
    reindexing_scheme = {v: vertex_ids.index(v) + 1 for v in vertex_ids}
    # We can now reconstruct our reindexed list by mapping v to
    # reindexing_scheme[v]
    sphere_data_list = [set([reindexing_scheme[v] for v in s]) for s in sphere_data_list]
    return sphere_data_list
Example #10
0
File: moves.py Project: raylee/CDT
def try_3_to_1(simplex_id_or_simplex):
    """
    Tries a 3->1 move and returns the move data that the metropolis
    algorithm will use to decide whether or not to accept the move. If
    the move is simply not topologically acceptable, returns false.
    """
    # The complex
    cmpx = complex_3_to_1(simplex_id_or_simplex)
    
    # If there are no topologically acceptable complices, stop right
    # now and return False. Otherwise, extract the triangles.
    if cmpx:
        triangles = cmpx.get_triangles()
    else:
        return False

    # Now that we have the triangle, extract the list of points of
    # each triangle.
    old_vertices = [sd.triangle.instances[t].get_vertices() \
                        for t in triangles]
    # The central vertex is the intersection of all the vertices in
    # the old triangles
    central_vertex = ut.set_intersection([set(t) for t in old_vertices])
    # The boundary vertices are the union of the vertices of the old
    # triangles minus the intersection:
    boundary_vertices = ut.set_union([set(t) for t in old_vertices]) \
        - central_vertex

    # We're removing the central vertex, but each boundary vertex will
    # be attached to 1 fewer triangle.
    
    # "Replace" the 3 original vertices
    removed_vertices = [st.imaginary_vertex(len(v),False) \
                            for v in boundary_vertices]
    added_vertices = [st.imaginary_vertex(len(v)-1,True) \
                          for v in boundary_vertices]
    # "Remove" the center vertex
    removed_vertices.append(st.imaginary_vertex(3,False))

    return st.move_data(removed_vertices + added_vertices,cmpx,
                        move_3_to_1,-2)
Example #11
0
def build_sphere_from_data(sphere_data):
    """
    sphere_data should be a list of sets, each with 3 points in
    it. Resets the sphere and then builds it from this data.
    """
    # First we need to check that sphere_data is what we want.
    for s in sphere_data:
        if not (type(s) == set and len(s) == 3):
            raise TypeError("Sphere data needs to be a list of sets, "
                            +"each of length 3!")
        for i in s:
            if not (type(i) == int and i > 0):
                raise TypeError("The vertices must all be "
                                +"positive integers!")

    # The vertices in existence will be the union of the triangle
    # point lists:
    vertex_ids = ut.set_union(sphere_data)
    # The last used vertex id is the maximum of the vertex ids
    last_used_vertex_id = max(vertex_ids)

    # make sure there are no vertices are missing (print sphere to
    # file shouldn't let there be any)
    assert set(range(1,last_used_vertex_id+1)) - vertex_ids == set([])

    # Once we're sure the set is what we want, we need to make sure no
    # sphere is currently initialized.
    sm.delete_all_geometries()
    # Make the points we need
    sm.make_n_vertices(last_used_vertex_id)
    # Ensure the points we made are the points in our list
    assert set(vertex.instances.keys()) == vertex_ids

    # Make the triangles we need out of the points.
    triangle_ids = [sm.build_triangle_and_edges(t) for t in sphere_data]

    # Connect all the triangles and tell points what triangles contain them
    connect_all_triangles()

    return triangle_ids
Example #12
0
File: moves.py Project: raylee/CDT
def move_1_to_3(cmpx):
    "Applies a 1->3 move to the input complex, cmpx."
    # Extract the single triangle required for this move.
    if len(cmpx.get_triangles()) == 1:
        triangle_id = list(cmpx.get_triangles())[0]
    else:
        raise ValueError("There should be only one "+
                         "triangle for the 1->3 complex.")
    triangle = sd.triangle.instances[triangle_id]

    # Vertices
    original_vertices = triangle.get_vertices()
    
    # Edges 
    original_edges = triangle.get_edges()

    # Endpoints of edges
    endpoints = [e.get_vertex_ids() for e in original_edges]

    # Make the point that will trisect the triangle
    v = sd.vertex()
    sd.vertex.add(v)

    # Generate the vertices for the three new triangles to be created
    vertex_list = [points | set([v.get_id()]) for points in endpoints]
    
    # Make the new triangles
    new_triangles = [sm.build_triangle_and_edges(tri) for tri in vertex_list]

    # Delete the old triangle
    sm.remove_triangle(triangle)

    # Set neighbors, triangles for each vertex, and do some error checking
    vertex_ids = ut.set_union(vertex_list)
    vertices = [sd.vertex.instances[i] for i in vertex_ids]
    set_neighbors_and_triangles(vertices,new_triangles)

    return True
Example #13
0
File: moves.py Project: raylee/CDT
def complex_2_to_2(simplex_id_or_simplex):
    """
    Takes a simplex or simplex id as input and calculates what, if
    any, complices are topologically acceptable to operate on. If
    there's more than one, return one at random. If there are none,
    return False.

    The 2->2 move equires that the new edge not already exist (there
    are cases when it does) and that the endpoints of the deleted edge
    each have >=4 triangles attached to them before the move is
    applied.
    """
    # Declare local constants
    pair_length = 2 # The length of a pair 
    neighbor_length = 3 # The number of vertices a triangle must have.

    # Extract data for the first triangle
    # Extract triangle
    t1 = extract_triangle(simplex_id_or_simplex)
    # Extract neighbors
    t1_neighbors = t1.get_neighbors()
    # Extract vertices
    t1_vertices = t1.get_vertices()

    # If we can find a pair of vertices of t1 that each have >=4
    # triangles attached, then these vertices might be good choices of
    # endpoints for the edge we will delete.
    possible_endpoints = [v for v in t1_vertices if len(v) >= 4]

    # If there are fewer than two possible endpoints, no acceptable
    # edge exists, so me might as well give up.
    if len(possible_endpoints) < 2:
        return False
    else: # If >=2 possible endpoints exist, get all possible pairs:
        possible_endpoint_pairs = ut.k_combinations(possible_endpoints,2)
    
    # The other triangle in the complex will be the neighbor that
    # shares the chosen pair of of endpoint vertices. We want to keep
    # track of which pair this is associated with.
    acceptable_neighbors = [(p,n) for p in possible_endpoint_pairs \
                                for n in t1_neighbors \
                                if p.issubset(n.get_vertices())]

    # We will be making an edge between the unshared vertices of the
    # two neighboring triangles. We have to make sure that this edge
    # does not yet exist. 

    # A function to calculate the unshared vertices as a pair. Just
    # syntactic sugar.
    unshared_v = lambda p,n: ut.set_union([set(t1.get_vertices()),
                                           set(n.get_vertices())]) - set(p)
    # An acceptable complex has a pair of shared points, a neighbor,
    # and a pair of unshared points which are not the endpoints of an
    # existing edge.
    acceptable_cmpxs = [(p,n,unshared_v(p,n))\
                             for (p,n) in acceptable_neighbors \
                             if not sd.edge.exists(unshared_v(p,n))]

    # Double check to make sure we have what we expect.
    acceptable_cmpxs = [(p,n,u) for (p,n,u) in acceptable_cmpxs \
                            if len(p) == pair_length\
                            and len(n) == neighbor_length\
                            and len(u) == pair_length]

    # We have everything. If it exists, stick it in a complex and
    # return it. Otherwise, return false.
    if acceptable_cmpxs:
        chosen_complex = random.choice(acceptable_cmpxs)
        triangles = [t1,chosen_complex[1]]
        shared_vertices = chosen_complex[0]
        unshared_vertices = chosen_complex[2]
        cmpx = complex22(triangles)
        cmpx.set_shared_vertices(shared_vertices)
        cmpx.set_unshared_vertices(unshared_vertices)
        return cmpx
    else:
        return False