Fixed database typo and removed unnecessary class identifier.
This commit is contained in:
parent
00ad49a143
commit
45fb349a7d
5098 changed files with 952558 additions and 85 deletions
243
venv/Lib/site-packages/networkx/algorithms/flow/edmondskarp.py
Normal file
243
venv/Lib/site-packages/networkx/algorithms/flow/edmondskarp.py
Normal file
|
@ -0,0 +1,243 @@
|
|||
"""
|
||||
Edmonds-Karp algorithm for maximum flow problems.
|
||||
"""
|
||||
|
||||
import networkx as nx
|
||||
from networkx.algorithms.flow.utils import build_residual_network
|
||||
|
||||
__all__ = ["edmonds_karp"]
|
||||
|
||||
|
||||
def edmonds_karp_core(R, s, t, cutoff):
|
||||
"""Implementation of the Edmonds-Karp algorithm.
|
||||
"""
|
||||
R_nodes = R.nodes
|
||||
R_pred = R.pred
|
||||
R_succ = R.succ
|
||||
|
||||
inf = R.graph["inf"]
|
||||
|
||||
def augment(path):
|
||||
"""Augment flow along a path from s to t.
|
||||
"""
|
||||
# Determine the path residual capacity.
|
||||
flow = inf
|
||||
it = iter(path)
|
||||
u = next(it)
|
||||
for v in it:
|
||||
attr = R_succ[u][v]
|
||||
flow = min(flow, attr["capacity"] - attr["flow"])
|
||||
u = v
|
||||
if flow * 2 > inf:
|
||||
raise nx.NetworkXUnbounded("Infinite capacity path, flow unbounded above.")
|
||||
# Augment flow along the path.
|
||||
it = iter(path)
|
||||
u = next(it)
|
||||
for v in it:
|
||||
R_succ[u][v]["flow"] += flow
|
||||
R_succ[v][u]["flow"] -= flow
|
||||
u = v
|
||||
return flow
|
||||
|
||||
def bidirectional_bfs():
|
||||
"""Bidirectional breadth-first search for an augmenting path.
|
||||
"""
|
||||
pred = {s: None}
|
||||
q_s = [s]
|
||||
succ = {t: None}
|
||||
q_t = [t]
|
||||
while True:
|
||||
q = []
|
||||
if len(q_s) <= len(q_t):
|
||||
for u in q_s:
|
||||
for v, attr in R_succ[u].items():
|
||||
if v not in pred and attr["flow"] < attr["capacity"]:
|
||||
pred[v] = u
|
||||
if v in succ:
|
||||
return v, pred, succ
|
||||
q.append(v)
|
||||
if not q:
|
||||
return None, None, None
|
||||
q_s = q
|
||||
else:
|
||||
for u in q_t:
|
||||
for v, attr in R_pred[u].items():
|
||||
if v not in succ and attr["flow"] < attr["capacity"]:
|
||||
succ[v] = u
|
||||
if v in pred:
|
||||
return v, pred, succ
|
||||
q.append(v)
|
||||
if not q:
|
||||
return None, None, None
|
||||
q_t = q
|
||||
|
||||
# Look for shortest augmenting paths using breadth-first search.
|
||||
flow_value = 0
|
||||
while flow_value < cutoff:
|
||||
v, pred, succ = bidirectional_bfs()
|
||||
if pred is None:
|
||||
break
|
||||
path = [v]
|
||||
# Trace a path from s to v.
|
||||
u = v
|
||||
while u != s:
|
||||
u = pred[u]
|
||||
path.append(u)
|
||||
path.reverse()
|
||||
# Trace a path from v to t.
|
||||
u = v
|
||||
while u != t:
|
||||
u = succ[u]
|
||||
path.append(u)
|
||||
flow_value += augment(path)
|
||||
|
||||
return flow_value
|
||||
|
||||
|
||||
def edmonds_karp_impl(G, s, t, capacity, residual, cutoff):
|
||||
"""Implementation of the Edmonds-Karp algorithm.
|
||||
"""
|
||||
if s not in G:
|
||||
raise nx.NetworkXError(f"node {str(s)} not in graph")
|
||||
if t not in G:
|
||||
raise nx.NetworkXError(f"node {str(t)} not in graph")
|
||||
if s == t:
|
||||
raise nx.NetworkXError("source and sink are the same node")
|
||||
|
||||
if residual is None:
|
||||
R = build_residual_network(G, capacity)
|
||||
else:
|
||||
R = residual
|
||||
|
||||
# Initialize/reset the residual network.
|
||||
for u in R:
|
||||
for e in R[u].values():
|
||||
e["flow"] = 0
|
||||
|
||||
if cutoff is None:
|
||||
cutoff = float("inf")
|
||||
R.graph["flow_value"] = edmonds_karp_core(R, s, t, cutoff)
|
||||
|
||||
return R
|
||||
|
||||
|
||||
def edmonds_karp(
|
||||
G, s, t, capacity="capacity", residual=None, value_only=False, cutoff=None
|
||||
):
|
||||
"""Find a maximum single-commodity flow using the Edmonds-Karp algorithm.
|
||||
|
||||
This function returns the residual network resulting after computing
|
||||
the maximum flow. See below for details about the conventions
|
||||
NetworkX uses for defining residual networks.
|
||||
|
||||
This algorithm has a running time of $O(n m^2)$ for $n$ nodes and $m$
|
||||
edges.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : 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'.
|
||||
|
||||
residual : NetworkX graph
|
||||
Residual network on which the algorithm is to be executed. If None, a
|
||||
new residual network is created. Default value: None.
|
||||
|
||||
value_only : bool
|
||||
If True compute only the value of the maximum flow. This parameter
|
||||
will be ignored by this algorithm because it is not applicable.
|
||||
|
||||
cutoff : integer, float
|
||||
If specified, the algorithm will terminate when the flow value reaches
|
||||
or exceeds the cutoff. In this case, it may be unable to immediately
|
||||
determine a minimum cut. Default value: None.
|
||||
|
||||
Returns
|
||||
-------
|
||||
R : NetworkX DiGraph
|
||||
Residual network after computing the maximum flow.
|
||||
|
||||
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:`preflow_push`
|
||||
:meth:`shortest_augmenting_path`
|
||||
|
||||
Notes
|
||||
-----
|
||||
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']`. If :samp:`cutoff` is not
|
||||
specified, 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.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from networkx.algorithms.flow import edmonds_karp
|
||||
|
||||
The functions that implement flow algorithms and output a residual
|
||||
network, such as this one, are not imported to the base NetworkX
|
||||
namespace, so you have to explicitly import them from the flow package.
|
||||
|
||||
>>> 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)
|
||||
>>> R = edmonds_karp(G, "x", "y")
|
||||
>>> flow_value = nx.maximum_flow_value(G, "x", "y")
|
||||
>>> flow_value
|
||||
3.0
|
||||
>>> flow_value == R.graph["flow_value"]
|
||||
True
|
||||
|
||||
"""
|
||||
R = edmonds_karp_impl(G, s, t, capacity, residual, cutoff)
|
||||
R.graph["algorithm"] = "edmonds_karp"
|
||||
return R
|
Loading…
Add table
Add a link
Reference in a new issue