def check_neighbor_edge_correlation(self): """ Ensures there is a bijection between neighbors and edges of same type This method can be compatible with both the types of triangle. """ spacelike_edges = set([]) timelike_edges = set([]) for n in self.get_sst_neighbors(): shared_spacelike_edges = ut.set_intersection([n.spacelike_edges, self.spacelike_edges]) shared_timelike_edges = ut.set_intersection([n.timelike_edges, self.timelike_edges]) if len(shared_spacelike_edges) == 1 : spacelike_edges.add(list(shared_spacelike_edges)[0]) elif len(shared_timelike_edges) == 1 : timelike_edges.add(list(shared_timelike_edges)[0]) else: print(" Sorry, there is no shared edges of sst neigbors.") for n in self.get_tts_neighbors(): shared_spacelike_edges = ut.set_intersection([n.spacelike_edges, self.spacelike_edges]) shared_timelike_edges = ut.set_intersection([n.timelike_edges, self.timelike_edges]) if len(shared_spacelike_edges) == 1 : spacelike_edges.add(list(shared_spacelike_edges)[0]) elif len(shared_timelike_edges) == 1 : timelike_edges.add(list(shared_timelike_edges)[0]) else: print(" Sorry, there is no shared edges of tts_neighbors.") if spacelike_edges != self.spacelike_edges and timelike_edges != self.timelike_edges: print("\n Erroneous Triangle!\n") print(self) raise ValueError("Each neighbor doesnot share exactly 1 edges of same type")
def triangles_shared_with(self, other_instance_or_id): """ Tests to see whether self is a vertex of one of the same triangles as other. Other can be a vertex instance or a vertex ID. If triangles exist, returns them. Otherwise, returns false. """ # Parse input other = self.parse_input(other_instance_or_id) # The triangles shared with self: shared_sst_triangles = ut.set_intersection( [set(self.get_sst_triangles()), set(other.get_sst_triangles())]) shared_tts_triangles = ut.set_intersection( [set(self.get_tts_triangles()), set(other.get_tts_triangles())]) return shared_sst_triangles, shared_tts_triangles
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
def triangles_shared_with(self,other_instance_or_id): """ Tests to see whether self is a vertex of one of the same triangles as other. Other can be a vertex instance or a vertex ID. If triangles exist, returns them. Otherwise, returns false. """ # Parse input other = self.parse_input(other_instance_or_id) # The triangles shared with self: shared_triangles = ut.set_intersection([set(self.get_triangles()), set(other.get_triangles())]) return shared_triangles
def check_neighbor_edge_correlation(self): """ Ensures there is a bijection between neighbors and edges. """ edges = set([]) for n in self.get_neighbors(): shared_edges = ut.set_intersection([n.edges,self.edges]) if len(shared_edges) == 1: edges.add(list(shared_edges)[0]) if edges != self.edges: print "\nErroneous Triangle!\n" print self raise ValueError("Each neighbor does not share exactly 1 edge!")
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
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)