mainFeatures.py
#Graph representation module
from Himesis.Graph import Graph
from Himesis.Node import Node
#Primitive types
from Himesis.Int import Int
from Himesis.String import String
from Himesis.Float import Float
from Himesis.Bool import Bool
#To import/export to XML
from Himesis.GraphUtils.AGLLoader import AGLLoader
from Himesis.GraphUtils.AGLGenerator import AGLGenerator
#To match graphs
from Himesis.GraphUtils.Match import Match
import os
#In linux , to pretty print this file to .ps
#aliased to enscript -G2rjE --color -o !*.ps !*; gv !*.ps
# to html: enscript -Whtml -Epython --color mainFeatures.py -o mainFeatures.html
#Instantiating a graph g = Graph(ID="", label="", parent=None)
#all arguments are facultative.
root = Graph(ID="Root", label="PrimitiveElementsGraph")
print "Root ID: ", root.getName()
print "Root label: ", root.getLabel()
print "Root parent: ", root.getParent()
#All elements have the same interface
# Node(ID="", label="", parent=None)
# Int(ID="", label="", parent=None, value=None)
# e.g.
i1 = Int(ID="i1", label="Int", value=55)
print "Int i1 ID: ", i1.getName()
print "Int i1 label: ", i1.getLabel()
print "Int i1 parent: ", i1.getParent()
print "Int i1 value: ", i1.getValue()
#setting value, simply:
i1.setValue(456)
#Adding elements to a graph:
# graph[path] = element
# A path is a string of the form ID1.ID2.ID3 navigating down
# the hierarchy of graphs. The final ID (ID3 in our example)
# it the actual name of the added element. The added element
# will be renamed..
root["i3"] = i1 #this will rename i1 to i3
root["i2"] = Int(label="Int", value=102)
#getting elements by name
print "Int i3 (previously i1) ", root["i3"]
print "Int i2", root["i2"]
#each element has a unique, global id, which is a path from the root
print "i3 unique ID: ", root["i3"].getGlobalId()
#getting elements by label
#getElements(labels=[listofwantedlabels])
print "Elements with label Int: \n", root.getElements(labels=["Int"])
#adding elements with other labels
root["f1"] = Float(label="Float", value=4.56)
root["f2"] = Float(label="Float", value=55.6)
print "Elements with label Int and Float: \n", root.getElements(labels=["Int", "Float"])
#cloning a graph. simply g.clone()
internalGraph = root.clone()
#comparing the graphs (structural equality, IDs are ignored in the process)
#(labels are used to compare elements)
print "Graphs should be equals: ", internalGraph.equals(root)
#adding the graph to root..
root["internalGraph"]=internalGraph
#Graphs aren't equal anymore
print "Graphs should not be equals: ", root["internalGraph"].equals(root)
#adding a string to root
root["s1"] = String(label="String", value=99.9)
#iterating over the elements of the first level:
print "Iterating over the first level"
for elem in root: #or root.iterate()
print elem.getGlobalId()
print "Iterating over all elements (default traversal is Depth First)"
for elem in root.iterateAll():
print elem.getGlobalId()
print "Iterating over all elements (Breath First)"
for elem in root.iterateAll(traversal="BreathFirst"):
print elem.getGlobalId()
#connecting stuff
root.connect("i3", "i2")
root.connect("i3", "f1")
root.connect("f1", "s1")
#accross level, using the path syntax..
root.connect("i3", "internalGraph.f2")
#iterating over connections..
print "iterating over i3 out connections"
for outC in root["i3"].outC():
print outC.getGlobalId()
print "iterating over s1 in connections"
for inC in root["s1"].inC():
print inC.getGlobalId()
# to get a list of connections
outList = root["i3"].getOutC()
inList = root["i3"].getInC()
# to get the degree..
print "i3 out degree: ", root["i3"].getOutDegree()
print "i3 in degree: ", root["i3"].getInDegree()
#disconnecting..
root.disconnect("i3", "internalGraph.f2")
#creating a graph to match..
#the matching algorithm will, by default, match nodes with corresponding labels.
#note that it *will* match through hierarchies..
#In order to match, first create a match objects, which implements the
#matching algorithms:
# m = Match(subgraph, host)
# This object will try to match subgraph in host and returns, for now,
# a list of lists [match1, match2, ...] of tuples
# [ [(subgraph.element, host.element), ..], ...]
#For now, two functions are provided, subgraphIso and subgraphHomo,
#for inductive and non-inductive matches. Those two functions run the same
#algorithm solving a constraint satisfaction problem with different rules to prune the search tree.
#and a different check to verify if the current extension is legal
#Ullman's test is used while solving subgraph isomorphism.
subgraph = Graph(ID="subgraph", label="PrimitiveElementsGraph")
subgraph["oneInt"] = Int(label="Int", value=444)
subgraph["twoInt"] = Int(label="Int", value=444)
subgraph.connect("oneInt", "twoInt")
#creating the match object..
m = Match(subgraph, root)
print "Finding one match: \n", m.subgraphIso()
print "connecting elements deeper in the hierarchy.."
root["internalGraph"].connect("i2", "i3")
print "Finding two matches: \n", m.subgraphIso()
#Graph can also be exported to a simple xml (agl, for a graph language).
#One file will be generated for each graph in the exported graph, connections
#are stored in the lowest common parent. Generating xml is quite simple.
#Create a generator object, implementing the algorithm:
#it takes a graph and a directory as an argument
#you can also specify indendation size (default is two space)
#if you want unzipped agl, you must also specify it (it generates zipped stuff by default)
print "generating files in the current directory"
gen = AGLGenerator(root, directory="", indentSize=" ", unzip=True)
gen.genCode()
#Similarly, to load, create a loader specifying the search path
loader = AGLLoader(directory="")
#then, you can load the graphs *independently* !
loadedRoot = loader.load("Root")
print "Comparing loaded graphs: "
print loadedRoot.equals(root)
#Unique ID should be specified
loadedInternal = loader.load("Root.internalGraph")
print "Comparing loaded internal graphs:"
print loadedInternal.equals(root.remove("internalGraph"))