123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- # coding: utf-8
- """
- Author: Sten Vercamman
- Univeristy of Antwerp
- Example code for paper: Efficient model transformations for novices
- url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
- The main goal of this code is to give an overview, and an understandable
- implementation, of known techniques for pattern matching and solving the
- sub-graph homomorphism problem. The presented techniques do not include
- performance adaptations/optimizations. It is not optimized to be efficient
- but rather for the ease of understanding the workings of the algorithms.
- The paper does list some possible extensions/optimizations.
- It is intended as a guideline, even for novices, and provides an in-depth look
- at the workings behind various techniques for efficient pattern matching.
- """
- from graph import *
- import math
- class SearchGraph(Graph):
- """
- A SearchGraph is an extended Graph, it keeps traks of statistics
- for creating the cost model when generating a search plan.
- It stire the amount of edges for each edge.type per vertex.type.
- """
- def __init__(self, orig=None, deepCopy=False):
- Graph.__init__(self)
- # member variables:
- self.nr_of_inc_edges = {} # {vertex_type, {edge_type, nr of incoming edges of edge_type for vertex_type } }
- self.nr_of_out_edges = {} # {vertex_type, {edge_type, nr of outgoing edges of edge_type for vertex_type } }
- if orig != None:
- if not (isinstance(orig, Graph) or isinstance(orig, SearchGraph)):
- raise TypeError('Can only create SearchGraph from Graph and SearchGraph types')
- if not deepCopy:
- # copy all memeber elements:
- self.vertices = orig.vertices # this is a reference
- self.edges = orig.edges # this is a reference
- # udpate the edge counters for each edge
- for _, edges in self.edges.items():
- for edge in edges:
- self.addToEdgeCounters(edge)
- else: # TODO: deepcopy (not really needed)
- pass
- def addCreateEdge(self, src, tgt, str_type):
- """
- Creates edge of str_type from src to tgt, and returns it,
- so that properties can be added to the edge.
- This also add the Edge to the Edge counters
- """
- # call parent fucntion, this function is an extention
- edge = Graph.addCreateEdge(self, src, tgt, str_type)
- self.updateEdgeCounters(edge)
- return edge
- def addToEdgeCounters(self, edge):
- """
- Add the Edge to the Edge counters.
- """
- # get {edge.type, counter} for tgt vertex of edge (or create it)
- edge_counters = self.nr_of_inc_edges.setdefault(edge.tgt.type, {})
- # increase counter of edge.type by 1
- edge_counters[edge.type] = edge_counters.get(edge.type, 0) + 1
- # get {edge.type, counter} for src vertex of edge (or create it)
- edge_counters = self.nr_of_out_edges.setdefault(edge.src.type, {})
- # increase counter of edge.type by 1
- edge_counters[edge.type] = edge_counters.get(edge.type, 0) + 1
- def getCostLkp(self, type, is_vertex):
- """
- Returns the cost of a lkp primitive operation (of a vertex or edge).
- Returns None if vertex type or edge type not present in Host Graph
- """
- if is_vertex:
- cost = len(self.getVerticesOfType(type))
- else:
- cost = len(self.getEdgesOfType(type))
- if cost == 0:
- return None
- # we use a logaritmic cost
- return math.log(cost)
- def getCostInc(self, vertex_type, edge_type):
- """
- Returns the cost of an in primitive operation.
- Returns None if vertex_type or edge_type not present in Host Graph
- """
- cost = float(self.nr_of_inc_edges.get(vertex_type, {}).get(edge_type))
- if cost != None:
- nr_of_vertices_with_type = len(self.getVerticesOfType(vertex_type))
- if nr_of_vertices_with_type != 0:
- cost /= len(self.getVerticesOfType(vertex_type))
- # we use a logaritmic cost
- cost = math.log(cost)
- return cost
- def getCostOut(self, vertex_type, edge_type):
- """
- Returns the cost of an out primitive operation.
- Returns None if vertex_type or edge_type not present in Host Graph
- """
- cost = float(self.nr_of_out_edges.get(vertex_type, {}).get(edge_type))
- if cost != None:
- nr_of_vertices_with_type = len(self.getVerticesOfType(vertex_type))
- if nr_of_vertices_with_type != 0:
- cost /= len(self.getVerticesOfType(vertex_type))
- # we use a logaritmic cost
- cost = math.log(cost)
- return cost
|