pattern matching: convert tabs to spaces
This commit is contained in:
parent
88172d64c5
commit
3ae35a87d0
5 changed files with 929 additions and 915 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Author: Sten Vercamman
|
Author: Sten Vercamman
|
||||||
Univeristy of Antwerp
|
Univeristy of Antwerp
|
||||||
|
|
||||||
Example code for paper: Efficient model transformations for novices
|
Example code for paper: Efficient model transformations for novices
|
||||||
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
||||||
|
|
@ -25,178 +25,178 @@ import collections
|
||||||
import random
|
import random
|
||||||
|
|
||||||
class GraphGenerator(object):
|
class GraphGenerator(object):
|
||||||
"""
|
"""
|
||||||
Generates a random Graph with dv an array containing all vertices (there type),
|
Generates a random Graph with dv an array containing all vertices (there type),
|
||||||
de an array containing all edges (their type) and dc_inc an array representing
|
de an array containing all edges (their type) and dc_inc an array representing
|
||||||
the incoming edges (analogue for dc_out)
|
the incoming edges (analogue for dc_out)
|
||||||
"""
|
"""
|
||||||
def __init__(self, dv, de, dc_inc, dc_out, debug=False):
|
def __init__(self, dv, de, dc_inc, dc_out, debug=False):
|
||||||
if len(de) != len(dc_inc):
|
if len(de) != len(dc_inc):
|
||||||
raise ValueError('de and dc_inc should be the same length.')
|
raise ValueError('de and dc_inc should be the same length.')
|
||||||
if len(de) != len(dc_out):
|
if len(de) != len(dc_out):
|
||||||
raise ValueError('de and dc_out should be the same length.')
|
raise ValueError('de and dc_out should be the same length.')
|
||||||
|
|
||||||
self.dv = dv
|
self.dv = dv
|
||||||
self.de = de
|
self.de = de
|
||||||
self.dc_inc = dc_inc
|
self.dc_inc = dc_inc
|
||||||
self.dc_out = dc_out
|
self.dc_out = dc_out
|
||||||
|
|
||||||
# print for debugging, so you know the used values
|
# print for debugging, so you know the used values
|
||||||
if debug:
|
if debug:
|
||||||
print('dv')
|
print('dv')
|
||||||
print('[',','.join(map(str,dv)),']')
|
print('[',','.join(map(str,dv)),']')
|
||||||
print('_____')
|
print('_____')
|
||||||
print('de')
|
print('de')
|
||||||
print('[',','.join(map(str,de)),']')
|
print('[',','.join(map(str,de)),']')
|
||||||
print('_____')
|
print('_____')
|
||||||
print('dc_inc')
|
print('dc_inc')
|
||||||
print('[',','.join(map(str,dc_inc)),']')
|
print('[',','.join(map(str,dc_inc)),']')
|
||||||
print('_____')
|
print('_____')
|
||||||
print('dc_out')
|
print('dc_out')
|
||||||
print('[',','.join(map(str,dc_out)),']')
|
print('[',','.join(map(str,dc_out)),']')
|
||||||
print('_____')
|
print('_____')
|
||||||
|
|
||||||
self.graph = graph.Graph()
|
self.graph = graph.Graph()
|
||||||
self.vertices = []
|
self.vertices = []
|
||||||
# create all the vertices:
|
# create all the vertices:
|
||||||
for v_type in self.dv:
|
for v_type in self.dv:
|
||||||
# v_type represents the type of the vertex
|
# v_type represents the type of the vertex
|
||||||
self.vertices.append(self.graph.addCreateVertex('v' + str(v_type)))
|
self.vertices.append(self.graph.addCreateVertex('v' + str(v_type)))
|
||||||
|
|
||||||
index = 0
|
index = 0
|
||||||
# create all edges
|
# create all edges
|
||||||
for e_type in self.de:
|
for e_type in self.de:
|
||||||
# e_type represents the type of the edge
|
# e_type represents the type of the edge
|
||||||
src = self.vertices[self.dc_out[index]] # get src vertex
|
src = self.vertices[self.dc_out[index]] # get src vertex
|
||||||
tgt = self.vertices[self.dc_inc[index]] # get tgt vertex
|
tgt = self.vertices[self.dc_inc[index]] # get tgt vertex
|
||||||
self.graph.addCreateEdge(src, tgt, 'e' + str(e_type)) # create edge
|
self.graph.addCreateEdge(src, tgt, 'e' + str(e_type)) # create edge
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
def getRandomGraph(self):
|
def getRandomGraph(self):
|
||||||
return self.graph
|
return self.graph
|
||||||
|
|
||||||
def getRandomPattern(self, max_nr_of_v, max_nr_of_e, start=0, debug=False):
|
def getRandomPattern(self, max_nr_of_v, max_nr_of_e, start=0, debug=False):
|
||||||
# create pattern
|
# create pattern
|
||||||
pattern = graph.Graph()
|
pattern = graph.Graph()
|
||||||
|
|
||||||
# map from graph to new pattern
|
# map from graph to new pattern
|
||||||
graph_to_pattern = {}
|
graph_to_pattern = {}
|
||||||
|
|
||||||
# map of possible edges
|
# map of possible edges
|
||||||
# we don't need a dict, but python v2.7 does not have an OrderedSet
|
# we don't need a dict, but python v2.7 does not have an OrderedSet
|
||||||
possible_edges = collections.OrderedDict()
|
possible_edges = collections.OrderedDict()
|
||||||
|
|
||||||
# set of chosen edges
|
# set of chosen edges
|
||||||
chosen_edges = set()
|
chosen_edges = set()
|
||||||
|
|
||||||
# start node from graph
|
# start node from graph
|
||||||
g_node = self.vertices[start]
|
g_node = self.vertices[start]
|
||||||
p_node = pattern.addCreateVertex(g_node.type)
|
p_node = pattern.addCreateVertex(g_node.type)
|
||||||
# for debuging, print the order in which the pattern gets created and
|
# for debuging, print the order in which the pattern gets created and
|
||||||
# connects it edges
|
# connects it edges
|
||||||
if debug:
|
if debug:
|
||||||
print('v'+str(id(p_node))+'=pattern.addCreateVertex('+"'"+str(g_node.type)+"'"+')')
|
print('v'+str(id(p_node))+'=pattern.addCreateVertex('+"'"+str(g_node.type)+"'"+')')
|
||||||
# save corrolation
|
# save corrolation
|
||||||
graph_to_pattern[g_node] = p_node
|
graph_to_pattern[g_node] = p_node
|
||||||
|
|
||||||
def insertAllEdges(edges, possible_edges, chosen_edges):
|
def insertAllEdges(edges, possible_edges, chosen_edges):
|
||||||
for edge in edges:
|
for edge in edges:
|
||||||
# if we did not chose the edge
|
# if we did not chose the edge
|
||||||
if edge not in chosen_edges:
|
if edge not in chosen_edges:
|
||||||
# if inc_edge not in possible edges, add it with value 1
|
# if inc_edge not in possible edges, add it with value 1
|
||||||
possible_edges[edge] = None
|
possible_edges[edge] = None
|
||||||
|
|
||||||
def insertEdges(g_vertex, possible_edges, chosen_edges):
|
def insertEdges(g_vertex, possible_edges, chosen_edges):
|
||||||
insertAllEdges(g_vertex.incoming_edges, possible_edges, chosen_edges)
|
insertAllEdges(g_vertex.incoming_edges, possible_edges, chosen_edges)
|
||||||
insertAllEdges(g_vertex.outgoing_edges, possible_edges, chosen_edges)
|
insertAllEdges(g_vertex.outgoing_edges, possible_edges, chosen_edges)
|
||||||
|
|
||||||
insertEdges(g_node, possible_edges, chosen_edges)
|
insertEdges(g_node, possible_edges, chosen_edges)
|
||||||
|
|
||||||
while max_nr_of_v > len(graph_to_pattern) and max_nr_of_e > len(chosen_edges):
|
while max_nr_of_v > len(graph_to_pattern) and max_nr_of_e > len(chosen_edges):
|
||||||
candidate = None
|
candidate = None
|
||||||
if len(possible_edges) == 0:
|
if len(possible_edges) == 0:
|
||||||
break
|
break
|
||||||
# get a random number between 0 and len(possible_edges)
|
# get a random number between 0 and len(possible_edges)
|
||||||
# We us a triangular distribution to approximate the fact that
|
# We us a triangular distribution to approximate the fact that
|
||||||
# the first element is the longest in the possible_edges and
|
# the first element is the longest in the possible_edges and
|
||||||
# already had the post chance of beeing choosen.
|
# already had the post chance of beeing choosen.
|
||||||
# (The approximation is because the first few ellements where
|
# (The approximation is because the first few ellements where
|
||||||
# added in the same itteration, but doing this exact is
|
# added in the same itteration, but doing this exact is
|
||||||
# computationally expensive.)
|
# computationally expensive.)
|
||||||
if len(possible_edges) == 1:
|
if len(possible_edges) == 1:
|
||||||
randie = 0
|
randie = 0
|
||||||
else:
|
else:
|
||||||
randie = int(round(random.triangular(1, len(possible_edges), len(possible_edges)))) - 1
|
randie = int(round(random.triangular(1, len(possible_edges), len(possible_edges)))) - 1
|
||||||
candidate = list(possible_edges.keys())[randie]
|
candidate = list(possible_edges.keys())[randie]
|
||||||
del possible_edges[candidate]
|
del possible_edges[candidate]
|
||||||
chosen_edges.add(candidate)
|
chosen_edges.add(candidate)
|
||||||
|
|
||||||
src = graph_to_pattern.get(candidate.src)
|
src = graph_to_pattern.get(candidate.src)
|
||||||
tgt = graph_to_pattern.get(candidate.tgt)
|
tgt = graph_to_pattern.get(candidate.tgt)
|
||||||
src_is_new = True
|
src_is_new = True
|
||||||
if src != None and tgt != None:
|
if src != None and tgt != None:
|
||||||
# create edge between source and target
|
# create edge between source and target
|
||||||
pattern.addCreateEdge(src, tgt, candidate.type)
|
pattern.addCreateEdge(src, tgt, candidate.type)
|
||||||
if debug:
|
if debug:
|
||||||
print('pattern.addCreateEdge('+'v'+str(id(src))+', '+'v'+str(id(tgt))+', '+"'"+str(candidate.type)+"'"+')')
|
print('pattern.addCreateEdge('+'v'+str(id(src))+', '+'v'+str(id(tgt))+', '+"'"+str(candidate.type)+"'"+')')
|
||||||
# skip adding new edges
|
# skip adding new edges
|
||||||
continue
|
continue
|
||||||
elif src == None:
|
elif src == None:
|
||||||
# create pattern vertex
|
# create pattern vertex
|
||||||
src = pattern.addCreateVertex(candidate.src.type)
|
src = pattern.addCreateVertex(candidate.src.type)
|
||||||
if debug:
|
if debug:
|
||||||
print('v'+str(id(src))+'=pattern.addCreateVertex('+"'"+str(candidate.src.type)+"'"+')')
|
print('v'+str(id(src))+'=pattern.addCreateVertex('+"'"+str(candidate.src.type)+"'"+')')
|
||||||
# map newly created pattern vertex
|
# map newly created pattern vertex
|
||||||
graph_to_pattern[candidate.src] = src
|
graph_to_pattern[candidate.src] = src
|
||||||
# create edge between source and target
|
# create edge between source and target
|
||||||
pattern.addCreateEdge(src, tgt, candidate.type)
|
pattern.addCreateEdge(src, tgt, candidate.type)
|
||||||
if debug:
|
if debug:
|
||||||
print('pattern.addCreateEdge('+'v'+str(id(src))+', '+'v'+str(id(tgt))+', '+"'"+str(candidate.type)+"'"+')')
|
print('pattern.addCreateEdge('+'v'+str(id(src))+', '+'v'+str(id(tgt))+', '+"'"+str(candidate.type)+"'"+')')
|
||||||
elif tgt == None:
|
elif tgt == None:
|
||||||
src_is_new = False
|
src_is_new = False
|
||||||
# create pattern vertex
|
# create pattern vertex
|
||||||
tgt = pattern.addCreateVertex(candidate.tgt.type)
|
tgt = pattern.addCreateVertex(candidate.tgt.type)
|
||||||
if debug:
|
if debug:
|
||||||
print('v'+str(id(tgt))+'=pattern.addCreateVertex('+"'"+str(candidate.tgt.type)+"'"+')')
|
print('v'+str(id(tgt))+'=pattern.addCreateVertex('+"'"+str(candidate.tgt.type)+"'"+')')
|
||||||
# map newly created pattern vertex
|
# map newly created pattern vertex
|
||||||
graph_to_pattern[candidate.tgt] = tgt
|
graph_to_pattern[candidate.tgt] = tgt
|
||||||
# create edge between source and target
|
# create edge between source and target
|
||||||
pattern.addCreateEdge(src, tgt, candidate.type)
|
pattern.addCreateEdge(src, tgt, candidate.type)
|
||||||
if debug:
|
if debug:
|
||||||
print('pattern.addCreateEdge('+'v'+str(id(src))+', '+'v'+str(id(tgt))+', '+"'"+str(candidate.type)+"'"+')')
|
print('pattern.addCreateEdge('+'v'+str(id(src))+', '+'v'+str(id(tgt))+', '+"'"+str(candidate.type)+"'"+')')
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('Bug: src or tgt of edge should be in out pattern')
|
raise RuntimeError('Bug: src or tgt of edge should be in out pattern')
|
||||||
|
|
||||||
# select the vertex from the chosen edge that was not yet part of the pattern
|
# select the vertex from the chosen edge that was not yet part of the pattern
|
||||||
if src_is_new:
|
if src_is_new:
|
||||||
new_vertex = candidate.src
|
new_vertex = candidate.src
|
||||||
else:
|
else:
|
||||||
new_vertex = candidate.tgt
|
new_vertex = candidate.tgt
|
||||||
# insert all edges from the new vertex
|
# insert all edges from the new vertex
|
||||||
insertEdges(new_vertex, possible_edges, chosen_edges)
|
insertEdges(new_vertex, possible_edges, chosen_edges)
|
||||||
|
|
||||||
return pattern
|
return pattern
|
||||||
|
|
||||||
def createConstantPattern():
|
def createConstantPattern():
|
||||||
"""
|
"""
|
||||||
Use this to create the same pattern over and over again.
|
Use this to create the same pattern over and over again.
|
||||||
"""
|
"""
|
||||||
# create pattern
|
# create pattern
|
||||||
pattern = graph.Graph()
|
pattern = graph.Graph()
|
||||||
|
|
||||||
|
|
||||||
# copy and paste printed pattern from debug output or create a pattern
|
# copy and paste printed pattern from debug output or create a pattern
|
||||||
# below the following line:
|
# below the following line:
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
v4447242448=pattern.addCreateVertex('v4')
|
v4447242448=pattern.addCreateVertex('v4')
|
||||||
v4457323088=pattern.addCreateVertex('v6')
|
v4457323088=pattern.addCreateVertex('v6')
|
||||||
pattern.addCreateEdge(v4447242448, v4457323088, 'e4')
|
pattern.addCreateEdge(v4447242448, v4457323088, 'e4')
|
||||||
v4457323216=pattern.addCreateVertex('v8')
|
v4457323216=pattern.addCreateVertex('v8')
|
||||||
pattern.addCreateEdge(v4457323216, v4447242448, 'e4')
|
pattern.addCreateEdge(v4457323216, v4447242448, 'e4')
|
||||||
v4457323344=pattern.addCreateVertex('v7')
|
v4457323344=pattern.addCreateVertex('v7')
|
||||||
pattern.addCreateEdge(v4457323216, v4457323344, 'e3')
|
pattern.addCreateEdge(v4457323216, v4457323344, 'e3')
|
||||||
v4457323472=pattern.addCreateVertex('v7')
|
v4457323472=pattern.addCreateVertex('v7')
|
||||||
pattern.addCreateEdge(v4457323344, v4457323472, 'e1')
|
pattern.addCreateEdge(v4457323344, v4457323472, 'e1')
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
return pattern
|
return pattern
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Author: Sten Vercamman
|
Author: Sten Vercamman
|
||||||
Univeristy of Antwerp
|
Univeristy of Antwerp
|
||||||
|
|
||||||
Example code for paper: Efficient model transformations for novices
|
Example code for paper: Efficient model transformations for novices
|
||||||
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
||||||
|
|
@ -19,139 +19,139 @@ at the workings behind various techniques for efficient pattern matching.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Properties(object):
|
class Properties(object):
|
||||||
"""
|
"""
|
||||||
Holds all Properties.
|
Holds all Properties.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# member variables:
|
# member variables:
|
||||||
self.properties = {}
|
self.properties = {}
|
||||||
|
|
||||||
def addProperty(self, name, value):
|
def addProperty(self, name, value):
|
||||||
"""
|
"""
|
||||||
Adds property (overrides if name already exists).
|
Adds property (overrides if name already exists).
|
||||||
"""
|
"""
|
||||||
self.properties[name] = value
|
self.properties[name] = value
|
||||||
|
|
||||||
def getProperty(self, name):
|
def getProperty(self, name):
|
||||||
"""
|
"""
|
||||||
Returns property with given name or None if not found.
|
Returns property with given name or None if not found.
|
||||||
"""
|
"""
|
||||||
return self.properties.get(name)
|
return self.properties.get(name)
|
||||||
|
|
||||||
class Edge(Properties):
|
class Edge(Properties):
|
||||||
"""
|
"""
|
||||||
Describes an Edge with source and target Node.
|
Describes an Edge with source and target Node.
|
||||||
The Edge can have several properties, like a name, a weight, etc...
|
The Edge can have several properties, like a name, a weight, etc...
|
||||||
"""
|
"""
|
||||||
def __init__(self, src, tgt, str_type=None):
|
def __init__(self, src, tgt, str_type=None):
|
||||||
# Call parent class constructor
|
# Call parent class constructor
|
||||||
Properties.__init__(self)
|
Properties.__init__(self)
|
||||||
# member variables:
|
# member variables:
|
||||||
self.src = src
|
self.src = src
|
||||||
self.tgt = tgt
|
self.tgt = tgt
|
||||||
self.type = str_type
|
self.type = str_type
|
||||||
|
|
||||||
class Vertex(Properties):
|
class Vertex(Properties):
|
||||||
"""
|
"""
|
||||||
Describes a Vertex with incoming, outgoing and undirected (both ways) edges.
|
Describes a Vertex with incoming, outgoing and undirected (both ways) edges.
|
||||||
The vertex can have several properties, like a name, a weight, etc...
|
The vertex can have several properties, like a name, a weight, etc...
|
||||||
"""
|
"""
|
||||||
def __init__(self, str_type):
|
def __init__(self, str_type):
|
||||||
# Call parent class constructor
|
# Call parent class constructor
|
||||||
Properties.__init__(self)
|
Properties.__init__(self)
|
||||||
# member variables:
|
# member variables:
|
||||||
self.incoming_edges = set() # undirected edges should be stored both in
|
self.incoming_edges = set() # undirected edges should be stored both in
|
||||||
self.outgoing_edges = set() # incoming and outgoing edges
|
self.outgoing_edges = set() # incoming and outgoing edges
|
||||||
self.type = str_type
|
self.type = str_type
|
||||||
|
|
||||||
def addIncomingEdge(self, edge):
|
def addIncomingEdge(self, edge):
|
||||||
"""
|
"""
|
||||||
Adds an incoming Edge.
|
Adds an incoming Edge.
|
||||||
"""
|
"""
|
||||||
if not isinstance(edge, Edge):
|
if not isinstance(edge, Edge):
|
||||||
raise TypeError('addIncomingEdge without it being an edge')
|
raise TypeError('addIncomingEdge without it being an edge')
|
||||||
self.incoming_edges.add(edge)
|
self.incoming_edges.add(edge)
|
||||||
|
|
||||||
def addOutgoingEdge(self, edge):
|
def addOutgoingEdge(self, edge):
|
||||||
"""
|
"""
|
||||||
Adds an outgoing Edge.
|
Adds an outgoing Edge.
|
||||||
"""
|
"""
|
||||||
if not isinstance(edge, Edge):
|
if not isinstance(edge, Edge):
|
||||||
raise TypeError('addOutgoingEdge without it being an edge')
|
raise TypeError('addOutgoingEdge without it being an edge')
|
||||||
self.outgoing_edges.add(edge)
|
self.outgoing_edges.add(edge)
|
||||||
|
|
||||||
def addUndirectedEdge(self, edge):
|
def addUndirectedEdge(self, edge):
|
||||||
"""
|
"""
|
||||||
Adds an undirected (or bi-directed) Edge.
|
Adds an undirected (or bi-directed) Edge.
|
||||||
"""
|
"""
|
||||||
self.addIncomingEdge(edge)
|
self.addIncomingEdge(edge)
|
||||||
self.addOutgoingEdge(edge)
|
self.addOutgoingEdge(edge)
|
||||||
|
|
||||||
class Graph(object):
|
class Graph(object):
|
||||||
"""
|
"""
|
||||||
Holds a Graph.
|
Holds a Graph.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# member variables:
|
# member variables:
|
||||||
# redundant type keeping, "needed" for fast iterating over specific type
|
# redundant type keeping, "needed" for fast iterating over specific type
|
||||||
self.vertices = {} # {type, set(v1, v2, ...)}
|
self.vertices = {} # {type, set(v1, v2, ...)}
|
||||||
self.edges = {} # {type, set(e1, e2, ...)}
|
self.edges = {} # {type, set(e1, e2, ...)}
|
||||||
|
|
||||||
def addCreateVertex(self, str_type):
|
def addCreateVertex(self, str_type):
|
||||||
"""
|
"""
|
||||||
Creates a Vertex of str_type, stores it and returs it
|
Creates a Vertex of str_type, stores it and returs it
|
||||||
(so that properties can be added to it).
|
(so that properties can be added to it).
|
||||||
"""
|
"""
|
||||||
vertex = Vertex(str_type)
|
vertex = Vertex(str_type)
|
||||||
self.addVertex(vertex)
|
self.addVertex(vertex)
|
||||||
return vertex
|
return vertex
|
||||||
|
|
||||||
def addVertex(self, vertex):
|
def addVertex(self, vertex):
|
||||||
"""
|
"""
|
||||||
Stores a Vertex into the Graph.
|
Stores a Vertex into the Graph.
|
||||||
"""
|
"""
|
||||||
if not isinstance(vertex, Vertex):
|
if not isinstance(vertex, Vertex):
|
||||||
raise TypeError('addVertex expects a Vertex')
|
raise TypeError('addVertex expects a Vertex')
|
||||||
# add vertex, but it first creates a new set for the vertex type
|
# add vertex, but it first creates a new set for the vertex type
|
||||||
# if the type does not exist in the dictionary
|
# if the type does not exist in the dictionary
|
||||||
self.vertices.setdefault(vertex.type, set()).add(vertex)
|
self.vertices.setdefault(vertex.type, set()).add(vertex)
|
||||||
|
|
||||||
def getVerticesOfType(self, str_type):
|
def getVerticesOfType(self, str_type):
|
||||||
"""
|
"""
|
||||||
Returns all vertices of a specific type,
|
Returns all vertices of a specific type,
|
||||||
Return [] if there are no vertices with the given type
|
Return [] if there are no vertices with the given type
|
||||||
"""
|
"""
|
||||||
return self.vertices.get(str_type, [])
|
return self.vertices.get(str_type, [])
|
||||||
|
|
||||||
def getEdgesOfType(self, str_type):
|
def getEdgesOfType(self, str_type):
|
||||||
"""
|
"""
|
||||||
Returns all edges of a specific type,
|
Returns all edges of a specific type,
|
||||||
Return [] if there are no edges with the given type
|
Return [] if there are no edges with the given type
|
||||||
"""
|
"""
|
||||||
return self.edges.get(str_type, [])
|
return self.edges.get(str_type, [])
|
||||||
|
|
||||||
def addCreateEdge(self, src, tgt, str_type):
|
def addCreateEdge(self, src, tgt, str_type):
|
||||||
"""
|
"""
|
||||||
Creates edge of str_type from src to tgt, and returns it,
|
Creates edge of str_type from src to tgt, and returns it,
|
||||||
so that properties can be added to the edge.
|
so that properties can be added to the edge.
|
||||||
"""
|
"""
|
||||||
if not isinstance(src, Vertex):
|
if not isinstance(src, Vertex):
|
||||||
raise TypeError('addCreateEdge: src is not a Vertex')
|
raise TypeError('addCreateEdge: src is not a Vertex')
|
||||||
if not isinstance(tgt, Vertex):
|
if not isinstance(tgt, Vertex):
|
||||||
raise TypeError('addCreateEdge: tgt is not a Vertex')
|
raise TypeError('addCreateEdge: tgt is not a Vertex')
|
||||||
edge = Edge(src, tgt, str_type)
|
edge = Edge(src, tgt, str_type)
|
||||||
# link vertices connected to this edge
|
# link vertices connected to this edge
|
||||||
edge.src.addOutgoingEdge(edge)
|
edge.src.addOutgoingEdge(edge)
|
||||||
edge.tgt.addIncomingEdge(edge)
|
edge.tgt.addIncomingEdge(edge)
|
||||||
self.addEdge(edge)
|
self.addEdge(edge)
|
||||||
return edge
|
return edge
|
||||||
|
|
||||||
def addEdge(self, edge):
|
def addEdge(self, edge):
|
||||||
"""
|
"""
|
||||||
Stores an Edge into the Graph.
|
Stores an Edge into the Graph.
|
||||||
"""
|
"""
|
||||||
if not isinstance(edge, Edge):
|
if not isinstance(edge, Edge):
|
||||||
raise TypeError('addEdge expects an Edge')
|
raise TypeError('addEdge expects an Edge')
|
||||||
# add edge, but it first creates a new set for the edge type
|
# add edge, but it first creates a new set for the edge type
|
||||||
# if the type does not exist in the dictionary
|
# if the type does not exist in the dictionary
|
||||||
self.edges.setdefault(edge.type, set()).add(edge)
|
self.edges.setdefault(edge.type, set()).add(edge)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Author: Sten Vercamman
|
Author: Sten Vercamman
|
||||||
Univeristy of Antwerp
|
Univeristy of Antwerp
|
||||||
|
|
||||||
Example code for paper: Efficient model transformations for novices
|
Example code for paper: Efficient model transformations for novices
|
||||||
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
||||||
|
|
@ -21,24 +21,24 @@ at the workings behind various techniques for efficient pattern matching.
|
||||||
import graph as mg
|
import graph as mg
|
||||||
|
|
||||||
def printGraph(fileName, graph, matched_v={}, matched_e={}):
|
def printGraph(fileName, graph, matched_v={}, matched_e={}):
|
||||||
if not isinstance(graph, mg.Graph):
|
if not isinstance(graph, mg.Graph):
|
||||||
raise TypeError('Can only print Graph Graphs')
|
raise TypeError('Can only print Graph Graphs')
|
||||||
|
|
||||||
with open(fileName, 'w') as f:
|
with open(fileName, 'w') as f:
|
||||||
f.write('digraph randomGraph {\n\n')
|
f.write('digraph randomGraph {\n\n')
|
||||||
for str_type, plan_vertices in graph.vertices.items():
|
for str_type, plan_vertices in graph.vertices.items():
|
||||||
for plan_vertex in plan_vertices:
|
for plan_vertex in plan_vertices:
|
||||||
vertex_str = str(id(plan_vertex)) + ' [label="'+str(str_type)+'"'
|
vertex_str = str(id(plan_vertex)) + ' [label="'+str(str_type)+'"'
|
||||||
if plan_vertex in list(matched_v.values()):
|
if plan_vertex in list(matched_v.values()):
|
||||||
vertex_str += ', style=dashed, style=filled]\n'
|
vertex_str += ', style=dashed, style=filled]\n'
|
||||||
else:
|
else:
|
||||||
vertex_str += ']\n'
|
vertex_str += ']\n'
|
||||||
f.write(vertex_str)
|
f.write(vertex_str)
|
||||||
for out_edge in plan_vertex.outgoing_edges:
|
for out_edge in plan_vertex.outgoing_edges:
|
||||||
edge_str = str(id(plan_vertex)) + ' -> ' + str(id(out_edge.tgt)) + ' [label="'+str(out_edge.type)+'"'
|
edge_str = str(id(plan_vertex)) + ' -> ' + str(id(out_edge.tgt)) + ' [label="'+str(out_edge.type)+'"'
|
||||||
if out_edge in list(matched_e.values()):
|
if out_edge in list(matched_e.values()):
|
||||||
edge_str += ', style=dashed, penwidth = 4]\n'
|
edge_str += ', style=dashed, penwidth = 4]\n'
|
||||||
else:
|
else:
|
||||||
edge_str += ']\n'
|
edge_str += ']\n'
|
||||||
f.write(edge_str)
|
f.write(edge_str)
|
||||||
f.write('\n}')
|
f.write('\n}')
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Author: Sten Vercamman
|
Author: Sten Vercamman
|
||||||
Univeristy of Antwerp
|
Univeristy of Antwerp
|
||||||
|
|
||||||
Example code for paper: Efficient model transformations for novices
|
Example code for paper: Efficient model transformations for novices
|
||||||
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
url: http://msdl.cs.mcgill.ca/people/hv/teaching/MSBDesign/projects/Sten.Vercammen
|
||||||
|
|
@ -18,8 +18,8 @@ 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.
|
at the workings behind various techniques for efficient pattern matching.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from generator import *
|
from generator import *
|
||||||
from patternMatching import *
|
from patternMatching import *
|
||||||
|
|
||||||
import graphToDot
|
import graphToDot
|
||||||
|
|
||||||
|
|
@ -28,66 +28,66 @@ import random
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
"""
|
"""
|
||||||
The main function called when running from the command line.
|
The main function called when running from the command line.
|
||||||
"""
|
"""
|
||||||
nr_of_vertices = 50
|
nr_of_vertices = 50
|
||||||
nr_of_diff_types_v = 2
|
nr_of_diff_types_v = 2
|
||||||
nr_of_edges = 150
|
nr_of_edges = 150
|
||||||
nr_of_diff_types_e = 2
|
nr_of_diff_types_e = 2
|
||||||
|
|
||||||
dv = [random.randint(0, nr_of_diff_types_v) for _ in range(nr_of_vertices)]
|
dv = [random.randint(0, nr_of_diff_types_v) for _ in range(nr_of_vertices)]
|
||||||
de = [random.randint(0, nr_of_diff_types_e) for _ in range(nr_of_edges)]
|
de = [random.randint(0, nr_of_diff_types_e) for _ in range(nr_of_edges)]
|
||||||
dc_inc = [random.randint(0, nr_of_vertices-1) for _ in range(nr_of_edges)]
|
dc_inc = [random.randint(0, nr_of_vertices-1) for _ in range(nr_of_edges)]
|
||||||
dc_out = [random.randint(0, nr_of_vertices-1) for _ in range(nr_of_edges)]
|
dc_out = [random.randint(0, nr_of_vertices-1) for _ in range(nr_of_edges)]
|
||||||
|
|
||||||
# override random graph by copy pasting output from terminal
|
# override random graph by copy pasting output from terminal
|
||||||
# dv = [ 10,5,4,0,8,6,8,0,4,8,5,5,7,0,10,0,5,6,10,4,0,3,0,8,2,7,5,8,1,0,2,10,0,0,1,6,8,4,7,6,4,2,10,10,6,4,6,0,2,7 ]
|
# dv = [ 10,5,4,0,8,6,8,0,4,8,5,5,7,0,10,0,5,6,10,4,0,3,0,8,2,7,5,8,1,0,2,10,0,0,1,6,8,4,7,6,4,2,10,10,6,4,6,0,2,7 ]
|
||||||
# de = [ 8,10,8,1,6,7,4,3,5,2,0,0,9,6,0,3,8,3,2,7,2,3,10,8,10,8,10,2,5,5,10,6,7,5,1,2,1,2,2,3,7,7,2,1,7,2,9,10,8,1,9,4,1,3,1,1,8,2,2,9,10,9,1,9,4,10,10,10,9,3,5,3,6,6,9,1,2,6,3,2,4,10,9,6,5,6,2,4,3,2,4,10,6,2,8,8,0,5,1,7,3,4,3,8,7,3,0,8,3,3,8,5,10,5,9,3,1,10,3,2,6,3,10,0,5,10,9,10,0,1,4,7,10,3,1,9,1,2,3,7,4,3,7,8,8,4,5,10,1,4 ]
|
# de = [ 8,10,8,1,6,7,4,3,5,2,0,0,9,6,0,3,8,3,2,7,2,3,10,8,10,8,10,2,5,5,10,6,7,5,1,2,1,2,2,3,7,7,2,1,7,2,9,10,8,1,9,4,1,3,1,1,8,2,2,9,10,9,1,9,4,10,10,10,9,3,5,3,6,6,9,1,2,6,3,2,4,10,9,6,5,6,2,4,3,2,4,10,6,2,8,8,0,5,1,7,3,4,3,8,7,3,0,8,3,3,8,5,10,5,9,3,1,10,3,2,6,3,10,0,5,10,9,10,0,1,4,7,10,3,1,9,1,2,3,7,4,3,7,8,8,4,5,10,1,4 ]
|
||||||
# dc_inc = [ 0,25,18,47,22,25,16,45,38,25,5,45,15,44,17,46,6,17,35,8,16,29,48,47,25,34,4,20,24,1,47,44,8,25,32,3,16,6,33,21,6,13,41,10,17,25,21,33,31,30,5,4,45,26,16,42,12,25,29,3,32,30,14,26,11,13,7,13,3,43,43,22,48,37,20,28,15,40,19,33,43,16,49,36,11,25,9,42,3,22,16,40,42,44,27,30,1,18,10,35,19,6,9,43,37,38,45,19,41,14,37,45,0,31,29,31,24,20,44,46,8,45,43,3,38,38,35,12,19,45,7,34,20,28,12,17,45,17,35,49,20,21,49,1,35,38,38,36,33,30 ]
|
# dc_inc = [ 0,25,18,47,22,25,16,45,38,25,5,45,15,44,17,46,6,17,35,8,16,29,48,47,25,34,4,20,24,1,47,44,8,25,32,3,16,6,33,21,6,13,41,10,17,25,21,33,31,30,5,4,45,26,16,42,12,25,29,3,32,30,14,26,11,13,7,13,3,43,43,22,48,37,20,28,15,40,19,33,43,16,49,36,11,25,9,42,3,22,16,40,42,44,27,30,1,18,10,35,19,6,9,43,37,38,45,19,41,14,37,45,0,31,29,31,24,20,44,46,8,45,43,3,38,38,35,12,19,45,7,34,20,28,12,17,45,17,35,49,20,21,49,1,35,38,38,36,33,30 ]
|
||||||
# dc_out = [ 9,2,49,49,37,33,16,21,5,46,4,15,9,6,14,22,16,33,23,21,15,31,37,23,47,3,30,26,35,9,29,21,39,32,22,43,5,9,41,30,31,30,37,33,31,34,23,22,34,26,44,36,38,33,48,5,9,34,13,7,48,41,43,26,26,7,12,6,12,28,22,8,29,22,24,27,16,4,31,41,32,15,19,20,38,0,26,18,43,46,40,17,29,14,34,14,32,17,32,47,16,45,7,4,35,22,42,11,38,2,0,29,4,38,17,44,9,23,5,10,31,17,1,11,16,5,37,27,35,32,45,16,18,1,14,4,42,24,43,31,21,38,6,34,39,46,20,1,38,47 ]
|
# dc_out = [ 9,2,49,49,37,33,16,21,5,46,4,15,9,6,14,22,16,33,23,21,15,31,37,23,47,3,30,26,35,9,29,21,39,32,22,43,5,9,41,30,31,30,37,33,31,34,23,22,34,26,44,36,38,33,48,5,9,34,13,7,48,41,43,26,26,7,12,6,12,28,22,8,29,22,24,27,16,4,31,41,32,15,19,20,38,0,26,18,43,46,40,17,29,14,34,14,32,17,32,47,16,45,7,4,35,22,42,11,38,2,0,29,4,38,17,44,9,23,5,10,31,17,1,11,16,5,37,27,35,32,45,16,18,1,14,4,42,24,43,31,21,38,6,34,39,46,20,1,38,47 ]
|
||||||
|
|
||||||
dv = [0, 1, 0, 1, 0]
|
dv = [0, 1, 0, 1, 0]
|
||||||
de = [0, 0, 0]
|
de = [0, 0, 0]
|
||||||
dc_inc = [0, 2, 4]
|
dc_inc = [0, 2, 4]
|
||||||
dc_out = [1, 3, 3]
|
dc_out = [1, 3, 3]
|
||||||
|
|
||||||
gg = GraphGenerator(dv, de, dc_inc, dc_out, debug)
|
gg = GraphGenerator(dv, de, dc_inc, dc_out, debug)
|
||||||
|
|
||||||
graph = gg.getRandomGraph()
|
graph = gg.getRandomGraph()
|
||||||
|
|
||||||
print(graph.vertices)
|
print(graph.vertices)
|
||||||
pattern = gg.getRandomPattern(3, 15, debug=debug)
|
pattern = gg.getRandomPattern(3, 15, debug=debug)
|
||||||
print(pattern.vertices)
|
print(pattern.vertices)
|
||||||
|
|
||||||
# override random pattern by copy pasting output from terminal to create
|
# override random pattern by copy pasting output from terminal to create
|
||||||
# pattern, paste it in the createConstantPattern function in the generator.py
|
# pattern, paste it in the createConstantPattern function in the generator.py
|
||||||
# pattern = gg.createConstantPattern()
|
# pattern = gg.createConstantPattern()
|
||||||
|
|
||||||
# generate here to know pattern and graph before searching it
|
# generate here to know pattern and graph before searching it
|
||||||
graphToDot.printGraph('randomPattern.dot', pattern)
|
graphToDot.printGraph('randomPattern.dot', pattern)
|
||||||
graphToDot.printGraph('randomGraph.dot', graph)
|
graphToDot.printGraph('randomGraph.dot', graph)
|
||||||
|
|
||||||
|
|
||||||
#PM = PatternMatching('naive')
|
#PM = PatternMatching('naive')
|
||||||
#PM = PatternMatching('SP')
|
#PM = PatternMatching('SP')
|
||||||
# PM = PatternMatching('Ullmann')
|
# PM = PatternMatching('Ullmann')
|
||||||
PM = PatternMatching('VF2')
|
PM = PatternMatching('VF2')
|
||||||
matches = [m for m in PM.matchVF2(pattern, graph)]
|
matches = [m for m in PM.matchVF2(pattern, graph)]
|
||||||
print("found", len(matches), "matches:", matches)
|
print("found", len(matches), "matches:", matches)
|
||||||
|
|
||||||
# regenerate graph, to show matched pattern
|
# regenerate graph, to show matched pattern
|
||||||
for i, (v,e) in enumerate(matches):
|
for i, (v,e) in enumerate(matches):
|
||||||
graphToDot.printGraph(f'randomGraph-{i}.dot', graph, v, e)
|
graphToDot.printGraph(f'randomGraph-{i}.dot', graph, v, e)
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print(len(v))
|
print(len(v))
|
||||||
print('___')
|
print('___')
|
||||||
print(v)
|
print(v)
|
||||||
for key, value in v.items():
|
for key, value in v.items():
|
||||||
print(value.type)
|
print(value.type)
|
||||||
print(len(e))
|
print(len(e))
|
||||||
print(e)
|
print(e)
|
||||||
print('___')
|
print('___')
|
||||||
for key, value in e.items():
|
for key, value in e.items():
|
||||||
print(value.type)
|
print(value.type)
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue