def operate_on(self, G): # Operates on the graph G by contracting an edge and unifying the adjacent vertices. image = [] for (i, e) in enumerate(G.edges(labels=False)): (u, v) = e # print("contract", u, v) pp = Shared.permute_to_left((u, v), range(0, self.domain.n_vertices)) sgn = self.domain.perm_sign(G, pp) G1 = copy(G) G1.relabel(pp, inplace=True) Shared.enumerate_edges(G1) previous_size = G1.size() G1.merge_vertices([0, 1]) if (previous_size - G1.size()) != 1: continue # print(sgn) G1.relabel(list(range(0, G1.order())), inplace=True) if not self.domain.even_edges: # p = [j for (a, b, j) in G1.edges()] # sgn *= Permutation(p).signature() sgn *= Shared.shifted_edge_perm_sign(G1) else: sgn *= -1 # TODO overall sign for even edges image.append((G1, sgn)) return image
def operate_on(self,G): # Operate on a hairy graph by deleting an edge and adding a hair to one of the vertices adjacent to the # deleted edge. sgn0 = -1 if G.order() % 2 else 1 image=[] for (i, e) in enumerate(G.edges(labels=False)): (u, v) = e # Only edges not connected to a hair-vertex can be cut if u >= self.domain.n_vertices or v >= self.domain.n_vertices: continue G1 = copy(G) if not self.domain.even_edges: Shared.enumerate_edges(G1) e_label = G1.edge_label(u, v) G1.delete_edge((u, v)) new_hair_idx = self.domain.n_vertices + self.domain.n_hairs G1.add_vertex(new_hair_idx) G2 = copy(G1) G1.add_edge((u, new_hair_idx)) G2.add_edge((v, new_hair_idx)) if not self.domain.even_edges: G1.set_edge_label(u, new_hair_idx, e_label) G2.set_edge_label(v, new_hair_idx, e_label) sgn1 = Shared.edge_perm_sign(G1) sgn2 = Shared.edge_perm_sign(G2) else: sgn1 = 1 sgn2 = -1 image.append((G1, sgn1*sgn0)) image.append((G2, sgn2*sgn0)) return image
def operate_on(self, G): # Operate on a bi colored hairy graph by deleting an edge and adding a hair of colour a to one of the adjacent # vertices and a hair of colour b to the other adjacent vertex. sgn0 = -1 if G.order() % 2 else 1 image = [] for (i, e) in enumerate(G.edges(labels=False)): (u, v) = e # Only edges not connected to a hair-vertex can be split. if u >= self.domain.n_vertices or v >= self.domain.n_vertices: continue G1 = copy(G) if not self.domain.even_edges: Shared.enumerate_edges(G1) e_label = G1.edge_label(u, v) G1.delete_edge((u, v)) new_hair_idx_1 = self.domain.n_vertices + self.domain.n_hairs new_hair_idx_2 = new_hair_idx_1 + 1 G1.add_vertex(new_hair_idx_1) G1.add_edge((u, new_hair_idx_1)) G1.add_vertex(new_hair_idx_2) G1.add_edge((v, new_hair_idx_2)) G2 = copy(G1) vertices = list(range(0, self.domain.n_vertices)) vertices = [] if vertices is None else vertices start_idx_a = self.domain.n_vertices start_idx_b = self.domain.n_vertices + self.domain.n_hairs_a + 1 hairs_a = list(range(start_idx_a + 1, start_idx_b)) hairs_a = [] if hairs_a is None else hairs_a hairs_b = list(range(start_idx_b, new_hair_idx_2)) hairs_b = [] if hairs_b is None else hairs_b p = vertices + hairs_a + hairs_b p1 = p + [start_idx_a, new_hair_idx_2] G1.relabel(p1) p2 = p + [new_hair_idx_2, start_idx_a] G2.relabel(p2) if not self.domain.even_edges: G1.set_edge_label(u, start_idx_a, e_label) G1.set_edge_label(v, new_hair_idx_2, G1.size() - 1) sgn1 = Shared.edge_perm_sign(G1) G2.set_edge_label(v, start_idx_a, e_label) G2.set_edge_label(u, new_hair_idx_2, G2.size() - 1) sgn2 = Shared.edge_perm_sign(G2) else: sgn1 = 1 sgn2 = -1 image.append((G1, sgn1 * sgn0)) image.append((G2, sgn2 * sgn0)) return image
def perm_sign(self, G, p): if self.even_edges: # The sign is (induced sign on vertices) * (induced sign edge orientations) sign = Shared.Perm(p).signature() for (u, v) in G.edges(labels=False): # We assume the edge is always directed from the larger to smaller index if (u < v and p[u] > p[v]) or (u > v and p[u] < p[v]): sign *= -1 return sign else: # The sign is (induced sign of the edge permutation) # We assume the edges are always lexicographically ordered # For the computation we use that G.edges() returns the edges in lex ordering # We first label the edges on a copy of G lexicographically G1 = copy(G) Shared.enumerate_edges(G1) # We permute the graph, and read of the new labels G1.relabel(p, inplace=True) return Shared.Perm([j for (u, v, j) in G1.edges()]).signature()
def operate_on(self,G): # Operates on the graph G by contracting an edge and unifying the adjacent vertices. image=[] for (i, e) in enumerate(G.edges(labels=False)): (u, v) = e # only edges not connected to a hair-vertex can be contracted if u >= self.domain.n_vertices or v >= self.domain.n_vertices: continue pp = Shared.permute_to_left((u, v), range(0, self.domain.n_vertices + self.domain.n_hairs)) sgn = self.domain.perm_sign(G, pp) G1 = copy(G) G1.relabel(pp, inplace=True) Shared.enumerate_edges(G1) previous_size = G1.size() G1.merge_vertices([0, 1]) if (previous_size - G1.size()) != 1: continue G1.relabel(list(range(0, G1.order())), inplace=True) if not self.domain.even_edges: sgn *= Shared.shifted_edge_perm_sign(G1) image.append((G1, sgn)) return image
def operate_on(self, G): # Operates on the graph G by contracting an edge and unifying the adjacent vertices. image = [] for (i, e) in enumerate(G.edges(labels=False)): (u, v) = e # only edges not connected to a numbered hair-vertex can be contracted if u >= self.domain.n_vertices + 2 or v >= self.domain.n_vertices + 2: continue # ensure u<v (this should be always true anyway actually) if u > v: u, v = v, u sgn = 1 if i % 2 == 0 else -1 previous_size = G.size() previous_has_tadpole = (previous_size - self.domain.n_vertices - self.domain.n_hairs < self.domain.n_loops) sgn *= -1 if previous_has_tadpole else 1 G1 = copy(G) # label all edges to determine sign later Shared.enumerate_edges(G1) # we always delete the lower index vertex. This ensures that the extra vertices are never deleted if v <= self.domain.n_vertices: G1.merge_vertices([v, u]) if (previous_size - G1.size()) != 1: continue G1.relabel(range( 0, self.domain.n_vertices + 1 + self.domain.n_hairs), inplace=True) # find edge permutation sign sgn *= Shared.shifted_edge_perm_sign2(G1) image.append((G1, sgn)) elif v == self.domain.n_vertices + 1: # the second vertex is now omega, so we need to merge the vertex with the eps vertex # after reonnecting one of the edges to omega # we assume that u != eps, because this is forbidden in our graphs G1.delete_edge(u, v) # special care must be taken since a tadpole could be created at eps # and this is true iff there is an edge u-eps eps = self.domain.n_vertices new_has_tadpole = G1.has_edge(u, eps) # double tadpole => zero if new_has_tadpole and previous_has_tadpole: continue if new_has_tadpole: # remove the edge and compute the appropriate sign k = G1.edge_label(u, eps) G1.delete_edge(u, eps) sgn *= 1 if ((k % 2 == 0) == (k < i)) else -1 # loop over other neighbors w to be connected to omega for w in G1.neighbors(u): G2 = copy(G1) sgn2 = sgn # reconnect the w-v-edge to omega (i.e., to v) old_label = G2.edge_label(u, w) G2.delete_edge(u, w) G2.add_edge(w, v, old_label) # now merge u and eps G2.merge_vertices([eps, u]) # in case we have too few edges some double edges have been created => zero if (previous_size - G2.size()) != (2 if new_has_tadpole else 1): continue G2.relabel(range( 0, self.domain.n_vertices + 1 + self.domain.n_hairs), inplace=True) # find edge permutation sign sgn2 *= Shared.shifted_edge_perm_sign2(G2) image.append((G2, sgn2)) return image