def test_dag_is_not_tree(): g = Graph.from_lists(("b", "c"), ("d", "e")) assert not g.is_tree() d = Node(Frame(name="d")) diamond_subdag = Node.from_lists(("a", ("b", d), ("c", d))) g = Graph([diamond_subdag]) assert not g.is_tree() g = Graph.from_lists(("e", "f", diamond_subdag), ("g", diamond_subdag, "h")) assert not g.is_tree()
def test_trees_are_trees(): g = Graph.from_lists(("a", )) assert g.is_tree() g = Graph.from_lists(("a", ("b", ("c")))) assert g.is_tree() g = Graph.from_lists(("a", "b", "c")) assert g.is_tree() g = Graph.from_lists(("a", ("b", "e", "f", "g"), ("c", "e", "f", "g"), ("d", "e", "f", "g"))) assert g.is_tree()
def test_filter_squash_with_merge(): r"""Test squash with a simple node merge. a / \ remove bd a b d ----------> | / \ c c c Note that here, because b and d have been removed, a will have only one child called c, which will contain merged (summed) data from the original c rows. """ check_filter_squash( GraphFrame.from_lists(("a", ("b", "c"), ("d", "c"))), lambda row: row["node"].frame["name"] in ("a", "c"), Graph.from_lists(("a", "c")), [3, 2], # a, c ) check_filter_no_squash( GraphFrame.from_lists(("a", ("b", "c"), ("d", "c"))), lambda row: row["node"].frame["name"] in ("a", "c"), 3, # a, c, c )
def test_copy(): d = Node(Frame(name="d")) diamond_subdag = Node.from_lists(("a", ("b", d), ("c", d))) g = Graph.from_lists(("e", "f", diamond_subdag), ("g", diamond_subdag, "h")) assert g.copy() == g
def test_filter_squash_with_rootless_merge(): r"""Test squash on a simple tree with several rootless node merges. a ___/ | \___ remove abcd b c d ------------> e f g /|\ /|\ /|\ e f g e f g e f g Note that here, because b and d have been removed, a will have only one child called c, which will contain merged (summed) data from the original c rows. """ check_filter_squash( GraphFrame.from_lists( ("a", ("b", "e", "f", "g"), ("c", "e", "f", "g"), ("d", "e", "f", "g")) ), lambda row: row["node"].frame["name"] not in ("a", "b", "c", "d"), Graph.from_lists(["e"], ["f"], ["g"]), [3, 3, 3], # e, f, g ) check_filter_no_squash( GraphFrame.from_lists( ("a", ("b", "e", "f", "g"), ("c", "e", "f", "g"), ("d", "e", "f", "g")) ), lambda row: row["node"].frame["name"] not in ("a", "b", "c", "d"), 9, # e, f, g, e, f, g, e, f, g )
def test_filter_squash_diamond(): r"""Test that diamond edges are collapsed when squashing. Ensure we can handle the most basic DAG. a / \ remove bc a b c ----------> | \ / d d """ d = Node(Frame(name="d")) check_filter_squash( GraphFrame.from_lists(("a", ("b", d), ("c", d))), lambda row: row["node"].frame["name"] not in ("b", "c"), Graph.from_lists(("a", "d")), [2, 1], # a, d ) check_filter_no_squash( GraphFrame.from_lists(("a", ("b", d), ("c", d))), lambda row: row["node"].frame["name"] not in ("b", "c"), 2, # a, d )
def test_filter_squash_bunny(): r"""Test squash on a complicated "bunny" shaped graph. This has multiple roots as well as multiple parents that themselves have parents. e g / \ / \ f a h remove abc e g / \ -----------> / \ / \ b c f d h \ / d """ d = Node(Frame(name="d")) diamond = Node.from_lists(("a", ("b", d), ("c", d))) new_d = Node(Frame(name="d")) check_filter_squash( GraphFrame.from_lists(("e", "f", diamond), ("g", diamond, "h")), lambda row: row["node"].frame["name"] not in ("a", "b", "c"), Graph.from_lists(("e", new_d, "f"), ("g", new_d, "h")), [3, 1, 1, 3, 1], # e, d, f, g, h ) check_filter_no_squash( GraphFrame.from_lists(("e", "f", diamond), ("g", diamond, "h")), lambda row: row["node"].frame["name"] not in ("a", "b", "c"), 5, # e, d, f, g, h )
def test_filter_squash_bunny_to_goat(): r"""Test squash on a "bunny" shaped graph: This one is more complex because there are more transitive edges to maintain between the roots (e, g) and b and c. e g e g / \ / \ /|\ /|\ f a h remove ac f | b | h / \ ----------> | | | b c \|/ \ / d d """ d = Node(Frame(name="d")) diamond = Node.from_lists(("a", ("b", d), ("c", d))) new_d = Node(Frame(name="d")) new_b = Node.from_lists(("b", new_d)) check_filter_squash( GraphFrame.from_lists(("e", "f", diamond), ("g", diamond, "h")), lambda row: row["node"].frame["name"] not in ("a", "c"), Graph.from_lists(("e", new_b, new_d, "f"), ("g", new_b, new_d, "h")), [4, 2, 1, 1, 4, 1], # e, b, d, f, g, h ) check_filter_no_squash( GraphFrame.from_lists(("e", "f", diamond), ("g", diamond, "h")), lambda row: row["node"].frame["name"] not in ("a", "c"), 6, # e, b, d, f, g, h )
def test_filter_squash_bunny_to_goat_with_merge(): r"""Test squash on a "bunny" shaped graph: This one is more complex because there are more transitive edges to maintain between the roots (e, g) and b and c. e g / \ / \ f a h remove ac e g / \ ----------> / \ / \ b c f b h \ / b """ b = Node(Frame(name="b")) diamond = Node.from_lists(("a", ("b", b), ("c", b))) new_b = Node(Frame(name="b")) check_filter_squash( GraphFrame.from_lists(("e", "f", diamond), ("g", diamond, "h")), lambda row: row["node"].frame["name"] not in ("a", "c"), Graph.from_lists(("e", new_b, "f"), ("g", new_b, "h")), [4, 2, 1, 4, 1], # e, b, f, g, h ) check_filter_no_squash( GraphFrame.from_lists(("e", "f", diamond), ("g", diamond, "h")), lambda row: row["node"].frame["name"] not in ("a", "c"), 5, # e, b, f, g, h )
def test_traverse_paths(): d = Node(Frame(name="d")) diamond_subdag = Node.from_lists(("a", ("b", d), ("c", d))) g = Graph.from_lists(("e", "f", diamond_subdag), ("g", diamond_subdag, "h")) assert list( g.traverse(attrs="name")) == ["e", "a", "b", "d", "c", "f", "g", "h"]
def test_union_dag(): # make graphs g1, g2, and g3, where you know g3 is the union of g1 and g2 c = Node.from_lists(("c", "d")) g1 = Graph.from_lists(("a", ("b", c), ("e", c, "f"))) d = Node(Frame(name="d")) g2 = Graph.from_lists(("a", ("b", ("c", d)), ("e", d, "f"))) d2 = Node(Frame(name="d")) c2 = Node.from_lists(("c", d2)) g3 = Graph.from_lists(("a", ("b", c2), ("e", c2, d2, "f"))) assert g1 != g2 g4 = g1.union(g2) assert g4 == g3
def test_from_lists(): """Ensure we can traverse roots in correct order without repeating a shared subdag. """ d = Node(Frame(name="d")) diamond_subdag = Node.from_lists(("a", ("b", d), ("c", d))) g = Graph.from_lists(("e", "f", diamond_subdag), ("g", diamond_subdag, "h")) assert list(g.traverse(attrs="name")) == ["e", "a", "b", "d", "c", "f", "g", "h"]
def test_filter_squash(): r"""Test squash on a simple tree with one root. a / \ remove bd a b d ----------> / \ / \ c e c e """ check_filter_squash( GraphFrame.from_lists(("a", ("b", "c"), ("d", "e"))), lambda row: row["node"].frame["name"] in ("a", "c", "e"), Graph.from_lists(("a", "c", "e")), [3, 1, 1], # a, c, e )
def test_filter_squash_different_roots(): r"""Test squash on a simple tree with one root but make multiple roots. a / \ remove a b d b d ---------> / \ / \ c e c e """ check_filter_squash( GraphFrame.from_lists(("a", ("b", "c"), ("d", "e"))), lambda row: row["node"].frame["name"] != "a", Graph.from_lists(("b", "c"), ("d", "e")), [2, 1, 2, 1], # b, c, d, e )
def test_len_chain(): graph = Graph.from_lists(("a", "b", "c", "d", "e")) assert len(graph) == 5
def test_len_diamond(): d = Node(Frame(name="d")) graph = Graph.from_lists(("a", ("b", d), ("c", d))) assert len(graph) == 4
def test_len_tree(): graph = Graph.from_lists(("a", ("b", "d"), ("c", "d"))) assert len(graph) == 5