def grid_and_non_grid():
    """
    return networkplan GeoGraph with grid and non-grid components

               0       2
               |       |
             +-6-+     1   3-4-5
              (inf)

    where node 3 is a fake node connecting node 0 to the grid

    """
    node_coords = np.array([[0.0, 1.0],
                            [4.0, 0.0],
                            [4.0, 1.0],
                            [5.0, 0.0],
                            [6.0, 0.0],
                            [7.0, 0.0],
                            [0.0, 0.0]])

    grid = GeoGraph(gm.PROJ4_FLAT_EARTH, dict(enumerate(node_coords)))
    budget_values = [5, 5, 5, 5, 5, 5, np.inf]
    nx.set_node_attributes(grid, 'budget', dict(enumerate(budget_values)))
    grid.add_edges_from([(0, 6), (1, 2), (3, 4), (4, 5)])

    return grid
Example #2
0
def simple_nodes_disjoint_grid():
    """
    return disjoint net plus nodes with fakes
    fakes are associated with disjoint subnets

    nodes by id (budget in parens)


           (5) 0-------1 (5)
               |       |
             +-+-+   +-+-+  <-- disjoint existing grid

    Useful for testing treating existing grid as single grid
    vs disjoint

    """
    # setup grid
    grid_coords = np.array([[-1.0, 0.0], [1.0, 0.0], [3.0, 0.0], [5.0, 0.0]])
    grid = GeoGraph(gm.PROJ4_FLAT_EARTH,
                    {'grid-' + str(n): c
                     for n, c in enumerate(grid_coords)})
    nx.set_node_attributes(grid, 'budget', {n: 0 for n in grid.nodes()})
    grid.add_edges_from([('grid-0', 'grid-1'), ('grid-2', 'grid-3')])

    # setup input nodes
    node_coords = np.array([[0.0, 1.0], [4.0, 1.0]])
    nodes = GeoGraph(gm.PROJ4_FLAT_EARTH, dict(enumerate(node_coords)))
    budget_values = [5, 5]
    nx.set_node_attributes(nodes, 'budget', dict(enumerate(budget_values)))

    fakes = [2, 3]
    return grid, nodes, fakes
Example #3
0
def simple_nodes_disjoint_grid():
    """
    return disjoint net plus nodes with fakes
    fakes are associated with disjoint subnets

    nodes by id (budget in parens)

                
           (5) 0-------1 (5)
               |       |
             +-+-+   +-+-+  <-- disjoint existing grid

    Useful for testing treating existing grid as single grid
    vs disjoint 

    """
    # setup grid
    grid_coords = np.array([[-1.0, 0.0], [1.0, 0.0], [3.0, 0.0], [5.0, 0.0]])
    grid = GeoGraph(gm.PROJ4_FLAT_EARTH, {'grid-' + str(n): c for n, c in
                    enumerate(grid_coords)})
    nx.set_node_attributes(grid, 'budget', {n: 0 for n in grid.nodes()})
    grid.add_edges_from([('grid-0', 'grid-1'), ('grid-2', 'grid-3')])

    # setup input nodes
    node_coords = np.array([[0.0, 1.0], [4.0, 1.0]])
    nodes = GeoGraph(gm.PROJ4_FLAT_EARTH, dict(enumerate(node_coords)))
    budget_values = [5, 5]
    nx.set_node_attributes(nodes, 'budget', dict(enumerate(budget_values)))

    fakes = [2, 3]
    return grid, nodes, fakes
def dataset_store_to_geograph(dataset_store):
    """
    convenience function for converting a network stored in a dataset_store
    into a GeoGraph

    Args:
        dataset_store containing a network

    Returns:
        GeoGraph representation of dataset_store network

    TODO: determine projection from dataset_store?
    """


    all_nodes = list(dataset_store.cycleNodes()) + \
        list(dataset_store.cycleNodes(isFake=True))
    
    # nodes in output GeoGraph are id'd from 0 to n (via enumerate)
    np_to_nx_id = {node.id: i for i, node in enumerate(all_nodes)}

    coords = [node.getCommonCoordinates() for node in all_nodes]
    coords_dict = dict(enumerate(coords))

    G = GeoGraph(coords=coords_dict)

    # only set population, system and budget for now
    # TODO:  Do we need all from the output?
    for i, node in enumerate(all_nodes):
        if not node.is_fake:
            properties = {
                'budget': node.metric,
                'population': node.output['demographics']['population count'],
                'system': node.output['metric']['system']
            }
            G.node[i] = properties
     

    def seg_to_nx_ids(seg):
        """
        Return the networkx segment ids
        """
        return (np_to_nx_id[seg.node1_id],
                np_to_nx_id[seg.node2_id])

    edges = [seg_to_nx_ids(s) for s in
             dataset_store.cycleSegments(is_existing=False)]
    edge_weights = {seg_to_nx_ids(s): s.weight for s in
                    dataset_store.cycleSegments(is_existing=False)}
    edge_is_existing = {seg_to_nx_ids(s): s.is_existing for s in
                        dataset_store.cycleSegments(is_existing=False)}
    edge_subnet_id = {seg_to_nx_ids(s): s.subnet_id for s in
                      dataset_store.cycleSegments(is_existing=False)}
    G.add_edges_from(edges)
    nx.set_edge_attributes(G, 'weight', edge_weights)
    nx.set_edge_attributes(G, 'is_existing', edge_is_existing)
    nx.set_edge_attributes(G, 'subnet_id', edge_subnet_id)

    return G
def dataset_store_to_geograph(dataset_store):
    """
    convenience function for converting a network stored in a dataset_store
    into a GeoGraph

    Args:
        dataset_store containing a network

    Returns:
        GeoGraph representation of dataset_store network

    TODO: determine projection from dataset_store?
    """

    all_nodes = list(dataset_store.cycleNodes()) + \
        list(dataset_store.cycleNodes(isFake=True))
    np_to_nx_id = {node.id: i for i, node in enumerate(all_nodes)}

    coords = [node.getCommonCoordinates() for node in all_nodes]
    coords_dict = dict(enumerate(coords))
    budget_dict = {i: node.metric for i, node in enumerate(all_nodes)}

    G = GeoGraph(coords=coords_dict)
    nx.set_node_attributes(G, 'budget', budget_dict)

    def seg_to_nx_ids(seg):
        """
        Return the networkx segment ids
        """
        return (np_to_nx_id[seg.node1_id],
                np_to_nx_id[seg.node2_id])

    edges = [seg_to_nx_ids(s) for s in
             dataset_store.cycleSegments(is_existing=False)]
    edge_weights = {seg_to_nx_ids(s): s.weight for s in
                    dataset_store.cycleSegments(is_existing=False)}
    edge_is_existing = {seg_to_nx_ids(s): s.is_existing for s in
                        dataset_store.cycleSegments(is_existing=False)}
    edge_subnet_id = {seg_to_nx_ids(s): s.subnet_id for s in
                      dataset_store.cycleSegments(is_existing=False)}
    G.add_edges_from(edges)
    nx.set_edge_attributes(G, 'weight', edge_weights)
    nx.set_edge_attributes(G, 'is_existing', edge_is_existing)
    nx.set_edge_attributes(G, 'subnet_id', edge_subnet_id)

    return G
Example #6
0
def generate_mst(coords):
    """ 
    Generate a min spanning tree based on coordinate 
    distances
    """
    input_proj = gm.PROJ4_LATLONG
    if gm.is_in_lon_lat(coords):
        input_proj = gm.PROJ4_LATLONG
    else:
        input_proj = gm.PROJ4_FLAT_EARTH

    node_dict = dict(enumerate(coords))

    geo_nodes = GeoGraph(input_proj, node_dict)
    geo_full = geo_nodes.get_connected_weighted_graph()
    geo_mst = nx.minimum_spanning_tree(geo_full)
    geo_nodes.add_edges_from(geo_mst.edges(data=True))
    return geo_nodes
Example #7
0
def test_load_write_json():
    """
    ensure that reading/writing js 'node-link' format works
    """

    os.mkdir('test/tmp')
    node_dict = {0: [0,0], 1: [0,1], 2: [1,0], 3: [1,1]}
    g = GeoGraph(gm.PROJ4_LATLONG, node_dict)
    g.add_edges_from([(0,1),(1,2),(2,3)])
    nio.write_json(g, open('test/tmp/g.js', 'w'))

    g2 = nio.load_json(open('test/tmp/g.js', 'r'))
    os.remove('test/tmp/g.js')
    os.rmdir('test/tmp')
    assert nx.is_isomorphic(g, g2,
                            node_match=operator.eq,
                            edge_match=operator.eq),\
           "expected written and read graphs to match"
Example #8
0
def test_load_write_json():
    """
    ensure that reading/writing js 'node-link' format works
    """

    os.mkdir(os.path.join('test', 'tmp'))
    node_dict = {0: [0,0], 1: [0,1], 2: [1,0], 3: [1,1]}
    g = GeoGraph(gm.PROJ4_LATLONG, node_dict)
    g.add_edges_from([(0,1),(1,2),(2,3)])
    json_file_path = os.path.join('test', 'tmp', 'g.json')
    nio.write_json(g, open(json_file_path, 'w'))

    g2 = nio.read_json_geograph(json_file_path)
    os.remove(json_file_path)
    os.rmdir(os.path.join('test', 'tmp'))
    assert nx.is_isomorphic(g, g2,
                            node_match=operator.eq,
                            edge_match=operator.eq),\
           "expected written and read graphs to match"
Example #9
0
def grid_and_non_grid():
    """
    return networkplan GeoGraph with grid and non-grid components

               0       2
               |       |
             +-6-+     1   3-4-5
              (inf)

    where node 3 is a fake node connecting node 0 to the grid

    """
    node_coords = np.array([[0.0, 1.0], [4.0, 0.0], [4.0, 1.0], [5.0, 0.0],
                            [6.0, 0.0], [7.0, 0.0], [0.0, 0.0]])

    grid = GeoGraph(gm.PROJ4_FLAT_EARTH, dict(enumerate(node_coords)))
    budget_values = [5, 5, 5, 5, 5, 5, np.inf]
    nx.set_node_attributes(grid, 'budget', dict(enumerate(budget_values)))
    grid.add_edges_from([(0, 6), (1, 2), (3, 4), (4, 5)])

    return grid
Example #10
0
def nodes_plus_existing_grid():
    """
    return net plus existing grid with certain properties for testing
    nodes by id (budget in parens)

           1 (3)
            \
             \
               0 (2)
               |       2 (5)
               |       |
     +-+-+-+-+-+-+-+-+-+-+  <-- existing grid

    """

    # setup grid
    grid_coords = np.array([[-5.0, 0.0], [5.0, 0.0]])
    grid = GeoGraph(gm.PROJ4_FLAT_EARTH,
                    {'grid-' + str(n): c
                     for n, c in enumerate(grid_coords)})
    nx.set_node_attributes(grid, 'budget', {n: 0 for n in grid.nodes()})
    grid.add_edges_from([('grid-0', 'grid-1')])

    # setup input nodes
    node_coords = np.array([[0.0, 2.0], [-1.0, 4.0], [4.0, 1.0]])
    nodes = GeoGraph(gm.PROJ4_FLAT_EARTH, dict(enumerate(node_coords)))
    budget_values = [2, 3, 5]
    nx.set_node_attributes(nodes, 'budget', dict(enumerate(budget_values)))

    # setup resulting edges when creating msf through the sequence of nodes
    # Note: Fake nodes integer label begins at the total number of nodes + 1
    # Hence why the fake node in the test is incremented by one on each
    # iteration
    edges_at_iteration = [
        [(0, 1)],  # 0 connects to fake_node
        [(0, 2)],  # 0, 1 can't connect
        [(0, 3), (2, 5), (1, 0)]
    ]  # 2 connects grid

    return grid, nodes, edges_at_iteration
Example #11
0
def nodes_plus_existing_grid():
    """
    return net plus existing grid with certain properties for testing
    nodes by id (budget in parens)

           1 (3)
            \
             \
               0 (2)
               |       2 (5)
               |       |
     +-+-+-+-+-+-+-+-+-+-+  <-- existing grid

    """

    # setup grid
    grid_coords = np.array([[-5.0, 0.0], [5.0, 0.0]])
    grid = GeoGraph(gm.PROJ4_FLAT_EARTH, {'grid-' + str(n): c for n, c in
                    enumerate(grid_coords)})
    nx.set_node_attributes(grid, 'budget', {n: 0 for n in grid.nodes()})
    grid.add_edges_from([('grid-0', 'grid-1')])

    # setup input nodes
    node_coords = np.array([[0.0, 2.0], [-1.0, 4.0], [4.0, 1.0]])
    nodes = GeoGraph(gm.PROJ4_FLAT_EARTH, dict(enumerate(node_coords)))
    budget_values = [2, 3, 5]
    nx.set_node_attributes(nodes, 'budget', dict(enumerate(budget_values)))

    # setup resulting edges when creating msf through the sequence of nodes
    # Note: Fake nodes integer label begins at the total number of nodes + 1
    # Hence why the fake node in the test is incremented by one on each
    # iteration
    edges_at_iteration = [[(0, 1)],  # 0 connects to fake_node
                          [(0, 2)],  # 0, 1 can't connect
                          [(0, 3), (2, 5), (1, 0)]] # 2 connects grid

    return grid, nodes, edges_at_iteration
Example #12
0
def nodes_plus_grid():
    """
    Return:  nodes as graph and grid as UnionFind/Rtree combo

    This example input demonstrates the "more" optimal nature
    of mod_boruvka vs mod_kruskal.

                          2(10)
                           |
            1(4)           |
  sqrt(5){ /|              |
          / |              |
         /  | }3           | } 5
     (2)0   |              |
      1{|   |              |
    +-+-3-+-4-+-+-+-+-+-+-+5-+-+-+  <-- existing grid


    In this case, all nodes will be connected via either algorithm,
    but the graph produced by mod_kruskal will have edge (4,1) whereas
    mod_boruvka will produce a graph with edge (0,1).

    Therefore, the mod_boruvka graph is more optimal.
    """

    mv_max_values = [2, 4, 10]
    coords = np.array([[0.0, 1.0], [1.0, 3.0], [10.0, 5.0]])
    coords_dict = dict(enumerate(coords))
    nodes = GeoGraph(gm.PROJ4_FLAT_EARTH, coords=coords_dict)

    nx.set_node_attributes(nodes, 'budget', dict(enumerate(mv_max_values)))

    grid_coords = np.array([[-5.0, 0.0], [15.0, 0.0]])
    grid = GeoGraph(gm.PROJ4_FLAT_EARTH,
                    {'grid-' + str(n): c
                     for n, c in enumerate(grid_coords)})
    nx.set_node_attributes(grid, 'budget', {n: 0 for n in grid.nodes()})
    grid.add_edges_from([('grid-0', 'grid-1')])

    # now find projections onto grid
    rtree = grid.get_rtree_index()
    projected = grid.project_onto(nodes, rtree_index=rtree)
    projected.remove_nodes_from(grid)
    projected.remove_nodes_from(nodes)

    # populate disjoint set of subgraphs
    subgraphs = UnionFind()
    # only one connected component, so just associate all nodes
    # with first node of grid
    parent = grid.nodes()[0]
    subgraphs.add_component(parent, budget=grid.node[parent]['budget'])
    for node in grid.nodes()[1:]:
        subgraphs.add_component(node, budget=grid.node[node]['budget'])
        subgraphs.union(parent, node, 0)

    # and the projected "fake" nodes
    for node in projected.nodes():
        subgraphs.add_component(node, budget=np.inf)
        subgraphs.union(parent, node, 0)

    # add projected nodes to node set
    nodes.add_nodes_from(projected, budget=np.inf)
    # merge coords
    nodes.coords = dict(nodes.coords, **projected.coords)

    return nodes, subgraphs, rtree
def nodes_plus_grid():
    """
    Return:  nodes as graph and grid as UnionFind/Rtree combo

    This example input demonstrates the "more" optimal nature
    of mod_boruvka vs mod_kruskal.

                          2(10)
                           |
            1(4)           |
  sqrt(5){ /|              |
          / |              |
         /  | }3           | } 5
     (2)0   |              |
      1{|   |              |
    +-+-3-+-4-+-+-+-+-+-+-+5-+-+-+  <-- existing grid


    In this case, all nodes will be connected via either algorithm,
    but the graph produced by mod_kruskal will have edge (4,1) whereas
    mod_boruvka will produce a graph with edge (0,1).

    Therefore, the mod_boruvka graph is more optimal.
    """

    mv_max_values = [2, 4, 10]
    coords = np.array([[0.0, 1.0], [1.0, 3.0], [10.0, 5.0]])
    coords_dict = dict(enumerate(coords))
    nodes = GeoGraph(gm.PROJ4_FLAT_EARTH, coords=coords_dict)

    nx.set_node_attributes(nodes, 'budget', dict(enumerate(mv_max_values)))

    grid_coords = np.array([[-5.0, 0.0], [15.0, 0.0]])
    grid = GeoGraph(gm.PROJ4_FLAT_EARTH, {'grid-' + str(n): c for n, c in
                    enumerate(grid_coords)})
    nx.set_node_attributes(grid, 'budget', {n: 0 for n in grid.nodes()})
    grid.add_edges_from([('grid-0', 'grid-1')])

    # now find projections onto grid
    rtree = grid.get_rtree_index()
    projected = grid.project_onto(nodes, rtree_index=rtree)
    projected.remove_nodes_from(grid)
    projected.remove_nodes_from(nodes)

    # populate disjoint set of subgraphs
    subgraphs = UnionFind()
    # only one connected component, so just associate all nodes
    # with first node of grid
    parent = grid.nodes()[0]
    subgraphs.add_component(parent, budget=grid.node[parent]['budget'])
    for node in grid.nodes()[1:]:
        subgraphs.add_component(node, budget=grid.node[node]['budget'])
        subgraphs.union(parent, node, 0)

    # and the projected "fake" nodes
    for node in projected.nodes():
        subgraphs.add_component(node, budget=np.inf)
        subgraphs.union(parent, node, 0)

    # add projected nodes to node set
    nodes.add_nodes_from(projected, budget=np.inf)
    # merge coords
    nodes.coords = dict(nodes.coords, **projected.coords)

    return nodes, subgraphs, rtree
Example #14
0
def dataset_store_to_geograph(dataset_store):
    """
    convenience function for converting a network stored in a dataset_store
    into a GeoGraph

    Args:
        dataset_store containing a network

    Returns:
        GeoGraph representation of dataset_store network

    TODO: determine projection from dataset_store?
    """


    all_nodes = list(dataset_store.cycleNodes()) + \
        list(dataset_store.cycleNodes(isFake=True))

    # nodes in output GeoGraph are id'd from 0 to n (via enumerate)
    np_to_nx_id = {node.id: i for i, node in enumerate(all_nodes)}

    coords = [node.getCommonCoordinates() for node in all_nodes]
    coords_dict = dict(enumerate(coords))

    G = GeoGraph(coords=coords_dict)

    # only set population, system and budget for now
    # TODO:  Do we need all from the output?
    for i, node in enumerate(all_nodes):
        if not node.is_fake:
            properties = {
                'budget': node.metric,
                'population': node.output['demographics']['population count'],
                'system': node.output['metric']['system']
            }
            G.node[i] = properties

    def seg_to_nx_ids(seg):
        """
        Return the networkx segment ids
        """
        return (np_to_nx_id[seg.node1_id], np_to_nx_id[seg.node2_id])

    edges = [
        seg_to_nx_ids(s)
        for s in dataset_store.cycleSegments(is_existing=False)
    ]
    edge_weights = {
        seg_to_nx_ids(s): s.weight
        for s in dataset_store.cycleSegments(is_existing=False)
    }
    edge_is_existing = {
        seg_to_nx_ids(s): s.is_existing
        for s in dataset_store.cycleSegments(is_existing=False)
    }
    edge_subnet_id = {
        seg_to_nx_ids(s): s.subnet_id
        for s in dataset_store.cycleSegments(is_existing=False)
    }
    G.add_edges_from(edges)
    nx.set_edge_attributes(G, 'weight', edge_weights)
    nx.set_edge_attributes(G, 'is_existing', edge_is_existing)
    nx.set_edge_attributes(G, 'subnet_id', edge_subnet_id)

    return G