ReGraph implements a framework for the version control (VC) of graph transformations in hierarchies.
The data structure VersionedHierarchy
allows to store the history of transformations of a hierarchy and perform the following VC operations:
In [1]:
from regraph import NXGraph, NXHierarchy
from regraph.audit import VersionedHierarchy
from regraph.rules import Rule
from regraph import print_graph, plot_rule, plot_graph
Let us start by creating a small hierarchy.
In [2]:
hierarchy = NXHierarchy()
shapes = NXGraph()
shapes.add_nodes_from(["circle", "square"])
hierarchy.add_graph("shapes", shapes)
colors = NXGraph()
colors.add_nodes_from(["white", "black"])
hierarchy.add_graph("colors", colors)
ag = NXGraph()
ag.add_nodes_from(
["wc", "bc", "ws", "bs"])
hierarchy.add_graph("metamodel", ag)
nugget = NXGraph()
nugget.add_nodes_from(
["wc1", "wc2", "bc1", "ws1", "bs2"])
hierarchy.add_graph("data", nugget)
hierarchy.add_typing(
"metamodel", "shapes", {
"wc": "circle",
"bc": "circle",
"ws": "square",
"bs": "square"
})
hierarchy.add_typing(
"metamodel", "colors", {
"wc": "white",
"bc": "black",
"ws": "white",
"bs": "black"
})
hierarchy.add_typing(
"data", "metamodel", {
"wc1": "wc",
"wc2": "wc",
"bc1": "bc",
"ws1": "ws",
"bs2": "bs"
})
hierarchy.add_typing(
"data", "colors", {
"wc1": "white",
"wc2": "white",
"bc1": "black",
"ws1": "white",
"bs2": "black"
})
base = NXGraph()
base.add_nodes_from(["node"])
hierarchy.add_graph("base", base)
hierarchy.add_typing(
"colors",
"base", {
"white": "node",
"black": "node"
})
Let us have a look at the hierarchy and its graphs.
In [3]:
print(hierarchy)
for g in hierarchy.graphs():
print("Graph: ", g, " nodes: ", hierarchy.get_graph(g).nodes())
We pass the hierarchy to the VersionedHierarchy
wrapper that will take care of the version control.
In [4]:
h = VersionedHierarchy(hierarchy)
print("Branches: ", h.branches())
print("Current branch: ", h.current_branch())
Let us create a new branch test1
In [5]:
h.branch("test1")
print("Branches: ", h.branches())
print("Current branch: ", h.current_branch())
We will now rewrite our hierarchy at the current branch of the audit trail
In [6]:
pattern = NXGraph()
pattern.add_nodes_from(["s"])
rule = Rule.from_transform(pattern)
rule.inject_remove_node("s")
rhs_instances, commit_id = h.rewrite(
"shapes",
rule, {"s": "square"},
message="Remove square in shapes")
The rewrite
method of VersionedHierarchy
returns the instances of the RHS of the applied rule in different graphs and the id of the newly created commit corresponding to this rewrite.
In [7]:
print("RHS instances", rhs_instances)
print("Commit ID: ", commit_id)
We switch back to the master
branch.
In [8]:
h.switch_branch("master")
We will now rewrite the hierarchy corresponding to the current branch
In [9]:
pattern = NXGraph()
pattern.add_nodes_from(["wc"])
rule = Rule.from_transform(pattern)
rule.inject_clone_node("wc")
_, clone_commit = h.rewrite(
"metamodel",
rule, {"wc": "wc"},
message="Clone 'wc' in ag")
h.print_history()
In [10]:
print("Clone commit ID: ", clone_commit)
In [11]:
pattern = NXGraph()
pattern.add_nodes_from(["wc1"])
rule = Rule.from_transform(pattern)
rule.inject_add_node("new_node")
rule.inject_add_edge("new_node", "wc1")
_ = h.rewrite(
"data",
rule, {"wc1": "wc1"},
message="Add a new node to 'data'")
We merge the branch test1
in into master
.
In [12]:
h.merge_with("test1")
Out[12]:
In [13]:
h.print_history()
Let us now try to rollback to the commit clone_commit
.
In [14]:
h.rollback(clone_commit)
In [15]:
h.print_history()
print("Branches: ", h.branches())
We can see that the revision history came back to the previous state (right after the clone commit), and we still have two branches master
and test1
.