structs.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. class DirectedGraph(object):
  2. """A graph structure with directed edges.
  3. """
  4. def __init__(self):
  5. self._vertices = set()
  6. self._forwards = {} # <key> -> Set[<key>]
  7. self._backwards = {} # <key> -> Set[<key>]
  8. def __iter__(self):
  9. return iter(self._vertices)
  10. def __len__(self):
  11. return len(self._vertices)
  12. def __contains__(self, key):
  13. return key in self._vertices
  14. def copy(self):
  15. """Return a shallow copy of this graph.
  16. """
  17. other = DirectedGraph()
  18. other._vertices = set(self._vertices)
  19. other._forwards = {k: set(v) for k, v in self._forwards.items()}
  20. other._backwards = {k: set(v) for k, v in self._backwards.items()}
  21. return other
  22. def add(self, key):
  23. """Add a new vertex to the graph.
  24. """
  25. if key in self._vertices:
  26. raise ValueError("vertex exists")
  27. self._vertices.add(key)
  28. self._forwards[key] = set()
  29. self._backwards[key] = set()
  30. def remove(self, key):
  31. """Remove a vertex from the graph, disconnecting all edges from/to it.
  32. """
  33. self._vertices.remove(key)
  34. for f in self._forwards.pop(key):
  35. self._backwards[f].remove(key)
  36. for t in self._backwards.pop(key):
  37. self._forwards[t].remove(key)
  38. def connected(self, f, t):
  39. return f in self._backwards[t] and t in self._forwards[f]
  40. def connect(self, f, t):
  41. """Connect two existing vertices.
  42. Nothing happens if the vertices are already connected.
  43. """
  44. if t not in self._vertices:
  45. raise KeyError(t)
  46. self._forwards[f].add(t)
  47. self._backwards[t].add(f)
  48. def iter_edges(self):
  49. for f, children in self._forwards.items():
  50. for t in children:
  51. yield f, t
  52. def iter_children(self, key):
  53. return iter(self._forwards[key])
  54. def iter_parents(self, key):
  55. return iter(self._backwards[key])