def remove(self, vertices): """Remove vertices from the graph.""" if not vertices in self.vertices: raise ValueError('Graph don\'t contain some of [{}]'.format(vertices)) for v in iterate(vertices): for w in iterate(self(v)): self.disconnect(v, w) self._vertices -= vertices for v in iterate(vertices): del self.neighborhoods[v]
def generate_random(nr_vertices, nr_edges=0): if not 0 <= nr_edges <= nr_vertices * (nr_vertices - 1) / 2: raise ValueError if not nr_edges: nr_edges = 0.5 graph = Graph() graph.add(bits(*range(nr_vertices))) if nr_edges < 1: # Add random edges between groups for v in graph: for w in graph: if v < w and random() < nr_edges: graph.connect(v, w) return graph else: vertex_list = list(iterate(graph.vertices)) for _ in range(nr_edges): while 1: v, w = sample(vertex_list, 2) # Don't connect vertices twice if not w in graph[v]: break graph.connect(v, w) return graph
def __call__(self, vertices): """Return the union of neighborhoods of vertices.""" result = 0 for v in iterate(vertices): result = result | self.neighborhoods[v] #result |= self.neighborhoods[v] return result
def components(graph): """Return a list of the connected components of in the graph.""" done = 0 for v in iterate(graph.vertices): if contains(done, v): continue component = sum(bfs(graph, v)) yield component done |= component
def add(self, vertices): """Add new vertices to the graph.""" assert isinstance(vertices, int) if not disjoint(self.vertices, vertices): raise ValueError('Graph already contain some of [{}]'.format(vertices)) self._vertices |= vertices for v in iterate(vertices): self.neighborhoods[v] = 0
def greedy_step(G, left, right, un_left, booldim_left, un_table, bound): best_vertex = None best_booldim = Infinity best_un = None if size(right) == 1: return right, {0}, 1 assert size(right) > 1 candidates = get_neighborhood_2(G.neighborhoods, left) & right # Trivial cases are slow for v in iterate(candidates): if trivial_case(G.neighborhoods, left, right, v): new_un = increment_un(G, left, un_left, v) new_booldim = len(new_un) return v, new_un, new_booldim for v in iterate(candidates): if left | v not in un_table: un_table[left | v] = increment_un(G, left, un_left, v) new_un = un_table[left | v] new_booldim = len(new_un) # Apply pruning if new_booldim >= bound: # print('pruning') continue if new_booldim < best_booldim: best_vertex = v best_booldim = new_booldim best_un = new_un # If nothing found if best_vertex == None: best_un = increment_un(G, left, un_left, v) best_booldim = len(best_un) best_vertex = v assert best_vertex != None return best_vertex, best_un, best_booldim
def is_word_in_graph(word: str, graph, last_vertex=0, forbidden_vertices=0): if not word: return True letter = word[0] candidates = graph.letters_to_vertices[letter] | graph.letters_to_vertices['.'] candidates = subtract(candidates, forbidden_vertices) if last_vertex: candidates &= graph.neighborhoods[last_vertex] return any(is_word_in_graph(word[1:], graph, v, forbidden_vertices | v) for v in iterate(candidates))
def is_word_in_graph(word: str, graph): if not word: return False letter = word[0] candidates = (graph.letters_to_vertices[letter] if letter in graph.letters_to_vertices else 0) if not candidates: return False return any(recurse(word[1:], graph, v, v) for v in iterate(candidates))
def trivial_case(N, left, right, v): # No neighbors if contains(left, N[v]): return True # Twins for u in iterate(left): if N[v] & right == subtract(N[u], v) & right: return True return False
def contract(self, v): """Contract a vertex.""" if not v in self: raise ValueError neighbors = list(iterate(self(v))) self.remove(v) for w1 in neighbors: for w2 in neighbors: if w1 < w2 and not w1 in self[w2]: self.connect(w1, w2)
def recurse(word: str, graph, last_vertex, forbidden): if not word: return True letter = word[0] if letter not in graph.letters_to_vertices: return False candidates = subtract(graph.letters_to_vertices[letter] & graph.neighborhoods[last_vertex], forbidden) if not candidates: return False return any(recurse(word[1:], graph, v, forbidden | v) for v in iterate(candidates))
def heuristic(graph): subset = 0 while is_independent(graph, subset): # Find valid vertex with the least new neighbors existing_neighbors = graph(subset) min_new_neighbors = Infinity new_vertex = None for v in iterate(subtract(graph.vertices, subset)): if not graph(v) & subset: new_neighbors = subtract(graph(v), existing_neighbors) if size(new_neighbors) < min_new_neighbors: min_new_neighbors = size(new_neighbors) new_vertex = v if new_vertex == None: return subset else: subset |= new_vertex
def verify_symmetry(self): for v in self: for w in iterate(self(v)): assert v in self(w)
def get_neighborhood_2(N, subset): result = get_neighborhood(N, subset) for v in iterate(result): result |= N[v] return result
def edges(self): """Iterate over each pair of connected vertices exactly once.""" for v in self: for w in iterate(self(v)): if w < v: yield v, w
def is_independent(graph, subset): for v in iterate(subset): for w in iterate(subset): if v > w and graph(v) & w: return False return True
def get_neighborhood(N, subset): result = 0 for v in iterate(subset): result |= N[v] return result
def __iter__(self): """Iterate over all vertices.""" return iterate(self.vertices)
def __repr__(self): return 'vertices: {}'.format(list(iterate(self.vertices)))