def blockForest(self): bf = SimpleGraph() vertexmap = {} # vertex: vertex in block forest articulations = set() # separators mapped to block forest for sv in self._separators: av = bf.pushVertex() articulations.add(av) vertexmap[sv] = av for bc_k, bc in self._biconComponents.items(): seps = self._separatorMap[bc_k] if len(bc) == 2 and len(seps) == 2: it = iter(bc) bf.addEdge(vertexmap[next(it)], vertexmap[next(it)]) else: bcv = bf.pushVertex() for v in bc - seps: vertexmap[v] = bcv for sv in seps: bf.addEdge(bcv, vertexmap[sv]) return bf, vertexmap, articulations
def _build4by4(): # makes a grid structure like: # 0 - 1 - 2 - 3 # ! ! ! ! # 4 - 5 - 6 - 7 # ! ! ! ! # 8 - 9 - 10- 11 # ! ! ! ! # 12- 13- 14- 15 g = SimpleGraph() g.addVertices(range(16)) for k in range(0, 16, 4): for i in range(k, k + 3): g.addEdge(i, i + 1) for k in range(4): for i in range(k, 12, 4): g.addEdge(i, i + 4) for i in [0, 3, 12, 15]: assert g.degree(i) == 2 for i in [1, 2, 7, 11, 14, 13, 8, 4]: assert g.degree(i) == 3 for i in [5, 6, 9, 10]: assert g.degree(i) == 4 return g
class GraphOntoRectangularGrid(object): """ Locations in the grid are tuples (x, y), 0-based. Each vertex maps to one grid location. It is possible for a grid location to map to multiple vertices. """ def __init__(self, width, height=None): height = height or width assert width > 0 and height > 0 self._width = width self._height = height self._graph = SimpleGraph() self._locationMap = {} # vertex : location for x, y in product(range(self._width), range(self._height)): v = self.pushVertex((x, y)) if x > 0: self._graph.addEdge(v, self.singleVertexAt((x - 1, y))) if y > 0: self._graph.addEdge(v, self.singleVertexAt((x, y - 1))) @property def width(self): return self._width @property def height(self): return self._height @property def graph(self): return self._graph.asReadOnly() def getLocationMap(self): return dict((v, tuple(c)) for v, c in self._locationMap.items()) def pushVertex(self, xy): x, y = xy assert 0 <= x < self._width assert 0 <= y < self._height v = self._graph.pushVertex() self._locationMap[v] = xy return v def removeVertex(self, v): self._graph.removeVertex(v) del self._locationMap[v] def removeVertexAt(self, xy): self.removeVertex(self.singleVertexAt(xy)) def addEdge(self, v1, v2): self._graph.addEdge(v1, v2) def removeUniqueEdge(self, xy1, xy2): v1, v2 = map(self.singleVertexAt, (xy1, xy2)) self._graph.removeEdge(v1, v2) def verticesAt(self, xy): """Get the set of any/all vertices mapped to location.""" return set(k for k, v in self._locationMap.items() if v == xy) def singleVertexAt(self, xy): """Get the single vertex mapped to location. Error if not 1-to-1.""" v = self.verticesAt(xy) assert len(v) == 1 return v.pop() def adjacenciesAt(self, xy): return self._graph.adjacencies(self.singleVertexAt(xy)) def orthogonalAdjacencies(self, xy): x, y = xy a = self.adjacenciesAt(xy) xa = a & (self.verticesAt((x - 1, y)) | self.verticesAt((x + 1, y))) ya = a & (self.verticesAt((x, y - 1)) | self.verticesAt((x, y + 1))) return xa, ya
def _testMatching(): g = SimpleGraph() verts = list(range(7)) g.addVertices(verts) assert g.isMatching() g.addEdge(0, 1) assert g.isMatching() g.addEdge(1, 2) assert not g.isMatching() g.addEdge(2, 3) g.addEdge(4, 5) assert not g.isMatching() g.removeEdge(1, 2) assert g.isMatching() assert not g.isPerfectMatching() g.addEdge(6, g.pushVertex()) assert g.isPerfectMatching() g = _build4by4() assert not g.isMatching() assert g.maximumMatching().isPerfectMatching() v_a = g.pushVertex() g.addEdge(0, v_a) m = g.maximumMatching() assert m.isMatching() assert not m.isPerfectMatching() v_b = g.pushVertex() g.addEdge(v_a, v_b) assert g.maximumMatching().isPerfectMatching() g.addEdge(v_b, 4) assert g.maximumMatching().isPerfectMatching() g = SimpleGraph() A = _makeChain(g, 9) assert not g.isCycle(A) assert g.maximumMatching().edgeCount() == 4 g.addEdge(A[0], A[-1]) assert g.isCycle(A) assert g.maximumMatching().edgeCount() == 4 hub = g.pushVertex() for Av in A: g.addEdge(hub, Av) assert g.maximumMatching().isPerfectMatching() for Av in A: g.addEdge(Av, _makeLoop(g, 5)[0]) assert not g.maximumMatching().isPerfectMatching() g.removeVertex(hub) assert g.maximumMatching().isPerfectMatching() g = _build4by4() g.removeVertices([4, 8, 3, 15]) assert g.maximumMatching().isPerfectMatching()
def _testGraph(): g = SimpleGraph() assert isinstance(g, QueryableSimpleGraph) assert not isinstance(g.asReadOnly(), SimpleGraph) assert isinstance(g.asReadOnly(), QueryableSimpleGraph) g.assertSimple() verts = [] for i in range(10): verts.append(g.pushVertex()) try: g.addVertex(verts[0]) raise AssertionError except ValueError: pass assert len(set(verts)) == len(verts) for v in verts: assert not g.adjacencies(v) assert g.connectedComponent(v) == {v} assert not g.isSeparator(v) assert g.isConnectedSet([v]) parts = g.disjointPartitions() assert len(parts) == len(verts) s = set() for p in parts: assert len(p) == 1 s.add(p.pop()) assert s == set(verts) edgeCount = 0 assert g.edgeCount() == edgeCount assert g.edgeCount(without=set()) == g.edgeCount() for i in range(len(verts) - 1): edgeCount += 1 g.addEdge(verts[i], verts[i + 1]) for v in verts[i + 2:]: assert not g.connected(verts[i + 1], v) assert not g.connected(v, verts[i + 1]) for j in range(i + 1): if j > 0: assert g.connected(verts[0], verts[j]) assert g.connected(verts[j], verts[0]) assert g.connectedComponent(verts[j]) == set(verts[:i + 2]) assert g.edgeCount() == edgeCount assert g.edgeCount(without=set()) == g.edgeCount() assert g.edgeCount(mask=verts) == g.edgeCount() for v in verts: assert g.edgeCount(mask={v}) == 0 assert g.connectedComponent(v) == set(verts) assert g.isConnectedSet(verts) assert g.isConnectedSet([verts[2], verts[4]], verts[2:5]) assert not g.isConnectedSet([verts[2], verts[4]], [verts[2], verts[4]]) assert g.isConnectedSet(verts[:4] + verts[5:]) assert not g.isConnectedSet(verts[:4] + verts[5:], verts[:4] + verts[5:]) assert not g.isSeparator(verts[0]) assert not g.isSeparator(verts[-1]) assert all(g.isSeparator(v) for v in verts[1:-1]) assert g.shortestPath(verts[0], verts[-1]) == verts assert g.shortestPath(verts[-1], verts[0]) == list(reversed(verts)) assert g.shortestPath(verts[3], verts[3]) == [verts[3]] shortcut = g.pushVertex() edgeCount += 2 g.addEdge(verts[0], shortcut) g.addEdge(verts[-1], shortcut) assert g.shortestPath(verts[0], verts[-1]) == \ [verts[0], shortcut, verts[-1]] assert verts[0] == 0 edgeCount -= 1 g.removeEdge(verts[-1], shortcut) assert g.shortestPath(shortcut, verts[1]) == [shortcut, verts[0], verts[1]] edgeCount -= len(g.adjacencies(shortcut)) assert g.edgeCount(without={shortcut}) == edgeCount g.removeVertex(shortcut) assert g.edgeCount() == edgeCount # noinspection PyUnusedLocal edgeCount = None g.addEdge(verts[0], verts[-1]) assert g.shortestPath(verts[0], verts[-1]) == [verts[0], verts[-1]] assert not any(g.isSeparator(v) for v in verts) g.removeEdge(verts[0], verts[-1]) g.asReadOnly() mask = verts[:2] + verts[3:] parts = g.disjointPartitions(mask) assert len(parts) == 2 assert not parts[0].intersection(parts[1]) assert g.isConnectedSet(parts[0]) assert g.isConnectedSet(parts[1]) for v1 in parts[0]: for v2 in parts[1]: assert g.shortestPath(v1, v2, mask) == [] assert not g.isConnectedSet(mask, mask) assert verts[2] not in parts[0].union(parts[1]) assert parts[0].union(parts[1]) == set(verts) - set(verts[2:3]) drops = [verts[i] for i in [2, 5, 8]] for v in drops: g.removeVertex(v) verts.remove(v) assert not g.adjacencies(verts[-1]) for v in verts[:-1]: assert len(g.adjacencies(v)) == 1 assert not g.isSeparator(v) g.assertSimple() assert len(g.disjointPartitions()) == 4 assert len(g.disjointPartitions(verts[1:])) == 4 assert len(g.disjointPartitions(verts[2:])) == 3 assert g.connectedComponent(verts[-1]) == set(verts[-1:]) assert g.connectedComponent(verts[1], verts[1:]) == set(verts[1:2]) backbone = [list(p)[0] for p in g.disjointPartitions()] for i in range(len(backbone) - 1): g.addEdge(backbone[i], backbone[i + 1]) g.addEdge(backbone[0], backbone[-1]) assert len(g.disjointPartitions()) == 1 assert g.connectedComponent(verts[0]) == set(verts) assert g.connected(verts[0], verts[-1]) assert g.isConnectedSet(set(verts[:1] + verts[-1:])) assert g.edgeCount(without={3, 6}) == g.edgeCount() - 5 assert g.edgeCount(without={0, 9}) == g.edgeCount() - 4