Beispiel #1
0
def validate_network(graph: Dict) -> Dict[str, Union[bool, List]]:
    """

    Parameters
    ----------
    graph : dict
        graph in graph-dict format.
        For example:
        graph = {
            "directed": True,
            "nodes": [{"id": "A"}, {"id": "B"}],
            "edges": [{"source": "A", "target": "B"}],
        }

    """

    _graph = thin_graph_dict(graph)
    G = graph_factory(_graph)

    isvalid = validate.is_valid(G)

    result: Dict[str, Union[bool, List]] = {"isvalid": isvalid}

    if isvalid:
        return result

    else:
        _keys = [
            "node_cycles", "edge_cycles", "multiple_out_edges",
            "duplicate_edges"
        ]
        for key, value in zip(_keys, validate.validate_network(G)):
            result[key] = value

        return result
Beispiel #2
0
def solution_sequence(
    graph: Dict[str, Any], min_branch_size: int
) -> Dict[str, Dict[str, List[Dict[str, List[Dict[str, Union[str, Dict]]]]]]]:

    _graph = thin_graph_dict(graph)  # strip unneeded metadata

    G = graph_factory(_graph)

    _sequence = parallel_sequential_subgraph_nodes(G, min_branch_size)

    sequence = {
        "parallel": [{
            "series": [{
                "nodes": [{
                    "id": n
                } for n in nodes]
            } for nodes in series]
        } for series in _sequence]
    }

    result: Dict[str, Any] = {"graph": _graph}
    result["min_branch_size"] = min_branch_size
    result["solution_sequence"] = sequence

    return result
Beispiel #3
0
def test_post_solve_watershed_stable(client, watershed_requests,
                                     watershed_responses, watershed_test_case):

    size, pct_tmnt, dirty_nodes = watershed_test_case
    watershed_request = watershed_requests[size, pct_tmnt]
    post_response = watershed_responses[size, pct_tmnt]

    results = post_response.json()["data"]["results"]

    reqd_min_attrs = attrs_to_resubmit(results)
    previous_results = {
        "previous_results":
        [{k: dct[k]
          for k in dct.keys() if k in reqd_min_attrs + ["node_id"]}
         for dct in results]
    }

    g = graph_factory(watershed_request["graph"])

    subg = nx.DiGraph(g.subgraph(get_subset(g, nodes=dirty_nodes)).edges)
    subgraph = {"graph": nxGraph_to_dict(subg)}

    new_request = deepcopy(watershed_request)
    new_request.update(subgraph)
    new_request.update(previous_results)

    payload = json.dumps(new_request)
    route = config.API_LATEST + "/watershed/solve"
    response = client.post(route, data=payload)

    subgraph_results = response.json()["data"]["results"]

    check_subgraph_response_equal(subgraph_results, results)
Beispiel #4
0
def test_watershed_solve_sequence(contexts, watershed_requests, n_nodes,
                                  pct_tmnt):

    watershed_request = deepcopy(watershed_requests[n_nodes, pct_tmnt])
    context = contexts["default"]

    g = graph_factory(watershed_request["graph"])

    initial_results = land_surface_loading(watershed_request,
                                           False,
                                           context=context)["summary"]
    db = pandas.DataFrame(initial_results).set_index("node_id")

    _node_list = solution_sequence(
        watershed_request["graph"],
        16)["solution_sequence"]["parallel"][0]["series"]
    node_list = [[n["id"] for n in nl["nodes"]] for nl in _node_list]

    presults = []  # no initial results, obvs
    for branch_nodes in node_list:

        # this subgraph is empty, has no data.
        subg = nx.DiGraph(g.subgraph(branch_nodes).edges)
        subgraph = {"graph": nxGraph_to_dict(subg)}
        reqd_min_attrs = attrs_to_resubmit(presults)
        previous_results = {
            "previous_results": [{
                k: dct[k]
                for k in dct.keys() if k in reqd_min_attrs + ["node_id"]
            } for dct in presults if dct["node_id"] in subg.nodes()]
        }

        subg_request = deepcopy(watershed_request)
        subg_request.update(subgraph)
        subg_request.update(previous_results)

        subgraph_response_dict = solve_watershed(
            subg_request,
            False,
            context=context,
        )
        subgraph_results = subgraph_response_dict["results"]

        presults.extend(subgraph_results)
        db = db.combine_first(
            pandas.DataFrame(subgraph_results).set_index("node_id"))

    response_dict = solve_watershed(
        watershed=watershed_request,
        treatment_pre_validated=False,
        context=context,
    )
    results = response_dict["results"] + response_dict["leaf_results"]

    check_db = pandas.DataFrame(results).set_index("node_id").sort_index(0)
    check_results_dataframes(db.sort_index(0), check_db)
Beispiel #5
0
def test_round_trip_dict_to_dict(graph_dict_isvalid):
    graph_dict, isvalid = graph_dict_isvalid

    # round trips back to dictionaries are only possible if graph is directed.
    # this is because if the graph is undirected, then the 'source' and 'target'
    # keys _might_ be swapped.
    # if graph_dict['directed']:
    _g = utils.graph_factory(graph_dict)
    rt_graph_dict = utils.nxGraph_to_dict(_g)
    assert is_equal_subset(graph_dict, rt_graph_dict)
Beispiel #6
0
def test_thin_graph_dict_roundtrip_graph_to_graph(graph_obj_isvalid):

    graph_obj, isvalid = graph_obj_isvalid

    _g = utils.thin_graph_dict(utils.nxGraph_to_dict(graph_obj))

    rt_Graph = utils.graph_factory(_g)

    assert rt_Graph.is_directed() == graph_obj.is_directed()
    assert rt_Graph.is_multigraph() == graph_obj.is_multigraph()
    assert nx.is_isomorphic(rt_Graph, graph_obj)
Beispiel #7
0
def test_thin_graph_dict_roundtrip_dict_to_dict(graph_dict_isvalid, check):

    graph_dict, isvalid = graph_dict_isvalid

    _graph_dict = utils.thin_graph_dict(graph_dict)

    _g = utils.graph_factory(_graph_dict)
    rt_graph_dict = utils.nxGraph_to_dict(_g)

    # if it's in the input, check that it's in the output too.
    if graph_dict.get(check, None) is not None:
        assert is_equal_subset(rt_graph_dict[check], graph_dict[check])
Beispiel #8
0
def test_clean_graph_object(graph_obj_isvalid):

    graph_obj, isvalid = graph_obj_isvalid
    clean_graph_dict = utils.clean_graph_dict(graph_obj)

    assert all([isinstance(n["id"], str) for n in clean_graph_dict["nodes"]])
    assert all([isinstance(e["source"], str) for e in clean_graph_dict["edges"]])
    assert all([isinstance(e["target"], str) for e in clean_graph_dict["edges"]])

    clean_graph_obj = nx.relabel_nodes(graph_obj, lambda x: str(x))
    _g = utils.graph_factory(clean_graph_dict)

    assert nx.is_isomorphic(_g, clean_graph_obj)
Beispiel #9
0
def render_subgraph_svg(task_result: dict, npi: Optional[float] = None) -> IO:

    g = graph_factory(task_result["graph"])

    fig = render_subgraphs(
        g,
        request_nodes=task_result["requested_nodes"],
        subgraph_nodes=task_result["subgraph_nodes"],
        npi=npi,
    )

    svg_bin = fig_to_image(fig)
    svg: IO = svg_bin.read()

    return svg
Beispiel #10
0
def test_round_trip_graph_to_graph(graph_obj_isvalid):
    graph_obj, isvalid = graph_obj_isvalid

    _g = utils.nxGraph_to_dict(graph_obj)

    G = utils.graph_factory(_g)

    assert nx.is_isomorphic(G, graph_obj)  # same structure nodes and edges

    for node, data in G.nodes(data=True):  # same node attrs
        assert data == graph_obj.nodes[node]

    if G.is_multigraph():
        for s, t, k, data in G.edges(data=True, keys=True):  # same edge attrs
            assert is_equal_subset(graph_obj.edges[(s, t, k)], data)
    else:
        for s, t, data in G.edges(data=True):  # same edge attrs
            assert is_equal_subset(graph_obj.edges[(s, t)], data)
Beispiel #11
0
def initialize_graph(
    watershed: Dict[str, Any], treatment_pre_validated: bool, context: Dict[str, Any],
) -> Tuple[nx.DiGraph, List[str]]:

    errors: List[str] = []

    g = graph_factory(watershed["graph"])

    if not is_valid(g):
        err_msg = "NetworkValidationError: "
        _keys = ["node_cycles", "edge_cycles", "multiple_out_edges", "duplicate_edges"]
        for key, value in zip(_keys, validate_network(g)):
            if len(value) > 0:
                err_msg += ", " + ": ".join([key, str(value)])
        errors.append(err_msg)

    land_surface = land_surface_loading(watershed, details=False, context=context)
    errors.extend(land_surface["errors"])

    treatment_facilities = initialize_treatment_facilities(
        watershed, pre_validated=treatment_pre_validated, context=context
    )
    errors.extend(treatment_facilities["errors"])

    treatment_sites = initialize_treatment_sites(watershed, context=context,)
    errors.extend(treatment_sites["errors"])

    data: Dict[str, Any] = {}
    for dictlist in [
        watershed.get("previous_results", []),
        land_surface.get("summary", []),
        treatment_facilities.get("treatment_facilities", []),
        treatment_sites.get("treatment_sites", []),
    ]:
        node_data = dictlist_to_dict(dictlist, "node_id")
        for n, _data in node_data.items():
            if n not in data:
                data[n] = {}
            data[n].update(_data)

    nx.set_node_attributes(g, data)

    return g, errors
Beispiel #12
0
def render_solution_sequence_svg(task_result: dict,
                                 npi: Optional[float] = None) -> IO:

    _graph = thin_graph_dict(task_result["graph"])  # strip unneeded metadata

    g = graph_factory(_graph)

    _sequence = task_result["solution_sequence"]

    solution_sequence = [[[n["id"] for n in ser["nodes"]]
                          for ser in p["series"]]
                         for p in _sequence["parallel"]]

    fig = render_solution_sequence(g,
                                   solution_sequence=solution_sequence,
                                   npi=npi)

    svg_bin = fig_to_image(fig)
    svg: IO = svg_bin.read()

    return svg
Beispiel #13
0
def test_stable_watershed_stable_subgraph_solutions(contexts,
                                                    watershed_requests,
                                                    watershed_test_case):

    n_nodes, pct_tmnt, dirty_nodes = watershed_test_case
    watershed_request = deepcopy(watershed_requests[(n_nodes, pct_tmnt)])
    context = contexts["default"]
    response_dict = solve_watershed(
        watershed=watershed_request,
        treatment_pre_validated=False,
        context=context,
    )
    results = response_dict["results"]

    reqd_min_attrs = attrs_to_resubmit(results)
    previous_results = {
        "previous_results":
        [{k: dct[k]
          for k in dct.keys() if k in reqd_min_attrs + ["node_id"]}
         for dct in results]
    }

    g = graph_factory(watershed_request["graph"])

    # this subgraph is empty, has no data.
    subg = nx.DiGraph(g.subgraph(get_subset(g, nodes=dirty_nodes)).edges)
    subgraph = {"graph": nxGraph_to_dict(subg)}

    new_request = deepcopy(watershed_request)
    new_request.update(subgraph)
    new_request.update(previous_results)

    subgraph_response_dict = solve_watershed(
        watershed=new_request,
        treatment_pre_validated=False,
        context=context,
    )
    subgraph_results = subgraph_response_dict["results"]

    check_subgraph_response_equal(subgraph_results, results)
Beispiel #14
0
def network_subgraphs(graph: Dict[str, Any],
                      nodes: List[Dict[str, Any]]) -> Dict[str, Any]:

    _graph = thin_graph_dict(graph)

    node_ids = [node["id"] for node in nodes]

    G = graph_factory(_graph)
    subset = get_subset(G, node_ids)
    sub_g = G.subgraph(subset)

    subgraph_nodes = [{
        "nodes": [{
            "id": n
        } for n in nodes]
    } for nodes in nx.weakly_connected_components(sub_g)]

    result: Dict[str, Any] = {"graph": _graph}
    result.update({"requested_nodes": nodes})
    result.update({"subgraph_nodes": subgraph_nodes})

    return result
Beispiel #15
0
def test_validate_network(edgelist, isvalid, exp):
    expected_result = [isvalid] + list(exp)

    g = {"edges": [{"source": s, "target": t} for s, t in edgelist], "directed": True}

    G = graph_factory(g)

    result = tasks.validate_network(g)

    keys = [
        "isvalid",
        "node_cycles",
        "edge_cycles",
        "multiple_out_edges",
        "duplicate_edges",
    ]

    if isvalid:
        assert result["isvalid"] == isvalid
    else:
        for key, value in zip(keys, expected_result):
            assert result[key] == value
Beispiel #16
0
def test_graph_factory_no_edges():
    g1 = {"nodes": [{"id": "A"}, {"id": "C"}, {"id": "B"}]}

    G = utils.graph_factory(g1)
    assert len(G.nodes) == 3