Example #1
0
def test_transitive_reduction():
    # reduce
    # 1 -> 2 -> 3
    # |         |
    #  ---->----
    # in
    # 1 -> 2 -> 3
    
    G = nx.DiGraph()
    G.add_edges_from([(1, 2), (2, 3), (1, 3)])
    G1 = transitive_reduction(G)

    assert json_graph.node_link_data(G1)['links'] == [{'source': 1, 'target': 2}, {'source': 2, 'target': 3}]

    # reduce 
    #  <- 1 ->
    # |       |
    # 2 --<-- 4
    # |       |
    #  -> 3 ->
    # error : loop
    
    G = nx.DiGraph()
    G.add_edges_from([(1, 2), (2, 3), (3, 4), (1, 4), (4, 2)])

    with pytest.raises(NetworkXError) as excinfo:
        G1 = transitive_reduction(G)
        assert 'Transitive reduction only uniquely defined on directed acyclic graphs' in str(excinfo.value)
Example #2
0
def build_dag(fname: str):
    """ build DAG with Networkx

    Parameters
    ----------
    fname : file containing dependencies
    query    parents
    req3.sql req1.sql,req2.sql

    Returns
    -------
    G : directed graph
    """
    df = pd.read_csv(fname, sep=' ', names=["node", "parents"], header='infer')

    # build DAG
    G = nx.DiGraph()
    for idx, row in df.iterrows():
        node = row["node"]
        for parent in row["parents"].split(','):
            G.add_edge(parent, node)

    # reduce graph
    G = transitive_reduction(G)

    assert is_directed_acyclic_graph(G), "check it is a DAG"

    return G
Example #3
0
def hasse(pairs_in, thresh):
    """
    Draw a hasse diagram showing which treatments/expcombs have significantly
    differences from each other.
    """
    from networkx.algorithms.dag import transitive_reduction
    from networkx.drawing.nx_pylab import draw_networkx
    from networkx.drawing.nx_agraph import graphviz_layout
    import matplotlib.pyplot as plt

    pvalmat, orig_scores, docs = load_pairs_in(pairs_in)
    digraph = mk_sd_graph(pvalmat, thresh)
    digraph = transitive_reduction(digraph)
    layout = graphviz_layout(digraph, prog="dot")
    draw_networkx(digraph, pos=layout)
    plt.show()
Example #4
0
def statistics(graph, reduce=True, verb=True):
    stats = dict()

    # perform transitive reduction
    if reduce:
        from networkx.algorithms.dag import transitive_reduction
        reduced = transitive_reduction(graph)
        stats['reduced'] = reduced

        # git the extra edges that we honestly don't need
        superfluous_edges = graph.edges() - reduced.edges()
        stats['superfluous_edges'] = superfluous_edges
        # if verb:
        # print(superfluous_edges)
    else:
        stats['reduced'] = graph

    # find any cycles
    from networkx.algorithms.cycles import simple_cycles
    cycles = list(simple_cycles(stats['reduced']))
    if verb and len(cycles) > 0:
        print("Found {0} cycles".format(len(cycles)))
    elif verb:
        print("Graph is cycle-free")
    stats['cycles'] = cycles

    # calculate connected components
    # from networkx.algorithms.components import connected_components
    components = list(nx.weakly_connected_components(stats['reduced']))
    if verb:
        print("{0} connected component{1}".format(
            len(components), "" if len(components) == 1 else "s"))
    stats['components'] = components

    # return all the stats we calclulated
    return stats
Example #5
0
def dag(nodenum, initial_edges, ranks_wanted):

    if nodenum == 0:
        return {
            'cocos': [],
            'edges': {
                'present': [],
                'removed': [],
                'closure': [],
                'closing': [],
                'forbidden': []
            },
            'r_to_pq': []
        }

    if nodenum == 1:
        return {
            'cocos': [{
                'nodes': [{
                    'q': 0,
                    'r': 0,
                    'x': 0,
                    'y': 0,
                    'rank': {
                        'min': 0,
                        'max': 0
                    }
                }],
                'edges': [],
                'svg_size': {
                    'x': 0,
                    'y': 0
                },
                'longest_path_length':
                0
            }],
            'edges': {
                'present': [],
                'removed': [],
                'closure': [],
                'closing': [],
                'forbidden': []
            },
            'r_to_pq': [[0, 0]]
        }

    nodes = range(nodenum)

    graph = nx.DiGraph()
    graph.add_nodes_from(nodes)
    graph.add_edges_from(initial_edges)

    if not is_directed_acyclic_graph(graph):
        return 'Error: The graph is not a DAG.'

    # transitive reduction (remove redundant edges)
    graph = transitive_reduction(graph)
    edges = list(graph.edges)
    removed_edges = list(set(initial_edges).difference(set(edges)))

    # transitive closure
    closure_graph = transitive_closure(graph)
    closure_edges = list(closure_graph.edges)
    closing_edges = list(set(closure_edges).difference(set(edges)))

    # forbidden edges (opposite edges of those in the t. c.)
    forbidden_edges = []
    for edge in closure_edges:
        forbidden_edges.append((edge[1], edge[0]))

    # create connected components (works only from undirected graph)
    graph_undir = graph.to_undirected()
    if nx.is_connected(graph_undir):
        result = connected_dag(nodes, edges, ranks_wanted)
        cocos = [result]
    else:
        cocos = []
        nodes_by_component = nx.connected_components(graph_undir)  # generator
        for comp_nodes in nodes_by_component:
            comp_edges = []
            for graph_edge in edges:
                if graph_edge[0] in comp_nodes:
                    comp_edges.append(graph_edge)
            coco = connected_dag(comp_nodes, comp_edges, ranks_wanted)
            cocos.append(coco)

    # r --> (p, q)     (node ID in DAG to pair of coco ID and node ID in coco)
    r_to_pq = [0] * nodenum
    for p, coco in enumerate(cocos):
        for node in coco['nodes']:
            r_to_pq[node['r']] = [p, node['q']]

    return {
        'cocos': cocos,
        'edges': {
            'present': edges,  # edges of the graph
            'removed': removed_edges,  # edges removed in transitive reduction
            'closure': closure_edges,  # transitive closure (present + closing)
            'closing': closing_edges,  # t. c. without present edges
            'forbidden': forbidden_edges  # edges that would create circles
        },
        'r_to_pq': r_to_pq
    }