123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- """
- Minimum cost flow algorithms on directed connected graphs.
- """
- __all__ = ["min_cost_flow_cost", "min_cost_flow", "cost_of_flow", "max_flow_min_cost"]
- import networkx as nx
- def min_cost_flow_cost(G, demand="demand", capacity="capacity", weight="weight"):
- r"""Find the cost of a minimum cost flow satisfying all demands in digraph G.
- G is a digraph with edge costs and capacities and in which nodes
- have demand, i.e., they want to send or receive some amount of
- flow. A negative demand means that the node wants to send flow, a
- positive demand means that the node want to receive flow. A flow on
- the digraph G satisfies all demand if the net flow into each node
- is equal to the demand of that node.
- Parameters
- ----------
- G : NetworkX graph
- DiGraph on which a minimum cost flow satisfying all demands is
- to be found.
- demand : string
- Nodes of the graph G are expected to have an attribute demand
- that indicates how much flow a node wants to send (negative
- demand) or receive (positive demand). Note that the sum of the
- demands should be 0 otherwise the problem in not feasible. If
- this attribute is not present, a node is considered to have 0
- demand. Default value: 'demand'.
- 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'.
- weight : string
- Edges of the graph G are expected to have an attribute weight
- that indicates the cost incurred by sending one unit of flow on
- that edge. If not present, the weight is considered to be 0.
- Default value: 'weight'.
- Returns
- -------
- flowCost : integer, float
- Cost of a minimum cost flow satisfying all demands.
- Raises
- ------
- NetworkXError
- This exception is raised if the input graph is not directed or
- not connected.
- NetworkXUnfeasible
- This exception is raised in the following situations:
- * The sum of the demands is not zero. Then, there is no
- flow satisfying all demands.
- * There is no flow satisfying all demand.
- NetworkXUnbounded
- This exception is raised if the digraph G has a cycle of
- negative cost and infinite capacity. Then, the cost of a flow
- satisfying all demands is unbounded below.
- See also
- --------
- cost_of_flow, max_flow_min_cost, min_cost_flow, network_simplex
- Notes
- -----
- This algorithm is not guaranteed to work if edge weights or demands
- are floating point numbers (overflows and roundoff errors can
- cause problems). As a workaround you can use integer numbers by
- multiplying the relevant edge attributes by a convenient
- constant factor (eg 100).
- Examples
- --------
- A simple example of a min cost flow problem.
- >>> G = nx.DiGraph()
- >>> G.add_node("a", demand=-5)
- >>> G.add_node("d", demand=5)
- >>> G.add_edge("a", "b", weight=3, capacity=4)
- >>> G.add_edge("a", "c", weight=6, capacity=10)
- >>> G.add_edge("b", "d", weight=1, capacity=9)
- >>> G.add_edge("c", "d", weight=2, capacity=5)
- >>> flowCost = nx.min_cost_flow_cost(G)
- >>> flowCost
- 24
- """
- return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[0]
- def min_cost_flow(G, demand="demand", capacity="capacity", weight="weight"):
- r"""Returns a minimum cost flow satisfying all demands in digraph G.
- G is a digraph with edge costs and capacities and in which nodes
- have demand, i.e., they want to send or receive some amount of
- flow. A negative demand means that the node wants to send flow, a
- positive demand means that the node want to receive flow. A flow on
- the digraph G satisfies all demand if the net flow into each node
- is equal to the demand of that node.
- Parameters
- ----------
- G : NetworkX graph
- DiGraph on which a minimum cost flow satisfying all demands is
- to be found.
- demand : string
- Nodes of the graph G are expected to have an attribute demand
- that indicates how much flow a node wants to send (negative
- demand) or receive (positive demand). Note that the sum of the
- demands should be 0 otherwise the problem in not feasible. If
- this attribute is not present, a node is considered to have 0
- demand. Default value: 'demand'.
- 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'.
- weight : string
- Edges of the graph G are expected to have an attribute weight
- that indicates the cost incurred by sending one unit of flow on
- that edge. If not present, the weight is considered to be 0.
- Default value: 'weight'.
- Returns
- -------
- flowDict : dictionary
- Dictionary of dictionaries keyed by nodes such that
- flowDict[u][v] is the flow edge (u, v).
- Raises
- ------
- NetworkXError
- This exception is raised if the input graph is not directed or
- not connected.
- NetworkXUnfeasible
- This exception is raised in the following situations:
- * The sum of the demands is not zero. Then, there is no
- flow satisfying all demands.
- * There is no flow satisfying all demand.
- NetworkXUnbounded
- This exception is raised if the digraph G has a cycle of
- negative cost and infinite capacity. Then, the cost of a flow
- satisfying all demands is unbounded below.
- See also
- --------
- cost_of_flow, max_flow_min_cost, min_cost_flow_cost, network_simplex
- Notes
- -----
- This algorithm is not guaranteed to work if edge weights or demands
- are floating point numbers (overflows and roundoff errors can
- cause problems). As a workaround you can use integer numbers by
- multiplying the relevant edge attributes by a convenient
- constant factor (eg 100).
- Examples
- --------
- A simple example of a min cost flow problem.
- >>> G = nx.DiGraph()
- >>> G.add_node("a", demand=-5)
- >>> G.add_node("d", demand=5)
- >>> G.add_edge("a", "b", weight=3, capacity=4)
- >>> G.add_edge("a", "c", weight=6, capacity=10)
- >>> G.add_edge("b", "d", weight=1, capacity=9)
- >>> G.add_edge("c", "d", weight=2, capacity=5)
- >>> flowDict = nx.min_cost_flow(G)
- """
- return nx.network_simplex(G, demand=demand, capacity=capacity, weight=weight)[1]
- def cost_of_flow(G, flowDict, weight="weight"):
- """Compute the cost of the flow given by flowDict on graph G.
- Note that this function does not check for the validity of the
- flow flowDict. This function will fail if the graph G and the
- flow don't have the same edge set.
- Parameters
- ----------
- G : NetworkX graph
- DiGraph on which a minimum cost flow satisfying all demands is
- to be found.
- weight : string
- Edges of the graph G are expected to have an attribute weight
- that indicates the cost incurred by sending one unit of flow on
- that edge. If not present, the weight is considered to be 0.
- Default value: 'weight'.
- flowDict : dictionary
- Dictionary of dictionaries keyed by nodes such that
- flowDict[u][v] is the flow edge (u, v).
- Returns
- -------
- cost : Integer, float
- The total cost of the flow. This is given by the sum over all
- edges of the product of the edge's flow and the edge's weight.
- See also
- --------
- max_flow_min_cost, min_cost_flow, min_cost_flow_cost, network_simplex
- Notes
- -----
- This algorithm is not guaranteed to work if edge weights or demands
- are floating point numbers (overflows and roundoff errors can
- cause problems). As a workaround you can use integer numbers by
- multiplying the relevant edge attributes by a convenient
- constant factor (eg 100).
- """
- return sum((flowDict[u][v] * d.get(weight, 0) for u, v, d in G.edges(data=True)))
- def max_flow_min_cost(G, s, t, capacity="capacity", weight="weight"):
- """Returns a maximum (s, t)-flow of minimum cost.
- G is a digraph with edge costs and capacities. There is a source
- node s and a sink node t. This function finds a maximum flow from
- s to t whose total cost is minimized.
- Parameters
- ----------
- G : NetworkX graph
- DiGraph on which a minimum cost flow satisfying all demands is
- to be found.
- s: node label
- Source of the flow.
- t: node label
- Destination of 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'.
- weight: string
- Edges of the graph G are expected to have an attribute weight
- that indicates the cost incurred by sending one unit of flow on
- that edge. If not present, the weight is considered to be 0.
- Default value: 'weight'.
- Returns
- -------
- flowDict: dictionary
- Dictionary of dictionaries keyed by nodes such that
- flowDict[u][v] is the flow edge (u, v).
- Raises
- ------
- NetworkXError
- This exception is raised if the input graph is not directed or
- not connected.
- NetworkXUnbounded
- This exception is raised if there is an infinite capacity path
- from s to t in G. In this case there is no maximum flow. This
- exception is also raised if the digraph G has a cycle of
- negative cost and infinite capacity. Then, the cost of a flow
- is unbounded below.
- See also
- --------
- cost_of_flow, min_cost_flow, min_cost_flow_cost, network_simplex
- Notes
- -----
- This algorithm is not guaranteed to work if edge weights or demands
- are floating point numbers (overflows and roundoff errors can
- cause problems). As a workaround you can use integer numbers by
- multiplying the relevant edge attributes by a convenient
- constant factor (eg 100).
- Examples
- --------
- >>> G = nx.DiGraph()
- >>> G.add_edges_from(
- ... [
- ... (1, 2, {"capacity": 12, "weight": 4}),
- ... (1, 3, {"capacity": 20, "weight": 6}),
- ... (2, 3, {"capacity": 6, "weight": -3}),
- ... (2, 6, {"capacity": 14, "weight": 1}),
- ... (3, 4, {"weight": 9}),
- ... (3, 5, {"capacity": 10, "weight": 5}),
- ... (4, 2, {"capacity": 19, "weight": 13}),
- ... (4, 5, {"capacity": 4, "weight": 0}),
- ... (5, 7, {"capacity": 28, "weight": 2}),
- ... (6, 5, {"capacity": 11, "weight": 1}),
- ... (6, 7, {"weight": 8}),
- ... (7, 4, {"capacity": 6, "weight": 6}),
- ... ]
- ... )
- >>> mincostFlow = nx.max_flow_min_cost(G, 1, 7)
- >>> mincost = nx.cost_of_flow(G, mincostFlow)
- >>> mincost
- 373
- >>> from networkx.algorithms.flow import maximum_flow
- >>> maxFlow = maximum_flow(G, 1, 7)[1]
- >>> nx.cost_of_flow(G, maxFlow) >= mincost
- True
- >>> mincostFlowValue = sum((mincostFlow[u][7] for u in G.predecessors(7))) - sum(
- ... (mincostFlow[7][v] for v in G.successors(7))
- ... )
- >>> mincostFlowValue == nx.maximum_flow_value(G, 1, 7)
- True
- """
- maxFlow = nx.maximum_flow_value(G, s, t, capacity=capacity)
- H = nx.DiGraph(G)
- H.add_node(s, demand=-maxFlow)
- H.add_node(t, demand=maxFlow)
- return min_cost_flow(H, capacity=capacity, weight=weight)
|