graph.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. # coding: utf-8
  2. """
  3. Author: Sten Vercamman
  4. Univeristy of Antwerp
  5. Example code for paper: Efficient model transformations for novices
  6. url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
  7. The main goal of this code is to give an overview, and an understandable
  8. implementation, of known techniques for pattern matching and solving the
  9. sub-graph homomorphism problem. The presented techniques do not include
  10. performance adaptations/optimizations. It is not optimized to be efficient
  11. but rather for the ease of understanding the workings of the algorithms.
  12. The paper does list some possible extensions/optimizations.
  13. It is intended as a guideline, even for novices, and provides an in-depth look
  14. at the workings behind various techniques for efficient pattern matching.
  15. """
  16. class Properties(object):
  17. """
  18. Holds all Properties.
  19. """
  20. def __init__(self):
  21. # member variables:
  22. self.properties = {}
  23. def addProperty(self, name, value):
  24. """
  25. Adds property (overrides if name already exists).
  26. """
  27. self.properties[name] = value
  28. def getProperty(self, name):
  29. """
  30. Returns property with given name or None if not found.
  31. """
  32. return self.properties.get(name)
  33. class Edge(Properties):
  34. """
  35. Describes an Edge with source and target Node.
  36. The Edge can have several properties, like a name, a weight, etc...
  37. """
  38. def __init__(self, src, tgt, str_type=None):
  39. # Call parent class constructor
  40. Properties.__init__(self)
  41. # member variables:
  42. self.src = src
  43. self.tgt = tgt
  44. self.type = str_type
  45. class Vertex(Properties):
  46. """
  47. Describes a Vertex with incoming, outgoing and undirected (both ways) edges.
  48. The vertex can have several properties, like a name, a weight, etc...
  49. """
  50. def __init__(self, str_type):
  51. # Call parent class constructor
  52. Properties.__init__(self)
  53. # member variables:
  54. self.incoming_edges = set() # undirected edges should be stored both in
  55. self.outgoing_edges = set() # incoming and outgoing edges
  56. self.type = str_type
  57. def addIncomingEdge(self, edge):
  58. """
  59. Adds an incoming Edge.
  60. """
  61. if not isinstance(edge, Edge):
  62. raise TypeError('addIncomingEdge without it being an edge')
  63. self.incoming_edges.add(edge)
  64. def addOutgoingEdge(self, edge):
  65. """
  66. Adds an outgoing Edge.
  67. """
  68. if not isinstance(edge, Edge):
  69. raise TypeError('addOutgoingEdge without it being an edge')
  70. self.outgoing_edges.add(edge)
  71. def addUndirectedEdge(self, edge):
  72. """
  73. Adds an undirected (or bi-directed) Edge.
  74. """
  75. self.addIncomingEdge(edge)
  76. self.addOutgoingEdge(edge)
  77. class Graph(object):
  78. """
  79. Holds a Graph.
  80. """
  81. def __init__(self):
  82. # member variables:
  83. # redundant type keeping, "needed" for fast iterating over specific type
  84. self.vertices = {} # {type, set(v1, v2, ...)}
  85. self.edges = {} # {type, set(e1, e2, ...)}
  86. def addCreateVertex(self, str_type):
  87. """
  88. Creates a Vertex of str_type, stores it and returs it
  89. (so that properties can be added to it).
  90. """
  91. vertex = Vertex(str_type)
  92. self.addVertex(vertex)
  93. return vertex
  94. def addVertex(self, vertex):
  95. """
  96. Stores a Vertex into the Graph.
  97. """
  98. if not isinstance(vertex, Vertex):
  99. raise TypeError('addVertex expects a Vertex')
  100. # add vertex, but it first creates a new set for the vertex type
  101. # if the type does not exist in the dictionary
  102. self.vertices.setdefault(vertex.type, set()).add(vertex)
  103. def getVerticesOfType(self, str_type):
  104. """
  105. Returns all vertices of a specific type,
  106. Return [] if there are no vertices with the given type
  107. """
  108. return self.vertices.get(str_type, [])
  109. def getEdgesOfType(self, str_type):
  110. """
  111. Returns all edges of a specific type,
  112. Return [] if there are no edges with the given type
  113. """
  114. return self.edges.get(str_type, [])
  115. def addCreateEdge(self, src, tgt, str_type):
  116. """
  117. Creates edge of str_type from src to tgt, and returns it,
  118. so that properties can be added to the edge.
  119. """
  120. if not isinstance(src, Vertex):
  121. raise TypeError('addCreateEdge: src is not a Vertex')
  122. if not isinstance(tgt, Vertex):
  123. raise TypeError('addCreateEdge: tgt is not a Vertex')
  124. edge = Edge(src, tgt, str_type)
  125. # link vertices connected to this edge
  126. edge.src.addOutgoingEdge(edge)
  127. edge.tgt.addIncomingEdge(edge)
  128. self.addEdge(edge)
  129. return edge
  130. def addEdge(self, edge):
  131. """
  132. Stores an Edge into the Graph.
  133. """
  134. if not isinstance(edge, Edge):
  135. raise TypeError('addEdge expects an Edge')
  136. # add edge, but it first creates a new set for the edge type
  137. # if the type does not exist in the dictionary
  138. self.edges.setdefault(edge.type, set()).add(edge)