Repository: networkx/networkx

Issue:
max_flow_min_cost function running forever
Hello,
When I try to run this code, it's seemingly in some infinite loop. 

``` python
G = nx.DiGraph()
G.add_edges_from([
    ('1in', '1out', {'cost': 0, 'capacity': 1}), 
    ('2out', '4in', {'cost': -9.48, 'capacity': 1}), 
    ('2out', 'destination', {'cost': -10.9, 'capacity': 1}), 
    ('2out', '3in', {'cost': -10.31, 'capacity': 1}), 
    ('destination', 'sink', {'cost': 0, 'capacity': 1}), 
    ('2in', '2out', {'cost': 0, 'capacity': 1}), 
    ('source', '2in', {'cost': 0, 'capacity': 1}), 
    ('source', '4in', {'cost': 0, 'capacity': 1}), 
    ('source', '1in', {'cost': 0, 'capacity': 1}), 
    ('source', '3in', {'cost': 0, 'capacity': 1}), 
    ('4in', '4out', {'cost': 0, 'capacity': 1}), 
    ('1out', '2in', {'cost': -10.31, 'capacity': 1}), 
    ('1out', '4in', {'cost': -10.31, 'capacity': 1}), 
    ('1out', 'destination', {'cost':-10.9, 'capacity': 1}), 
    ('1out', '3in', {'cost': -9.48, 'capacity': 1}), 
    ('4out', 'destination', {'cost': -10.9, 'capacity': 1}), 
    ('3in', '3out', {'cost': 0, 'capacity': 1}), 
    ('3out', '4in', {'cost': -10.31, 'capacity': 1}), 
    ('3out', 'destination', {'cost': -10.9, 'capacity': 1})
])
nx.max_flow_min_cost(G, 'source', 'sink', weight='cost')
```

Actually, this breaks whenever the capacity from destination to sink is capacity 1, 2, or 3 (capacity 4 it works fine).

Here is an example of a similar list of edges where the algorithm runs fine for any capacity of destination-> sink from 1 to 7

``` python
[('destination', 'sink', {'capacity': 2, 'cost': 0}),
('1in', '1out', {'capacity': 1, 'cost': 0}),
 ('6out', '7in', {'capacity': 1, 'cost': -28.0}),
 ('6out', 'destination', {'capacity': 1, 'cost': -26.76}),
 ('source', '1in', {'capacity': 1, 'cost': 0}),
 ('source', '7in', {'capacity': 1, 'cost': 0}),
 ('source', '6in', {'capacity': 1, 'cost': 0}),
 ('source', '5in', {'capacity': 1, 'cost': 0}),
 ('source', '2in', {'capacity': 1, 'cost': 0}),
 ('source', '4in', {'capacity': 1, 'cost': 0}),
 ('source', '3in', {'capacity': 1, 'cost': 0}),
 ('7in', '7out', {'capacity': 1, 'cost': 0}),
 ('2out', '7in', {'capacity': 1, 'cost': -26.17}),
 ('2out', 'destination', {'capacity': 1, 'cost': -25.84}),
 ('2out', '6in', {'capacity': 1, 'cost': -26.76}),
 ('2out', '5in', {'capacity': 1, 'cost': -27.0}),
 ('2out', '4in', {'capacity': 1, 'cost': -27.0}),
 ('2out', '3in', {'capacity': 1, 'cost': -28.0}),
 ('6in', '6out', {'capacity': 1, 'cost': 0}),
 ('5in', '5out', {'capacity': 1, 'cost': 0}),
 ('2in', '2out', {'capacity': 1, 'cost': 0}),
 ('7out', 'destination', {'capacity': 1, 'cost': -27.59}),
 ('4in', '4out', {'capacity': 1, 'cost': 0}),
 ('1out', '7in', {'capacity': 1, 'cost': -25.84}),
 ('1out', 'destination', {'capacity': 1, 'cost': -25.0}),
 ('1out', '6in', {'capacity': 1, 'cost': -26.76}),
 ('1out', '5in', {'capacity': 1, 'cost': -27.59}),
 ('1out', '2in', {'capacity': 1, 'cost': -27.59}),
 ('1out', '4in', {'capacity': 1, 'cost': -25.84}),
 ('1out', '3in', {'capacity': 1, 'cost': -26.76}),
 ('4out', '7in', {'capacity': 1, 'cost': -27.0}),
 ('4out', 'destination', {'capacity': 1, 'cost': -27.59}),
 ('4out', '6in', {'capacity': 1, 'cost': -26.76}),
 ('4out', '5in', {'capacity': 1, 'cost': -26.17}),
 ('3out', '7in', {'capacity': 1, 'cost': -26.76}),
 ('3out', '4in', {'capacity': 1, 'cost': -28.0}),
 ('3out', 'destination', {'capacity': 1, 'cost': -26.76}),
 ('3out', '6in', {'capacity': 1, 'cost': -27.0}),
 ('3out', '5in', {'capacity': 1, 'cost': -26.76}),
 ('3in', '3out', {'capacity': 1, 'cost': 0}),
 ('5out', '7in', {'capacity': 1, 'cost': -27.0}),
 ('5out', 'destination', {'capacity': 1, 'cost': -25.84}),
 ('5out', '6in', {'capacity': 1, 'cost': -28.0})]
```

If this is my mistake let me know (I even posted on [StackOverflow](http://stackoverflow.com/questions/36630271/python-networkx-max-flow-min-cost-function-running-forever)).



Discussion:
Hi @misingnoglic. The algorithm implemented in `nx.network_simplex` is not guaranteed to work if edge weights are floating point numbers, and `nx.max_flow_min_cost` has the same limitations as it's using it. However only the docs for the former say so. As a workaround you can convert your weights to integers. In your example, multiplying cost by 100 will do it:

``` python
In [2]: %paste
G = nx.DiGraph()
G.add_edges_from([
('1in', '1out', {'cost': 0, 'capacity': 1}),
('2out', '4in', {'cost': -948, 'capacity': 1}),
('2out', 'destination', {'cost': -1090, 'capacity': 1}),
('2out', '3in', {'cost': -1031, 'capacity': 1}),
('destination', 'sink', {'cost': 0, 'capacity': 1}),
('2in', '2out', {'cost': 0, 'capacity': 1}),
('source', '2in', {'cost': 0, 'capacity': 1}),
('source', '4in', {'cost': 0, 'capacity': 1}),
('source', '1in', {'cost': 0, 'capacity': 1}),
('source', '3in', {'cost': 0, 'capacity': 1}),
('4in', '4out', {'cost': 0, 'capacity': 1}),
('1out', '2in', {'cost': -1031, 'capacity': 1}),
('1out', '4in', {'cost': -1031, 'capacity': 1}),
('1out', 'destination', {'cost':-1090, 'capacity': 1}),
('1out', '3in', {'cost': -948, 'capacity': 1}),
('4out', 'destination', {'cost': -1090, 'capacity': 1}),
('3in', '3out', {'cost': 0, 'capacity': 1}),
('3out', '4in', {'cost': -1031, 'capacity': 1}),
('3out', 'destination', {'cost': -1090, 'capacity': 1})
])
## -- End pasted text --

In [3]: %time nx.max_flow_min_cost(G, 'source', 'sink', weight='cost')
CPU times: user 1.23 ms, sys: 0 ns, total: 1.23 ms
Wall time: 3.12 ms
Out[3]: 
{'1in': {'1out': 1},
 '1out': {'2in': 1, '3in': 0, '4in': 0, 'destination': 0},
 '2in': {'2out': 1},
 '2out': {'3in': 1, '4in': 0, 'destination': 0},
 '3in': {'3out': 1},
 '3out': {'4in': 1, 'destination': 0},
 '4in': {'4out': 1},
 '4out': {'destination': 1},
 'destination': {'sink': 1},
 'sink': {},
 'source': {'1in': 1, '2in': 0, '3in': 0, '4in': 0}}
```

I'll put together a PR (hopefully this weekend) updating the docs (also for `nx.network_simplex`) because they don't mention the conversion to integers workaround.

PS: It's not nice to cross post questions in different sites at the same time.

@jtorrents  Thank you for the response (I appreciate it a lot!), and sorry about the double posting - I figured if I posted on StackOverflow it would be answered if it was an issue related to graph theory, and here if it was something related to the specific implementation (also because in full disclosure my semester project is due tomorrow and I just realized this issue existed). 


Resolving patch:
diff --git a/networkx/algorithms/flow/mincost.py b/networkx/algorithms/flow/mincost.py
--- a/networkx/algorithms/flow/mincost.py
+++ b/networkx/algorithms/flow/mincost.py
@@ -81,6 +81,14 @@ def min_cost_flow_cost(G, demand = 'demand', capacity = 'capacity',
     --------
     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.
@@ -166,6 +174,14 @@ def min_cost_flow(G, demand = 'demand', capacity = 'capacity',
     --------
     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.
@@ -216,6 +232,14 @@ def cost_of_flow(G, flowDict, weight = '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)))
@@ -275,6 +299,14 @@ def max_flow_min_cost(G, s, t, capacity = 'capacity', weight = 'weight'):
     --------
     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()
@@ -303,7 +335,6 @@ def max_flow_min_cost(G, s, t, capacity = 'capacity', weight = 'weight'):
     >>> mincostFlowValue == nx.maximum_flow_value(G, 1, 7)
     True
 
-
     """
     maxFlow = nx.maximum_flow_value(G, s, t, capacity = capacity)
     H = nx.DiGraph(G)
diff --git a/networkx/algorithms/flow/networksimplex.py b/networkx/algorithms/flow/networksimplex.py
--- a/networkx/algorithms/flow/networksimplex.py
+++ b/networkx/algorithms/flow/networksimplex.py
@@ -96,7 +96,9 @@ def network_simplex(G, demand='demand', capacity='capacity', weight='weight'):
     -----
     This algorithm is not guaranteed to work if edge weights or demands
     are floating point numbers (overflows and roundoff errors can
-    cause problems).
+    cause problems). As a workaround you can use integer numbers by
+    multiplying the relevant edge attributes by a convenient
+    constant factor (eg 100).
 
     See also
     --------


Test patch: