Spaces:
Paused
Paused
| """ | |
| Maximum flow (and minimum cut) algorithms on capacitated graphs. | |
| """ | |
| import networkx as nx | |
| from .boykovkolmogorov import boykov_kolmogorov | |
| from .dinitz_alg import dinitz | |
| from .edmondskarp import edmonds_karp | |
| from .preflowpush import preflow_push | |
| from .shortestaugmentingpath import shortest_augmenting_path | |
| from .utils import build_flow_dict | |
| # Define the default flow function for computing maximum flow. | |
| default_flow_func = preflow_push | |
| __all__ = ["maximum_flow", "maximum_flow_value", "minimum_cut", "minimum_cut_value"] | |
| def maximum_flow(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): | |
| """Find a maximum single-commodity flow. | |
| Parameters | |
| ---------- | |
| flowG : NetworkX graph | |
| Edges of the graph are expected to have an attribute called | |
| 'capacity'. If this attribute is not present, the edge is | |
| considered to have infinite capacity. | |
| _s : node | |
| Source node for the flow. | |
| _t : node | |
| Sink node for the flow. | |
| capacity : string | |
| Edges of the graph G are expected to have an attribute capacity | |
| that indicates how much flow the edge can support. If this | |
| attribute is not present, the edge is considered to have | |
| infinite capacity. Default value: 'capacity'. | |
| flow_func : function | |
| A function for computing the maximum flow among a pair of nodes | |
| in a capacitated graph. The function has to accept at least three | |
| parameters: a Graph or Digraph, a source node, and a target node. | |
| And return a residual network that follows NetworkX conventions | |
| (see Notes). If flow_func is None, the default maximum | |
| flow function (:meth:`preflow_push`) is used. See below for | |
| alternative algorithms. The choice of the default function may change | |
| from version to version and should not be relied on. Default value: | |
| None. | |
| kwargs : Any other keyword parameter is passed to the function that | |
| computes the maximum flow. | |
| Returns | |
| ------- | |
| flow_value : integer, float | |
| Value of the maximum flow, i.e., net outflow from the source. | |
| flow_dict : dict | |
| A dictionary containing the value of the flow that went through | |
| each edge. | |
| Raises | |
| ------ | |
| NetworkXError | |
| The algorithm does not support MultiGraph and MultiDiGraph. If | |
| the input graph is an instance of one of these two classes, a | |
| NetworkXError is raised. | |
| NetworkXUnbounded | |
| If the graph has a path of infinite capacity, the value of a | |
| feasible flow on the graph is unbounded above and the function | |
| raises a NetworkXUnbounded. | |
| See also | |
| -------- | |
| :meth:`maximum_flow_value` | |
| :meth:`minimum_cut` | |
| :meth:`minimum_cut_value` | |
| :meth:`edmonds_karp` | |
| :meth:`preflow_push` | |
| :meth:`shortest_augmenting_path` | |
| Notes | |
| ----- | |
| The function used in the flow_func parameter has to return a residual | |
| network that follows NetworkX conventions: | |
| The residual network :samp:`R` from an input graph :samp:`G` has the | |
| same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair | |
| of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a | |
| self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists | |
| in :samp:`G`. | |
| For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` | |
| is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists | |
| in :samp:`G` or zero otherwise. If the capacity is infinite, | |
| :samp:`R[u][v]['capacity']` will have a high arbitrary finite value | |
| that does not affect the solution of the problem. This value is stored in | |
| :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, | |
| :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and | |
| satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. | |
| The flow value, defined as the total flow into :samp:`t`, the sink, is | |
| stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using | |
| only edges :samp:`(u, v)` such that | |
| :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum | |
| :samp:`s`-:samp:`t` cut. | |
| Specific algorithms may store extra data in :samp:`R`. | |
| The function should supports an optional boolean parameter value_only. When | |
| True, it can optionally terminate the algorithm as soon as the maximum flow | |
| value and the minimum cut can be determined. | |
| Examples | |
| -------- | |
| >>> G = nx.DiGraph() | |
| >>> G.add_edge("x", "a", capacity=3.0) | |
| >>> G.add_edge("x", "b", capacity=1.0) | |
| >>> G.add_edge("a", "c", capacity=3.0) | |
| >>> G.add_edge("b", "c", capacity=5.0) | |
| >>> G.add_edge("b", "d", capacity=4.0) | |
| >>> G.add_edge("d", "e", capacity=2.0) | |
| >>> G.add_edge("c", "y", capacity=2.0) | |
| >>> G.add_edge("e", "y", capacity=3.0) | |
| maximum_flow returns both the value of the maximum flow and a | |
| dictionary with all flows. | |
| >>> flow_value, flow_dict = nx.maximum_flow(G, "x", "y") | |
| >>> flow_value | |
| 3.0 | |
| >>> print(flow_dict["x"]["b"]) | |
| 1.0 | |
| You can also use alternative algorithms for computing the | |
| maximum flow by using the flow_func parameter. | |
| >>> from networkx.algorithms.flow import shortest_augmenting_path | |
| >>> flow_value == nx.maximum_flow(G, "x", "y", flow_func=shortest_augmenting_path)[ | |
| ... 0 | |
| ... ] | |
| True | |
| """ | |
| if flow_func is None: | |
| if kwargs: | |
| raise nx.NetworkXError( | |
| "You have to explicitly set a flow_func if" | |
| " you need to pass parameters via kwargs." | |
| ) | |
| flow_func = default_flow_func | |
| if not callable(flow_func): | |
| raise nx.NetworkXError("flow_func has to be callable.") | |
| R = flow_func(flowG, _s, _t, capacity=capacity, value_only=False, **kwargs) | |
| flow_dict = build_flow_dict(flowG, R) | |
| return (R.graph["flow_value"], flow_dict) | |
| def maximum_flow_value(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): | |
| """Find the value of maximum single-commodity flow. | |
| Parameters | |
| ---------- | |
| flowG : NetworkX graph | |
| Edges of the graph are expected to have an attribute called | |
| 'capacity'. If this attribute is not present, the edge is | |
| considered to have infinite capacity. | |
| _s : node | |
| Source node for the flow. | |
| _t : node | |
| Sink node for the flow. | |
| capacity : string | |
| Edges of the graph G are expected to have an attribute capacity | |
| that indicates how much flow the edge can support. If this | |
| attribute is not present, the edge is considered to have | |
| infinite capacity. Default value: 'capacity'. | |
| flow_func : function | |
| A function for computing the maximum flow among a pair of nodes | |
| in a capacitated graph. The function has to accept at least three | |
| parameters: a Graph or Digraph, a source node, and a target node. | |
| And return a residual network that follows NetworkX conventions | |
| (see Notes). If flow_func is None, the default maximum | |
| flow function (:meth:`preflow_push`) is used. See below for | |
| alternative algorithms. The choice of the default function may change | |
| from version to version and should not be relied on. Default value: | |
| None. | |
| kwargs : Any other keyword parameter is passed to the function that | |
| computes the maximum flow. | |
| Returns | |
| ------- | |
| flow_value : integer, float | |
| Value of the maximum flow, i.e., net outflow from the source. | |
| Raises | |
| ------ | |
| NetworkXError | |
| The algorithm does not support MultiGraph and MultiDiGraph. If | |
| the input graph is an instance of one of these two classes, a | |
| NetworkXError is raised. | |
| NetworkXUnbounded | |
| If the graph has a path of infinite capacity, the value of a | |
| feasible flow on the graph is unbounded above and the function | |
| raises a NetworkXUnbounded. | |
| See also | |
| -------- | |
| :meth:`maximum_flow` | |
| :meth:`minimum_cut` | |
| :meth:`minimum_cut_value` | |
| :meth:`edmonds_karp` | |
| :meth:`preflow_push` | |
| :meth:`shortest_augmenting_path` | |
| Notes | |
| ----- | |
| The function used in the flow_func parameter has to return a residual | |
| network that follows NetworkX conventions: | |
| The residual network :samp:`R` from an input graph :samp:`G` has the | |
| same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair | |
| of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a | |
| self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists | |
| in :samp:`G`. | |
| For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` | |
| is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists | |
| in :samp:`G` or zero otherwise. If the capacity is infinite, | |
| :samp:`R[u][v]['capacity']` will have a high arbitrary finite value | |
| that does not affect the solution of the problem. This value is stored in | |
| :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, | |
| :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and | |
| satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. | |
| The flow value, defined as the total flow into :samp:`t`, the sink, is | |
| stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using | |
| only edges :samp:`(u, v)` such that | |
| :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum | |
| :samp:`s`-:samp:`t` cut. | |
| Specific algorithms may store extra data in :samp:`R`. | |
| The function should supports an optional boolean parameter value_only. When | |
| True, it can optionally terminate the algorithm as soon as the maximum flow | |
| value and the minimum cut can be determined. | |
| Examples | |
| -------- | |
| >>> G = nx.DiGraph() | |
| >>> G.add_edge("x", "a", capacity=3.0) | |
| >>> G.add_edge("x", "b", capacity=1.0) | |
| >>> G.add_edge("a", "c", capacity=3.0) | |
| >>> G.add_edge("b", "c", capacity=5.0) | |
| >>> G.add_edge("b", "d", capacity=4.0) | |
| >>> G.add_edge("d", "e", capacity=2.0) | |
| >>> G.add_edge("c", "y", capacity=2.0) | |
| >>> G.add_edge("e", "y", capacity=3.0) | |
| maximum_flow_value computes only the value of the | |
| maximum flow: | |
| >>> flow_value = nx.maximum_flow_value(G, "x", "y") | |
| >>> flow_value | |
| 3.0 | |
| You can also use alternative algorithms for computing the | |
| maximum flow by using the flow_func parameter. | |
| >>> from networkx.algorithms.flow import shortest_augmenting_path | |
| >>> flow_value == nx.maximum_flow_value( | |
| ... G, "x", "y", flow_func=shortest_augmenting_path | |
| ... ) | |
| True | |
| """ | |
| if flow_func is None: | |
| if kwargs: | |
| raise nx.NetworkXError( | |
| "You have to explicitly set a flow_func if" | |
| " you need to pass parameters via kwargs." | |
| ) | |
| flow_func = default_flow_func | |
| if not callable(flow_func): | |
| raise nx.NetworkXError("flow_func has to be callable.") | |
| R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) | |
| return R.graph["flow_value"] | |
| def minimum_cut(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): | |
| """Compute the value and the node partition of a minimum (s, t)-cut. | |
| Use the max-flow min-cut theorem, i.e., the capacity of a minimum | |
| capacity cut is equal to the flow value of a maximum flow. | |
| Parameters | |
| ---------- | |
| flowG : NetworkX graph | |
| Edges of the graph are expected to have an attribute called | |
| 'capacity'. If this attribute is not present, the edge is | |
| considered to have infinite capacity. | |
| _s : node | |
| Source node for the flow. | |
| _t : node | |
| Sink node for the flow. | |
| capacity : string | |
| Edges of the graph G are expected to have an attribute capacity | |
| that indicates how much flow the edge can support. If this | |
| attribute is not present, the edge is considered to have | |
| infinite capacity. Default value: 'capacity'. | |
| flow_func : function | |
| A function for computing the maximum flow among a pair of nodes | |
| in a capacitated graph. The function has to accept at least three | |
| parameters: a Graph or Digraph, a source node, and a target node. | |
| And return a residual network that follows NetworkX conventions | |
| (see Notes). If flow_func is None, the default maximum | |
| flow function (:meth:`preflow_push`) is used. See below for | |
| alternative algorithms. The choice of the default function may change | |
| from version to version and should not be relied on. Default value: | |
| None. | |
| kwargs : Any other keyword parameter is passed to the function that | |
| computes the maximum flow. | |
| Returns | |
| ------- | |
| cut_value : integer, float | |
| Value of the minimum cut. | |
| partition : pair of node sets | |
| A partitioning of the nodes that defines a minimum cut. | |
| Raises | |
| ------ | |
| NetworkXUnbounded | |
| If the graph has a path of infinite capacity, all cuts have | |
| infinite capacity and the function raises a NetworkXError. | |
| See also | |
| -------- | |
| :meth:`maximum_flow` | |
| :meth:`maximum_flow_value` | |
| :meth:`minimum_cut_value` | |
| :meth:`edmonds_karp` | |
| :meth:`preflow_push` | |
| :meth:`shortest_augmenting_path` | |
| Notes | |
| ----- | |
| The function used in the flow_func parameter has to return a residual | |
| network that follows NetworkX conventions: | |
| The residual network :samp:`R` from an input graph :samp:`G` has the | |
| same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair | |
| of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a | |
| self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists | |
| in :samp:`G`. | |
| For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` | |
| is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists | |
| in :samp:`G` or zero otherwise. If the capacity is infinite, | |
| :samp:`R[u][v]['capacity']` will have a high arbitrary finite value | |
| that does not affect the solution of the problem. This value is stored in | |
| :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, | |
| :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and | |
| satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. | |
| The flow value, defined as the total flow into :samp:`t`, the sink, is | |
| stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using | |
| only edges :samp:`(u, v)` such that | |
| :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum | |
| :samp:`s`-:samp:`t` cut. | |
| Specific algorithms may store extra data in :samp:`R`. | |
| The function should supports an optional boolean parameter value_only. When | |
| True, it can optionally terminate the algorithm as soon as the maximum flow | |
| value and the minimum cut can be determined. | |
| Examples | |
| -------- | |
| >>> G = nx.DiGraph() | |
| >>> G.add_edge("x", "a", capacity=3.0) | |
| >>> G.add_edge("x", "b", capacity=1.0) | |
| >>> G.add_edge("a", "c", capacity=3.0) | |
| >>> G.add_edge("b", "c", capacity=5.0) | |
| >>> G.add_edge("b", "d", capacity=4.0) | |
| >>> G.add_edge("d", "e", capacity=2.0) | |
| >>> G.add_edge("c", "y", capacity=2.0) | |
| >>> G.add_edge("e", "y", capacity=3.0) | |
| minimum_cut computes both the value of the | |
| minimum cut and the node partition: | |
| >>> cut_value, partition = nx.minimum_cut(G, "x", "y") | |
| >>> reachable, non_reachable = partition | |
| 'partition' here is a tuple with the two sets of nodes that define | |
| the minimum cut. You can compute the cut set of edges that induce | |
| the minimum cut as follows: | |
| >>> cutset = set() | |
| >>> for u, nbrs in ((n, G[n]) for n in reachable): | |
| ... cutset.update((u, v) for v in nbrs if v in non_reachable) | |
| >>> print(sorted(cutset)) | |
| [('c', 'y'), ('x', 'b')] | |
| >>> cut_value == sum(G.edges[u, v]["capacity"] for (u, v) in cutset) | |
| True | |
| You can also use alternative algorithms for computing the | |
| minimum cut by using the flow_func parameter. | |
| >>> from networkx.algorithms.flow import shortest_augmenting_path | |
| >>> cut_value == nx.minimum_cut(G, "x", "y", flow_func=shortest_augmenting_path)[0] | |
| True | |
| """ | |
| if flow_func is None: | |
| if kwargs: | |
| raise nx.NetworkXError( | |
| "You have to explicitly set a flow_func if" | |
| " you need to pass parameters via kwargs." | |
| ) | |
| flow_func = default_flow_func | |
| if not callable(flow_func): | |
| raise nx.NetworkXError("flow_func has to be callable.") | |
| if kwargs.get("cutoff") is not None and flow_func is preflow_push: | |
| raise nx.NetworkXError("cutoff should not be specified.") | |
| R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) | |
| # Remove saturated edges from the residual network | |
| cutset = [(u, v, d) for u, v, d in R.edges(data=True) if d["flow"] == d["capacity"]] | |
| R.remove_edges_from(cutset) | |
| # Then, reachable and non reachable nodes from source in the | |
| # residual network form the node partition that defines | |
| # the minimum cut. | |
| non_reachable = set(dict(nx.shortest_path_length(R, target=_t))) | |
| partition = (set(flowG) - non_reachable, non_reachable) | |
| # Finally add again cutset edges to the residual network to make | |
| # sure that it is reusable. | |
| if cutset is not None: | |
| R.add_edges_from(cutset) | |
| return (R.graph["flow_value"], partition) | |
| def minimum_cut_value(flowG, _s, _t, capacity="capacity", flow_func=None, **kwargs): | |
| """Compute the value of a minimum (s, t)-cut. | |
| Use the max-flow min-cut theorem, i.e., the capacity of a minimum | |
| capacity cut is equal to the flow value of a maximum flow. | |
| Parameters | |
| ---------- | |
| flowG : NetworkX graph | |
| Edges of the graph are expected to have an attribute called | |
| 'capacity'. If this attribute is not present, the edge is | |
| considered to have infinite capacity. | |
| _s : node | |
| Source node for the flow. | |
| _t : node | |
| Sink node for the flow. | |
| capacity : string | |
| Edges of the graph G are expected to have an attribute capacity | |
| that indicates how much flow the edge can support. If this | |
| attribute is not present, the edge is considered to have | |
| infinite capacity. Default value: 'capacity'. | |
| flow_func : function | |
| A function for computing the maximum flow among a pair of nodes | |
| in a capacitated graph. The function has to accept at least three | |
| parameters: a Graph or Digraph, a source node, and a target node. | |
| And return a residual network that follows NetworkX conventions | |
| (see Notes). If flow_func is None, the default maximum | |
| flow function (:meth:`preflow_push`) is used. See below for | |
| alternative algorithms. The choice of the default function may change | |
| from version to version and should not be relied on. Default value: | |
| None. | |
| kwargs : Any other keyword parameter is passed to the function that | |
| computes the maximum flow. | |
| Returns | |
| ------- | |
| cut_value : integer, float | |
| Value of the minimum cut. | |
| Raises | |
| ------ | |
| NetworkXUnbounded | |
| If the graph has a path of infinite capacity, all cuts have | |
| infinite capacity and the function raises a NetworkXError. | |
| See also | |
| -------- | |
| :meth:`maximum_flow` | |
| :meth:`maximum_flow_value` | |
| :meth:`minimum_cut` | |
| :meth:`edmonds_karp` | |
| :meth:`preflow_push` | |
| :meth:`shortest_augmenting_path` | |
| Notes | |
| ----- | |
| The function used in the flow_func parameter has to return a residual | |
| network that follows NetworkX conventions: | |
| The residual network :samp:`R` from an input graph :samp:`G` has the | |
| same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair | |
| of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a | |
| self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists | |
| in :samp:`G`. | |
| For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` | |
| is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists | |
| in :samp:`G` or zero otherwise. If the capacity is infinite, | |
| :samp:`R[u][v]['capacity']` will have a high arbitrary finite value | |
| that does not affect the solution of the problem. This value is stored in | |
| :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, | |
| :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and | |
| satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. | |
| The flow value, defined as the total flow into :samp:`t`, the sink, is | |
| stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using | |
| only edges :samp:`(u, v)` such that | |
| :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum | |
| :samp:`s`-:samp:`t` cut. | |
| Specific algorithms may store extra data in :samp:`R`. | |
| The function should supports an optional boolean parameter value_only. When | |
| True, it can optionally terminate the algorithm as soon as the maximum flow | |
| value and the minimum cut can be determined. | |
| Examples | |
| -------- | |
| >>> G = nx.DiGraph() | |
| >>> G.add_edge("x", "a", capacity=3.0) | |
| >>> G.add_edge("x", "b", capacity=1.0) | |
| >>> G.add_edge("a", "c", capacity=3.0) | |
| >>> G.add_edge("b", "c", capacity=5.0) | |
| >>> G.add_edge("b", "d", capacity=4.0) | |
| >>> G.add_edge("d", "e", capacity=2.0) | |
| >>> G.add_edge("c", "y", capacity=2.0) | |
| >>> G.add_edge("e", "y", capacity=3.0) | |
| minimum_cut_value computes only the value of the | |
| minimum cut: | |
| >>> cut_value = nx.minimum_cut_value(G, "x", "y") | |
| >>> cut_value | |
| 3.0 | |
| You can also use alternative algorithms for computing the | |
| minimum cut by using the flow_func parameter. | |
| >>> from networkx.algorithms.flow import shortest_augmenting_path | |
| >>> cut_value == nx.minimum_cut_value( | |
| ... G, "x", "y", flow_func=shortest_augmenting_path | |
| ... ) | |
| True | |
| """ | |
| if flow_func is None: | |
| if kwargs: | |
| raise nx.NetworkXError( | |
| "You have to explicitly set a flow_func if" | |
| " you need to pass parameters via kwargs." | |
| ) | |
| flow_func = default_flow_func | |
| if not callable(flow_func): | |
| raise nx.NetworkXError("flow_func has to be callable.") | |
| if kwargs.get("cutoff") is not None and flow_func is preflow_push: | |
| raise nx.NetworkXError("cutoff should not be specified.") | |
| R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) | |
| return R.graph["flow_value"] | |