class KamiGraph: """Graph container data structure. Attributes ---------- graph : nx.(Di)Graph Graph meta_typing : dict Typing of the graph by the meta-model reference_typing : dict Typing of the graph by the reference graph """ def __init__(self, graph=None, meta_typing=None, reference_typing=None): """Initialize graph container.""" if graph: self.graph = NXGraph.copy(graph) else: self.graph = NXGraph() if meta_typing: self.meta_typing = copy.deepcopy(meta_typing) else: self.meta_typing = dict() if reference_typing: self.reference_typing = copy.deepcopy(reference_typing) else: self.reference_typing = dict() return def add_node(self, node_id, attrs=None, meta_typing=None, reference_typing=None): """Add node + typings to a nugget.""" self.graph.add_node(node_id, attrs) if meta_typing: self.meta_typing[node_id] = meta_typing if reference_typing: self.reference_typing[node_id] = reference_typing return def add_node_attrs(self, node_id, attrs): self.graph.add_node_attrs(node_id, attrs) def add_edge(self, s, t, attrs=None): """Add edge between the nodes of a nugget.""" self.graph.add_edge(s, t, attrs) return def remove_node(self, node_id): self.graph.remove_node(node_id) del self.meta_typing[node_id] if node_id in self.reference_typing: del self.reference_typing[node_id] def remove_node_attrs(self, node_id, attrs): self.graph.remove_node_attrs(node_id, attrs) def remove_edge(self, s, t): self.graph.remove_edge(s, t) def nodes(self): """Return a list of nodes of the nugget graph.""" return self.graph.nodes() def edges(self): """Return a list of edges of the nugget graph.""" return self.graph.edges()
def __init__(self): """Initialize hierarchies.""" self.nx_hierarchy = NXHierarchy() try: self.neo4j_hierarchy = Neo4jHierarchy(uri="bolt://localhost:7687", user="******", password="******") self.neo4j_hierarchy._clear() except: warnings.warn("Neo4j is down, skipping Neo4j-related tests") self.neo4j_hierarchy = None g0 = NXGraph() g0.add_node("circle", {"a": {1, 2, 3}}) g0.add_node("square", {"a": {1, 2, 3, 5}}) g0.add_node("triangle", {"new_attrs": {1}}) g0.add_edges_from([ ("circle", "circle"), # , {"b": {1, 2, 3, 4}}), ("circle", "square"), ("square", "circle", { "new_attrs": {2} }), ("square", "triangle", { "new_attrs": {3, 4} }) ]) self.nx_hierarchy.add_graph("g0", g0, {"name": "Shapes"}) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_graph("g0", g0, {"name": "Shapes"}) g00 = NXGraph() g00.add_node('black', {"a": {1, 2, 3}, "new_attrs": {1}}) g00.add_node('white', {"a": {1, 2, 3, 5}}) g00.add_edges_from([('white', 'white', { "new_attrs": 2 }), ('white', 'black', { "new_attrs": {4, 3} }), ('black', 'black'), ('black', 'white')]) self.nx_hierarchy.add_graph("g00", g00, {"name": "Colors"}) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_graph("g00", g00, {"name": "Colors"}) g1 = NXGraph() g1.add_nodes_from([("black_circle", { "a": {1, 2, 3} }), "white_circle", "black_square", ("white_square", { "a": {1, 2} }), "black_triangle", "white_triangle"]) g1.add_edges_from([ ("black_circle", "black_circle"), # {"b": {1, 2, 3, 4}}), ("black_circle", "white_circle"), ("black_circle", "black_square"), ("white_circle", "black_circle"), ("white_circle", "white_square"), ("black_square", "black_circle"), ("black_square", "black_triangle"), ("black_square", "white_triangle"), ("white_square", "white_circle"), ("white_square", "black_triangle"), ("white_square", "white_triangle") ]) self.nx_hierarchy.add_graph("g1", g1) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_graph("g1", g1) self.nx_hierarchy.add_typing( "g1", "g0", { "black_circle": "circle", "white_circle": "circle", "black_square": "square", "white_square": "square", "black_triangle": "triangle", "white_triangle": "triangle" }) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_typing( "g1", "g0", { "black_circle": "circle", "white_circle": "circle", "black_square": "square", "white_square": "square", "black_triangle": "triangle", "white_triangle": "triangle" }) self.nx_hierarchy.add_typing( "g1", "g00", { "black_square": "black", "black_circle": "black", "black_triangle": "black", "white_square": "white", "white_circle": "white", "white_triangle": "white" }) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_typing( "g1", "g00", { "black_square": "black", "black_circle": "black", "black_triangle": "black", "white_square": "white", "white_circle": "white", "white_triangle": "white" }) g2 = NXGraph() g2.add_nodes_from([ (1, { "a": {1, 2} }), 2, 3, 4, (5, { "a": {1} }), 6, 7, ]) g2.add_edges_from([ (1, 2), # {"b": {1, 2, 3}}), (2, 3), (3, 6), (3, 7), (4, 2), (4, 5), (5, 7) ]) self.nx_hierarchy.add_graph("g2", g2) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_graph("g2", g2) self.nx_hierarchy.add_typing( "g2", "g1", { 1: "black_circle", 2: "black_circle", 3: "black_square", 4: "white_circle", 5: "white_square", 6: "white_triangle", 7: "black_triangle" }) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_typing( "g2", "g1", { 1: "black_circle", 2: "black_circle", 3: "black_square", 4: "white_circle", 5: "white_square", 6: "white_triangle", 7: "black_triangle" }) g3 = NXGraph() g3.add_nodes_from([ (1), # {"a": {1, 2}}), 2, 3, 5, (4), # {"a": {1}}), 6, 7, ]) g3.add_edges_from([ (1, 1), # , {"b": {1, 2, 3}}), (1, 2), (1, 3), (1, 5), (2, 1), (3, 4), (4, 7), (4, 6), (5, 6), (5, 7) ]) self.nx_hierarchy.add_graph("g3", g3) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_graph("g3", g3) self.nx_hierarchy.add_typing( "g3", "g1", { 1: "black_circle", 2: "white_circle", 3: "white_circle", 5: "black_square", 4: "white_square", 6: "white_triangle", 7: "black_triangle" }) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_typing( "g3", "g1", { 1: "black_circle", 2: "white_circle", 3: "white_circle", 5: "black_square", 4: "white_square", 6: "white_triangle", 7: "black_triangle" }) g4 = NXGraph() g4.add_nodes_from([1, 2, 3]) g4.add_edges_from([(1, 2), (2, 3)]) self.nx_hierarchy.add_graph("g4", g4) self.nx_hierarchy.add_typing("g4", "g2", {1: 2, 2: 3, 3: 6}) self.nx_hierarchy.add_typing("g4", "g3", {1: 1, 2: 5, 3: 6}) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_graph("g4", g4) self.neo4j_hierarchy.add_typing("g4", "g2", {1: 2, 2: 3, 3: 6}) self.neo4j_hierarchy.add_typing("g4", "g3", {1: 1, 2: 5, 3: 6}) g5 = NXGraph() g5.add_nodes_from([ ("black_circle"), # {"a": {255}}), ("black_square"), # {"a": {256}}), ("white_triangle"), # {"a": {257}}), ("star") # , {"a": {258}}) ]) g5.add_edges_from([ ("black_circle", "black_square"), ("black_square", "white_triangle"), # , {"b": {11}}), ("star", "black_square"), ("star", "white_triangle") ]) self.nx_hierarchy.add_graph("g5", g5) if self.neo4j_hierarchy: self.neo4j_hierarchy.add_graph("g5", g5)
def __init__(self): D = NXGraph() D.add_node('square') D.add_node('circle') D.add_node('dark_square') D.add_node('dark_circle') D.add_edge('square', 'circle') D.add_edge('circle', 'dark_circle') D.add_edge('circle', 'dark_square') D.add_edge('circle', 'circle') self.D = D A = NXGraph() A.add_node(2) A.add_node(3) A.add_edge(2, 3) self.A = A B = NXGraph() B.add_node(1) B.add_node(2) B.add_node(3) B.add_edge(1, 2) B.add_edge(2, 3) self.B = B C = NXGraph() C.add_node(2) C.add_node(3) C.add_node('dark_square') C.add_edge(2, 3) C.add_edge(2, 'dark_square') C.add_edge(2, 2) self.C = C self.homAB = { 2: 2, 3: 3 } self.homAC = { 2: 2, 3: 3 } self.homBD = { 1: 'square', 2: 'circle', 3: 'dark_circle' } self.homCD = { 2: 'circle', 3: 'dark_circle', 'dark_square': 'dark_square' }
def test_graph_rollback(self): g = VersionedGraph(self.initial_graph) # Branch 'test' g.branch("test") pattern = NXGraph() pattern.add_node("square") rule = Rule.from_transform(pattern) # _, rhs_clone = rule.inject_clone_node("square") g.rewrite( rule, {"square": "square"}, "Clone square") # Switch to master g.switch_branch("master") print("\n\n\nasserting...............") for s, t in g._revision_graph.edges(): print(g._revision_graph.nodes[s]["message"]) print(g._revision_graph.nodes[t]["message"]) d = g._revision_graph.adj[s][t]["delta"] assert( set(d["rule"].rhs.nodes()) == set(d["rhs_instance"].keys()) ) # Add edge and triangle pattern = NXGraph() pattern.add_nodes_from(["circle"]) rule = Rule.from_transform(pattern) # _, rhs_clone = rule.inject_add_edge("circle", "circle") rule.inject_add_node("triangle") rule.inject_add_edge("triangle", "circle") rhs_instance, _ = g.rewrite( rule, {"circle": "circle"}, "Add edge to circle and triangle") triangle = rhs_instance["triangle"] # Clone circle pattern = NXGraph() pattern.add_node("circle") rule = Rule.from_transform(pattern) _, rhs_clone = rule.inject_clone_node("circle") rhs_instance, rollback_commit = g.rewrite( rule, {"circle": "circle"}, "Clone circle") rhs_circle_clones = list({ rule.p_rhs[p] for p in rule.cloned_nodes()["circle"] }) # Remove original circle pattern = NXGraph() pattern.add_node("circle") rule = Rule.from_transform(pattern) rule.inject_remove_node("circle") rhs_instance, _ = g.rewrite( rule, {"circle": rhs_instance[rhs_circle_clones[0]]}, message="Remove circle") # Merge circle clone and triangle pattern = NXGraph() pattern.add_nodes_from(["circle", "triangle"]) rule = Rule.from_transform(pattern) rule.inject_merge_nodes(["circle", "triangle"]) rhs_instance, _ = g.rewrite( rule, { "circle": rhs_instance[rhs_clone], "triangle": triangle }, message="Merge circle and triangle") g.print_history() g.rollback(rollback_commit) g.merge_with("test")
class TestGraphClasses: """Main test class.""" def __init__(self): """Initialize test object.""" self.nx_graph = NXGraph() try: self.neo4j_graph = Neo4jGraph(uri="bolt://localhost:7687", user="******", password="******") self.neo4j_graph._clear() except: warnings.warn("Neo4j is down, skipping Neo4j-related tests") self.neo4j_graph = None node_list = [("b", { "name": "Bob", "age": 20 }), ("a", { "name": "Alice", "age": 35 }), ("d", { "name": "dummy" })] edge_list = [("a", "b", { "type": "friends", "since": 1999 }), ("d", "a"), ("b", "d")] self.nx_graph.add_nodes_from(node_list) self.nx_graph.add_edges_from(edge_list) if self.neo4j_graph: self.neo4j_graph.add_nodes_from(node_list) self.neo4j_graph.add_edges_from(edge_list) node = "c" attrs = {"name": "Claire", "age": 66} self.nx_graph.add_node(node, attrs) if self.neo4j_graph: self.neo4j_graph.add_node(node, attrs) edge_attrs = {"type": "parent"} self.nx_graph.add_edge("c", "b", edge_attrs) if self.neo4j_graph: self.neo4j_graph.add_edge("c", "b", edge_attrs) self.nx_graph.remove_edge("d", "a") if self.neo4j_graph: self.neo4j_graph.remove_edge("d", "a") self.nx_graph.remove_node("d") if self.neo4j_graph: self.neo4j_graph.remove_node("d") self.nx_graph.update_node_attrs("a", {"name": "Alison"}) if self.neo4j_graph: self.neo4j_graph.update_node_attrs("a", {"name": "Alison"}) self.nx_graph.update_edge_attrs("a", "b", {"type": "enemies"}) if self.neo4j_graph: self.neo4j_graph.update_edge_attrs("a", "b", {"type": "enemies"}) self.nx_graph.set_node_attrs("a", {"age": 19}, update=False) if self.neo4j_graph: self.neo4j_graph.set_node_attrs("a", {"age": 19}, update=False) self.nx_graph.set_edge_attrs("a", "b", {"since": 1945}, update=False) if self.neo4j_graph: self.neo4j_graph.set_edge_attrs("a", "b", {"since": 1945}, update=False) self.nx_graph.add_node_attrs("a", {"gender": {"M", "F"}}) if self.neo4j_graph: self.neo4j_graph.add_node_attrs("a", {"gender": {"M", "F"}}) self.nx_graph.add_edge_attrs("a", "b", {"probability": 0.5}) if self.neo4j_graph: self.neo4j_graph.add_edge_attrs("a", "b", {"probability": 0.5}) self.nx_graph.remove_node_attrs("a", {"gender": "F"}) if self.neo4j_graph: self.neo4j_graph.remove_node_attrs("a", {"gender": "F"}) self.nx_graph.remove_edge_attrs("a", "b", {"probability": 0.5}) if self.neo4j_graph: self.neo4j_graph.remove_edge_attrs("a", "b", {"probability": 0.5}) clone_id = self.nx_graph.clone_node("b", "b_clone") if self.neo4j_graph: self.neo4j_graph.clone_node("b", "b_clone") # Test relabeling self.nx_graph.relabel_node("b", "baba") if self.neo4j_graph: self.neo4j_graph.relabel_node("b", "baba") self.nx_graph.relabel_node("baba", "b") if self.neo4j_graph: self.neo4j_graph.relabel_node("baba", "b") self.nx_graph.relabel_nodes({ clone_id: "lala", "b": "b1", "a": "a1", "c": "c1" }) if self.neo4j_graph: self.neo4j_graph.relabel_nodes({ clone_id: "lala", "b": "b1", "a": "a1", "c": "c1" }) self.nx_graph.relabel_nodes({ "b1": "b", "a1": "a", "c1": "c", "lala": clone_id }) if self.neo4j_graph: self.neo4j_graph.relabel_nodes({ "b1": "b", "a1": "a", "c1": "c", "lala": clone_id }) self.nx_graph.merge_nodes(["b", "c"]) if self.neo4j_graph: self.neo4j_graph.merge_nodes(["b", "c"]) self.nx_graph.copy_node("a", "a_copy") if self.neo4j_graph: self.neo4j_graph.copy_node("a", "a_copy") # Test find matching pattern = NXGraph() pattern.add_nodes_from(["x", ("y", {"name": "Claire"}), "z"]) pattern.add_edges_from([("x", "y"), ("y", "y"), ("y", "z")]) instances1 = self.nx_graph.find_matching(pattern) if self.neo4j_graph: instances2 = self.neo4j_graph.find_matching(pattern) assert (instances1 == instances2) rule = Rule.from_transform(pattern) p_n, r_n = rule.inject_clone_node("y") rule.inject_remove_edge(p_n, "y") rule.inject_remove_edge("y", "y") rule.inject_add_node("w", {"name": "Frank"}) rule.inject_add_edge("w", r_n, {"type": "parent"}) rhs_g1 = self.nx_graph.rewrite(rule, instances1[0]) if self.neo4j_graph: rhs_g2 = self.neo4j_graph.rewrite(rule, instances1[0]) self.nx_graph.relabel_node(rhs_g1[r_n], "b") if self.neo4j_graph: self.neo4j_graph.relabel_node(rhs_g2[r_n], "b") self.nx_graph.relabel_node(rhs_g1["y"], "c") if self.neo4j_graph: self.neo4j_graph.relabel_node(rhs_g2["y"], "c") # Test the two obtained graphs are the same assert (self.nx_graph == self.neo4j_graph) assert (set(self.nx_graph.predecessors("b")) == set( self.neo4j_graph.predecessors("b"))) assert (set(self.nx_graph.successors("a")) == set( self.neo4j_graph.successors("a"))) assert ( self.nx_graph.get_node("c") == self.neo4j_graph.get_node("c")) assert (self.nx_graph.get_edge("c", "b") == self.neo4j_graph.get_edge( "c", "b")) def test_getters(self): """Test various getters.""" if self.neo4j_graph: assert (set(self.nx_graph.nodes()) == set( self.neo4j_graph.nodes())) assert (set(self.nx_graph.edges()) == set( self.neo4j_graph.edges())) self.neo4j_graph.nodes(data=True) self.neo4j_graph.edges(data=True) assert ( self.nx_graph.get_node("a") == self.neo4j_graph.get_node("a")) assert (self.nx_graph.get_edge("a", "b") == self.neo4j_graph.get_edge( "a", "b")) assert (set(self.nx_graph.in_edges("b")) == set( self.neo4j_graph.in_edges("b"))) assert (set(self.nx_graph.out_edges("a")) == set( self.neo4j_graph.out_edges("a"))) def test_load_export(self): self.nx_graph.export("nxgraph.json") if self.neo4j_graph: self.neo4j_graph.export("neo4jgraph.json") g1 = NXGraph.load("nxgraph.json") if self.neo4j_graph: p = Neo4jGraph(driver=self.neo4j_graph._driver, node_label="new_node", edge_label="new_edge") p._clear() g2 = Neo4jGraph.load(driver=self.neo4j_graph._driver, filename="neo4jgraph.json", node_label="new_node", edge_label="new_edge") assert (g1 == g2)