예제 #1
0
    def ordered_items(self):
        '''
        Yields this graph's nodes and keys in a guaranteed consistent order.

        First: The (weakly) connected components of the graph are put in a
        list. The components are then sorted by the minimum
        (lexicographically-speaking) key they contain. Then, the tree's RNG
        seed is used to shuffle the connected components. A few notes:

            + The components are randomized because strange behavior might
            occur if the nodes are left to be in the same order produced by
            normal iteration. That would make the resulting graph look ugly.

            + The user can set the tree's seed field to help obtain the same
            result every time the program is run on the same input. The user
            can also change the seed to change the layout instead of fiddling
            around with the drawn tree itself.

            + The components are sorted even though they are then immediately
            shuffled again. This is to ensure the rng.shuffle function produces
            the same result for the same seed.

        Second: The keys and node dictionaries for all of the nodes in all of
        the components are then returned in lexicographical order.
        '''
        components = weakly_connected_components(self.graph)
        components = sorted(components,
                            key=lambda component: min(component, key=str))
        rng = random.Random(self.seed)
        rng.shuffle(components)
        for component in components:
            for key in sorted(component, key=str):
                yield key, self[key]
예제 #2
0
def g_treedoubling(g, exact_algo=held_karp, beta=1.0):
    # 1. Dividing the graph into components
    best_msa = None
    best_k = len(g)
    for start_node in g:
        msa = calc_msa(g, start_node)
        one_way_edge_count = len(list(find_one_way_edges(msa.edges, g, beta)))
        if one_way_edge_count < best_k:
            best_msa = msa
            best_k = one_way_edge_count
    msa = best_msa
    one_way_edges = list(find_one_way_edges(msa.edges, g, beta))

    # degenerate case: no one-way edges in msa => just do tree doubling
    if not one_way_edges:
        start_node = next(iter(g.nodes))
        tour = component_path(msa, g.nodes, start_node, start_node)
        tour = metric_shortcut(tour)
        return {'cost': tour_cost(tour, g), 'tour': tour, 'kernel_size': 0}

    for u, v in one_way_edges:
        msa.remove_edge(u, v)

    components = list(weakly_connected_components(msa))

    # 2. Finding a tour of the components
    meta_graph = nx.DiGraph()
    for (c1, nodes_1), (c2, nodes_2) in itertools.permutations(
            enumerate(components), 2):
        min_edge = cheapest_edge_between(nodes_1, nodes_2, g)
        # preserve a reference to the original edge
        u, v = min_edge
        meta_graph.add_edge(c1,
                            c2,
                            weight=g[u][v]['weight'],
                            original=min_edge)

    meta_tour = exact_algo(meta_graph)['tour']
    in_nodes, out_nodes = get_in_and_out_nodes(meta_tour, meta_graph)

    # 3. Finding a Hamilton path for each component
    eulerian_trails = [
        component_path(msa, comp_nodes, in_node,
                       out_node) for comp_nodes, in_node, out_node in zip(
                           components, in_nodes, out_nodes)
    ]

    # 4. Combining the component tour with the paths
    tour = []
    for comp_index in meta_tour:
        tour += eulerian_trails[comp_index]
    tour = metric_shortcut(tour)
    return {
        'cost': tour_cost(tour, g),
        'tour': tour,
        'kernel_size': len(one_way_edges)
    }
예제 #3
0
    def mark_families(self):
        '''
        Mark all families in the tree by adding a 'family' attribute to each
        Member node, which is a dictionary shared by all members of that
        family.
        '''

        # Families are weakly connected components of the members-only graph
        members_only = self.member_subgraph()
        families = weakly_connected_components(members_only)

        # Add a pointer to each member's family subgraph
        for family in families:
            family_dict = {}
            for key in family:
                self[key]['family'] = family_dict
예제 #4
0
from networkx.algorithms.components import weakly_connected_components, strongly_connected_components

with open('graph-components.txt') as f:
    lines = f.readlines()

edgeList = [line.strip().split() for line in lines]

G = nx.DiGraph()
G.add_edges_from(edgeList)

figure(figsize=(14, 6))
ax = plt.subplot(1, 3, 1)
ax.title.set_text("Input graph ")
nx.draw_networkx(G)

weak_components = weakly_connected_components(G)
strong_components = strongly_connected_components(G)

W = [G.subgraph(c).copy() for c in weakly_connected_components(G)]
S = [G.subgraph(c).copy() for c in strongly_connected_components(G)]

weak_component = max(W, key=len)
strong_component = max(S, key=len)

ax = plt.subplot(1, 3, 2)
ax.title.set_text("Weakly Connected Components ")
pos = nx.spring_layout(weak_component)
nx.draw_networkx(weak_component)

ax = plt.subplot(1, 3, 3)
ax.title.set_text("Strongly Connected Components ")
import networkx as nx
import matplotlib.pyplot as plt
import random
from networkx.algorithms.components import weakly_connected_components


colorlist = ['r', 'g', 'b', 'y', 'c', 'm', 'k']

g = nx.read_gexf('../../dataset/graph-small/graph.gexf')

wcc_subgraphs = [g.subgraph(wcc) for wcc in weakly_connected_components(g)]

# There are 7 weakly connected components and we are plotting the three biggest ones
# that represent customers of a specific store. They all have transaction at that POS device.
for i, subgraph in enumerate(wcc_subgraphs):
    randIndex = random.randint(0, len(colorlist) - 1)
    if(len(subgraph.nodes()) > 10):
        plt.subplot(2, 2, i+1)
        nx.draw(subgraph, node_color=colorlist[randIndex])

plt.show()