about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-4a52a71956a8d46fcb7294ac71734504bb09bcc2.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2bin0 -> 44623 bytes
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2bin0 -> 42248 bytes
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2bin0 -> 18972 bytes
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py128
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow.py573
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py156
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_mincost.py476
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py387
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2bin0 -> 88132 bytes
10 files changed, 1720 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/__init__.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2 b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2
new file mode 100644
index 00000000..e6ed5744
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2
Binary files differdiff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2 b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2
new file mode 100644
index 00000000..abd0e8a2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2
Binary files differdiff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2
new file mode 100644
index 00000000..cd3ea801
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2
Binary files differdiff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py
new file mode 100644
index 00000000..1649ec82
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py
@@ -0,0 +1,128 @@
+from itertools import combinations
+
+import pytest
+
+import networkx as nx
+from networkx.algorithms.flow import (
+    boykov_kolmogorov,
+    dinitz,
+    edmonds_karp,
+    preflow_push,
+    shortest_augmenting_path,
+)
+
+flow_funcs = [
+    boykov_kolmogorov,
+    dinitz,
+    edmonds_karp,
+    preflow_push,
+    shortest_augmenting_path,
+]
+
+
+class TestGomoryHuTree:
+    def minimum_edge_weight(self, T, u, v):
+        path = nx.shortest_path(T, u, v, weight="weight")
+        return min((T[u][v]["weight"], (u, v)) for (u, v) in zip(path, path[1:]))
+
+    def compute_cutset(self, G, T_orig, edge):
+        T = T_orig.copy()
+        T.remove_edge(*edge)
+        U, V = list(nx.connected_components(T))
+        cutset = set()
+        for x, nbrs in ((n, G[n]) for n in U):
+            cutset.update((x, y) for y in nbrs if y in V)
+        return cutset
+
+    def test_default_flow_function_karate_club_graph(self):
+        G = nx.karate_club_graph()
+        nx.set_edge_attributes(G, 1, "capacity")
+        T = nx.gomory_hu_tree(G)
+        assert nx.is_tree(T)
+        for u, v in combinations(G, 2):
+            cut_value, edge = self.minimum_edge_weight(T, u, v)
+            assert nx.minimum_cut_value(G, u, v) == cut_value
+
+    def test_karate_club_graph(self):
+        G = nx.karate_club_graph()
+        nx.set_edge_attributes(G, 1, "capacity")
+        for flow_func in flow_funcs:
+            T = nx.gomory_hu_tree(G, flow_func=flow_func)
+            assert nx.is_tree(T)
+            for u, v in combinations(G, 2):
+                cut_value, edge = self.minimum_edge_weight(T, u, v)
+                assert nx.minimum_cut_value(G, u, v) == cut_value
+
+    def test_davis_southern_women_graph(self):
+        G = nx.davis_southern_women_graph()
+        nx.set_edge_attributes(G, 1, "capacity")
+        for flow_func in flow_funcs:
+            T = nx.gomory_hu_tree(G, flow_func=flow_func)
+            assert nx.is_tree(T)
+            for u, v in combinations(G, 2):
+                cut_value, edge = self.minimum_edge_weight(T, u, v)
+                assert nx.minimum_cut_value(G, u, v) == cut_value
+
+    def test_florentine_families_graph(self):
+        G = nx.florentine_families_graph()
+        nx.set_edge_attributes(G, 1, "capacity")
+        for flow_func in flow_funcs:
+            T = nx.gomory_hu_tree(G, flow_func=flow_func)
+            assert nx.is_tree(T)
+            for u, v in combinations(G, 2):
+                cut_value, edge = self.minimum_edge_weight(T, u, v)
+                assert nx.minimum_cut_value(G, u, v) == cut_value
+
+    @pytest.mark.slow
+    def test_les_miserables_graph_cutset(self):
+        G = nx.les_miserables_graph()
+        nx.set_edge_attributes(G, 1, "capacity")
+        for flow_func in flow_funcs:
+            T = nx.gomory_hu_tree(G, flow_func=flow_func)
+            assert nx.is_tree(T)
+            for u, v in combinations(G, 2):
+                cut_value, edge = self.minimum_edge_weight(T, u, v)
+                assert nx.minimum_cut_value(G, u, v) == cut_value
+
+    def test_karate_club_graph_cutset(self):
+        G = nx.karate_club_graph()
+        nx.set_edge_attributes(G, 1, "capacity")
+        T = nx.gomory_hu_tree(G)
+        assert nx.is_tree(T)
+        u, v = 0, 33
+        cut_value, edge = self.minimum_edge_weight(T, u, v)
+        cutset = self.compute_cutset(G, T, edge)
+        assert cut_value == len(cutset)
+
+    def test_wikipedia_example(self):
+        # Example from https://en.wikipedia.org/wiki/Gomory%E2%80%93Hu_tree
+        G = nx.Graph()
+        G.add_weighted_edges_from(
+            (
+                (0, 1, 1),
+                (0, 2, 7),
+                (1, 2, 1),
+                (1, 3, 3),
+                (1, 4, 2),
+                (2, 4, 4),
+                (3, 4, 1),
+                (3, 5, 6),
+                (4, 5, 2),
+            )
+        )
+        for flow_func in flow_funcs:
+            T = nx.gomory_hu_tree(G, capacity="weight", flow_func=flow_func)
+            assert nx.is_tree(T)
+            for u, v in combinations(G, 2):
+                cut_value, edge = self.minimum_edge_weight(T, u, v)
+                assert nx.minimum_cut_value(G, u, v, capacity="weight") == cut_value
+
+    def test_directed_raises(self):
+        with pytest.raises(nx.NetworkXNotImplemented):
+            G = nx.DiGraph()
+            T = nx.gomory_hu_tree(G)
+
+    def test_empty_raises(self):
+        with pytest.raises(nx.NetworkXError):
+            G = nx.empty_graph()
+            T = nx.gomory_hu_tree(G)
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow.py
new file mode 100644
index 00000000..d7305a7b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow.py
@@ -0,0 +1,573 @@
+"""Maximum flow algorithms test suite."""
+
+import pytest
+
+import networkx as nx
+from networkx.algorithms.flow import (
+    boykov_kolmogorov,
+    build_flow_dict,
+    build_residual_network,
+    dinitz,
+    edmonds_karp,
+    preflow_push,
+    shortest_augmenting_path,
+)
+
+flow_funcs = {
+    boykov_kolmogorov,
+    dinitz,
+    edmonds_karp,
+    preflow_push,
+    shortest_augmenting_path,
+}
+
+max_min_funcs = {nx.maximum_flow, nx.minimum_cut}
+flow_value_funcs = {nx.maximum_flow_value, nx.minimum_cut_value}
+interface_funcs = max_min_funcs | flow_value_funcs
+all_funcs = flow_funcs | interface_funcs
+
+
+def compute_cutset(G, partition):
+    reachable, non_reachable = partition
+    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)
+    return cutset
+
+
+def validate_flows(G, s, t, flowDict, solnValue, capacity, flow_func):
+    errmsg = f"Assertion failed in function: {flow_func.__name__}"
+    assert set(G) == set(flowDict), errmsg
+    for u in G:
+        assert set(G[u]) == set(flowDict[u]), errmsg
+    excess = {u: 0 for u in flowDict}
+    for u in flowDict:
+        for v, flow in flowDict[u].items():
+            if capacity in G[u][v]:
+                assert flow <= G[u][v][capacity]
+            assert flow >= 0, errmsg
+            excess[u] -= flow
+            excess[v] += flow
+    for u, exc in excess.items():
+        if u == s:
+            assert exc == -solnValue, errmsg
+        elif u == t:
+            assert exc == solnValue, errmsg
+        else:
+            assert exc == 0, errmsg
+
+
+def validate_cuts(G, s, t, solnValue, partition, capacity, flow_func):
+    errmsg = f"Assertion failed in function: {flow_func.__name__}"
+    assert all(n in G for n in partition[0]), errmsg
+    assert all(n in G for n in partition[1]), errmsg
+    cutset = compute_cutset(G, partition)
+    assert all(G.has_edge(u, v) for (u, v) in cutset), errmsg
+    assert solnValue == sum(G[u][v][capacity] for (u, v) in cutset), errmsg
+    H = G.copy()
+    H.remove_edges_from(cutset)
+    if not G.is_directed():
+        assert not nx.is_connected(H), errmsg
+    else:
+        assert not nx.is_strongly_connected(H), errmsg
+
+
+def compare_flows_and_cuts(G, s, t, solnValue, capacity="capacity"):
+    for flow_func in flow_funcs:
+        errmsg = f"Assertion failed in function: {flow_func.__name__}"
+        R = flow_func(G, s, t, capacity)
+        # Test both legacy and new implementations.
+        flow_value = R.graph["flow_value"]
+        flow_dict = build_flow_dict(G, R)
+        assert flow_value == solnValue, errmsg
+        validate_flows(G, s, t, flow_dict, solnValue, capacity, flow_func)
+        # Minimum cut
+        cut_value, partition = nx.minimum_cut(
+            G, s, t, capacity=capacity, flow_func=flow_func
+        )
+        validate_cuts(G, s, t, solnValue, partition, capacity, flow_func)
+
+
+class TestMaxflowMinCutCommon:
+    def test_graph1(self):
+        # Trivial undirected graph
+        G = nx.Graph()
+        G.add_edge(1, 2, capacity=1.0)
+
+        # solution flows
+        # {1: {2: 1.0}, 2: {1: 1.0}}
+
+        compare_flows_and_cuts(G, 1, 2, 1.0)
+
+    def test_graph2(self):
+        # A more complex undirected graph
+        # adapted from https://web.archive.org/web/20220815055650/https://www.topcoder.com/thrive/articles/Maximum%20Flow:%20Part%20One
+        G = nx.Graph()
+        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)
+
+        # H
+        # {
+        #     "x": {"a": 3, "b": 1},
+        #     "a": {"c": 3, "x": 3},
+        #     "b": {"c": 1, "d": 2, "x": 1},
+        #     "c": {"a": 3, "b": 1, "y": 2},
+        #     "d": {"b": 2, "e": 2},
+        #     "e": {"d": 2, "y": 2},
+        #     "y": {"c": 2, "e": 2},
+        # }
+
+        compare_flows_and_cuts(G, "x", "y", 4.0)
+
+    def test_digraph1(self):
+        # The classic directed graph example
+        G = nx.DiGraph()
+        G.add_edge("a", "b", capacity=1000.0)
+        G.add_edge("a", "c", capacity=1000.0)
+        G.add_edge("b", "c", capacity=1.0)
+        G.add_edge("b", "d", capacity=1000.0)
+        G.add_edge("c", "d", capacity=1000.0)
+
+        # H
+        # {
+        #     "a": {"b": 1000.0, "c": 1000.0},
+        #     "b": {"c": 0, "d": 1000.0},
+        #     "c": {"d": 1000.0},
+        #     "d": {},
+        # }
+
+        compare_flows_and_cuts(G, "a", "d", 2000.0)
+
+    def test_digraph2(self):
+        # An example in which some edges end up with zero flow.
+        G = nx.DiGraph()
+        G.add_edge("s", "b", capacity=2)
+        G.add_edge("s", "c", capacity=1)
+        G.add_edge("c", "d", capacity=1)
+        G.add_edge("d", "a", capacity=1)
+        G.add_edge("b", "a", capacity=2)
+        G.add_edge("a", "t", capacity=2)
+
+        # H
+        # {
+        #     "s": {"b": 2, "c": 0},
+        #     "c": {"d": 0},
+        #     "d": {"a": 0},
+        #     "b": {"a": 2},
+        #     "a": {"t": 2},
+        #     "t": {},
+        # }
+
+        compare_flows_and_cuts(G, "s", "t", 2)
+
+    def test_digraph3(self):
+        # A directed graph example from Cormen et al.
+        G = nx.DiGraph()
+        G.add_edge("s", "v1", capacity=16.0)
+        G.add_edge("s", "v2", capacity=13.0)
+        G.add_edge("v1", "v2", capacity=10.0)
+        G.add_edge("v2", "v1", capacity=4.0)
+        G.add_edge("v1", "v3", capacity=12.0)
+        G.add_edge("v3", "v2", capacity=9.0)
+        G.add_edge("v2", "v4", capacity=14.0)
+        G.add_edge("v4", "v3", capacity=7.0)
+        G.add_edge("v3", "t", capacity=20.0)
+        G.add_edge("v4", "t", capacity=4.0)
+
+        # H
+        # {
+        #     "s": {"v1": 12.0, "v2": 11.0},
+        #     "v2": {"v1": 0, "v4": 11.0},
+        #     "v1": {"v2": 0, "v3": 12.0},
+        #     "v3": {"v2": 0, "t": 19.0},
+        #     "v4": {"v3": 7.0, "t": 4.0},
+        #     "t": {},
+        # }
+
+        compare_flows_and_cuts(G, "s", "t", 23.0)
+
+    def test_digraph4(self):
+        # A more complex directed graph
+        # from https://web.archive.org/web/20220815055650/https://www.topcoder.com/thrive/articles/Maximum%20Flow:%20Part%20One
+        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)
+
+        # H
+        # {
+        #     "x": {"a": 2.0, "b": 1.0},
+        #     "a": {"c": 2.0},
+        #     "b": {"c": 0, "d": 1.0},
+        #     "c": {"y": 2.0},
+        #     "d": {"e": 1.0},
+        #     "e": {"y": 1.0},
+        #     "y": {},
+        # }
+
+        compare_flows_and_cuts(G, "x", "y", 3.0)
+
+    def test_wikipedia_dinitz_example(self):
+        # Nice example from https://en.wikipedia.org/wiki/Dinic's_algorithm
+        G = nx.DiGraph()
+        G.add_edge("s", 1, capacity=10)
+        G.add_edge("s", 2, capacity=10)
+        G.add_edge(1, 3, capacity=4)
+        G.add_edge(1, 4, capacity=8)
+        G.add_edge(1, 2, capacity=2)
+        G.add_edge(2, 4, capacity=9)
+        G.add_edge(3, "t", capacity=10)
+        G.add_edge(4, 3, capacity=6)
+        G.add_edge(4, "t", capacity=10)
+
+        # solution flows
+        # {
+        #     1: {2: 0, 3: 4, 4: 6},
+        #     2: {4: 9},
+        #     3: {"t": 9},
+        #     4: {3: 5, "t": 10},
+        #     "s": {1: 10, 2: 9},
+        #     "t": {},
+        # }
+
+        compare_flows_and_cuts(G, "s", "t", 19)
+
+    def test_optional_capacity(self):
+        # Test optional capacity parameter.
+        G = nx.DiGraph()
+        G.add_edge("x", "a", spam=3.0)
+        G.add_edge("x", "b", spam=1.0)
+        G.add_edge("a", "c", spam=3.0)
+        G.add_edge("b", "c", spam=5.0)
+        G.add_edge("b", "d", spam=4.0)
+        G.add_edge("d", "e", spam=2.0)
+        G.add_edge("c", "y", spam=2.0)
+        G.add_edge("e", "y", spam=3.0)
+
+        # solution flows
+        # {
+        #     "x": {"a": 2.0, "b": 1.0},
+        #     "a": {"c": 2.0},
+        #     "b": {"c": 0, "d": 1.0},
+        #     "c": {"y": 2.0},
+        #     "d": {"e": 1.0},
+        #     "e": {"y": 1.0},
+        #     "y": {},
+        # }
+        solnValue = 3.0
+        s = "x"
+        t = "y"
+
+        compare_flows_and_cuts(G, s, t, solnValue, capacity="spam")
+
+    def test_digraph_infcap_edges(self):
+        # DiGraph with infinite capacity edges
+        G = nx.DiGraph()
+        G.add_edge("s", "a")
+        G.add_edge("s", "b", capacity=30)
+        G.add_edge("a", "c", capacity=25)
+        G.add_edge("b", "c", capacity=12)
+        G.add_edge("a", "t", capacity=60)
+        G.add_edge("c", "t")
+
+        # H
+        # {
+        #     "s": {"a": 85, "b": 12},
+        #     "a": {"c": 25, "t": 60},
+        #     "b": {"c": 12},
+        #     "c": {"t": 37},
+        #     "t": {},
+        # }
+
+        compare_flows_and_cuts(G, "s", "t", 97)
+
+        # DiGraph with infinite capacity digon
+        G = nx.DiGraph()
+        G.add_edge("s", "a", capacity=85)
+        G.add_edge("s", "b", capacity=30)
+        G.add_edge("a", "c")
+        G.add_edge("c", "a")
+        G.add_edge("b", "c", capacity=12)
+        G.add_edge("a", "t", capacity=60)
+        G.add_edge("c", "t", capacity=37)
+
+        # H
+        # {
+        #     "s": {"a": 85, "b": 12},
+        #     "a": {"c": 25, "t": 60},
+        #     "c": {"a": 0, "t": 37},
+        #     "b": {"c": 12},
+        #     "t": {},
+        # }
+
+        compare_flows_and_cuts(G, "s", "t", 97)
+
+    def test_digraph_infcap_path(self):
+        # Graph with infinite capacity (s, t)-path
+        G = nx.DiGraph()
+        G.add_edge("s", "a")
+        G.add_edge("s", "b", capacity=30)
+        G.add_edge("a", "c")
+        G.add_edge("b", "c", capacity=12)
+        G.add_edge("a", "t", capacity=60)
+        G.add_edge("c", "t")
+
+        for flow_func in all_funcs:
+            pytest.raises(nx.NetworkXUnbounded, flow_func, G, "s", "t")
+
+    def test_graph_infcap_edges(self):
+        # Undirected graph with infinite capacity edges
+        G = nx.Graph()
+        G.add_edge("s", "a")
+        G.add_edge("s", "b", capacity=30)
+        G.add_edge("a", "c", capacity=25)
+        G.add_edge("b", "c", capacity=12)
+        G.add_edge("a", "t", capacity=60)
+        G.add_edge("c", "t")
+
+        # H
+        # {
+        #     "s": {"a": 85, "b": 12},
+        #     "a": {"c": 25, "s": 85, "t": 60},
+        #     "b": {"c": 12, "s": 12},
+        #     "c": {"a": 25, "b": 12, "t": 37},
+        #     "t": {"a": 60, "c": 37},
+        # }
+
+        compare_flows_and_cuts(G, "s", "t", 97)
+
+    def test_digraph5(self):
+        # From ticket #429 by mfrasca.
+        G = nx.DiGraph()
+        G.add_edge("s", "a", capacity=2)
+        G.add_edge("s", "b", capacity=2)
+        G.add_edge("a", "b", capacity=5)
+        G.add_edge("a", "t", capacity=1)
+        G.add_edge("b", "a", capacity=1)
+        G.add_edge("b", "t", capacity=3)
+        # flow solution
+        # {
+        #     "a": {"b": 1, "t": 1},
+        #     "b": {"a": 0, "t": 3},
+        #     "s": {"a": 2, "b": 2},
+        #     "t": {},
+        # }
+        compare_flows_and_cuts(G, "s", "t", 4)
+
+    def test_disconnected(self):
+        G = nx.Graph()
+        G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity")
+        G.remove_node(1)
+        assert nx.maximum_flow_value(G, 0, 3) == 0
+        # flow solution
+        # {0: {}, 2: {3: 0}, 3: {2: 0}}
+        compare_flows_and_cuts(G, 0, 3, 0)
+
+    def test_source_target_not_in_graph(self):
+        G = nx.Graph()
+        G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity")
+        G.remove_node(0)
+        for flow_func in all_funcs:
+            pytest.raises(nx.NetworkXError, flow_func, G, 0, 3)
+        G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity")
+        G.remove_node(3)
+        for flow_func in all_funcs:
+            pytest.raises(nx.NetworkXError, flow_func, G, 0, 3)
+
+    def test_source_target_coincide(self):
+        G = nx.Graph()
+        G.add_node(0)
+        for flow_func in all_funcs:
+            pytest.raises(nx.NetworkXError, flow_func, G, 0, 0)
+
+    def test_multigraphs_raise(self):
+        G = nx.MultiGraph()
+        M = nx.MultiDiGraph()
+        G.add_edges_from([(0, 1), (1, 0)], capacity=True)
+        for flow_func in all_funcs:
+            pytest.raises(nx.NetworkXError, flow_func, G, 0, 0)
+
+
+class TestMaxFlowMinCutInterface:
+    def setup_method(self):
+        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)
+        self.G = G
+        H = nx.DiGraph()
+        H.add_edge(0, 1, capacity=1.0)
+        H.add_edge(1, 2, capacity=1.0)
+        self.H = H
+
+    def test_flow_func_not_callable(self):
+        elements = ["this_should_be_callable", 10, {1, 2, 3}]
+        G = nx.Graph()
+        G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight="capacity")
+        for flow_func in interface_funcs:
+            for element in elements:
+                pytest.raises(nx.NetworkXError, flow_func, G, 0, 1, flow_func=element)
+                pytest.raises(nx.NetworkXError, flow_func, G, 0, 1, flow_func=element)
+
+    def test_flow_func_parameters(self):
+        G = self.G
+        fv = 3.0
+        for interface_func in interface_funcs:
+            for flow_func in flow_funcs:
+                errmsg = (
+                    f"Assertion failed in function: {flow_func.__name__} "
+                    f"in interface {interface_func.__name__}"
+                )
+                result = interface_func(G, "x", "y", flow_func=flow_func)
+                if interface_func in max_min_funcs:
+                    result = result[0]
+                assert fv == result, errmsg
+
+    def test_minimum_cut_no_cutoff(self):
+        G = self.G
+        pytest.raises(
+            nx.NetworkXError,
+            nx.minimum_cut,
+            G,
+            "x",
+            "y",
+            flow_func=preflow_push,
+            cutoff=1.0,
+        )
+        pytest.raises(
+            nx.NetworkXError,
+            nx.minimum_cut_value,
+            G,
+            "x",
+            "y",
+            flow_func=preflow_push,
+            cutoff=1.0,
+        )
+
+    def test_kwargs(self):
+        G = self.H
+        fv = 1.0
+        to_test = (
+            (shortest_augmenting_path, {"two_phase": True}),
+            (preflow_push, {"global_relabel_freq": 5}),
+        )
+        for interface_func in interface_funcs:
+            for flow_func, kwargs in to_test:
+                errmsg = (
+                    f"Assertion failed in function: {flow_func.__name__} "
+                    f"in interface {interface_func.__name__}"
+                )
+                result = interface_func(G, 0, 2, flow_func=flow_func, **kwargs)
+                if interface_func in max_min_funcs:
+                    result = result[0]
+                assert fv == result, errmsg
+
+    def test_kwargs_default_flow_func(self):
+        G = self.H
+        for interface_func in interface_funcs:
+            pytest.raises(
+                nx.NetworkXError, interface_func, G, 0, 1, global_relabel_freq=2
+            )
+
+    def test_reusing_residual(self):
+        G = self.G
+        fv = 3.0
+        s, t = "x", "y"
+        R = build_residual_network(G, "capacity")
+        for interface_func in interface_funcs:
+            for flow_func in flow_funcs:
+                errmsg = (
+                    f"Assertion failed in function: {flow_func.__name__} "
+                    f"in interface {interface_func.__name__}"
+                )
+                for i in range(3):
+                    result = interface_func(
+                        G, "x", "y", flow_func=flow_func, residual=R
+                    )
+                    if interface_func in max_min_funcs:
+                        result = result[0]
+                    assert fv == result, errmsg
+
+
+# Tests specific to one algorithm
+def test_preflow_push_global_relabel_freq():
+    G = nx.DiGraph()
+    G.add_edge(1, 2, capacity=1)
+    R = preflow_push(G, 1, 2, global_relabel_freq=None)
+    assert R.graph["flow_value"] == 1
+    pytest.raises(nx.NetworkXError, preflow_push, G, 1, 2, global_relabel_freq=-1)
+
+
+def test_preflow_push_makes_enough_space():
+    # From ticket #1542
+    G = nx.DiGraph()
+    nx.add_path(G, [0, 1, 3], capacity=1)
+    nx.add_path(G, [1, 2, 3], capacity=1)
+    R = preflow_push(G, 0, 3, value_only=False)
+    assert R.graph["flow_value"] == 1
+
+
+def test_shortest_augmenting_path_two_phase():
+    k = 5
+    p = 1000
+    G = nx.DiGraph()
+    for i in range(k):
+        G.add_edge("s", (i, 0), capacity=1)
+        nx.add_path(G, ((i, j) for j in range(p)), capacity=1)
+        G.add_edge((i, p - 1), "t", capacity=1)
+    R = shortest_augmenting_path(G, "s", "t", two_phase=True)
+    assert R.graph["flow_value"] == k
+    R = shortest_augmenting_path(G, "s", "t", two_phase=False)
+    assert R.graph["flow_value"] == k
+
+
+class TestCutoff:
+    def test_cutoff(self):
+        k = 5
+        p = 1000
+        G = nx.DiGraph()
+        for i in range(k):
+            G.add_edge("s", (i, 0), capacity=2)
+            nx.add_path(G, ((i, j) for j in range(p)), capacity=2)
+            G.add_edge((i, p - 1), "t", capacity=2)
+        R = shortest_augmenting_path(G, "s", "t", two_phase=True, cutoff=k)
+        assert k <= R.graph["flow_value"] <= (2 * k)
+        R = shortest_augmenting_path(G, "s", "t", two_phase=False, cutoff=k)
+        assert k <= R.graph["flow_value"] <= (2 * k)
+        R = edmonds_karp(G, "s", "t", cutoff=k)
+        assert k <= R.graph["flow_value"] <= (2 * k)
+        R = dinitz(G, "s", "t", cutoff=k)
+        assert k <= R.graph["flow_value"] <= (2 * k)
+        R = boykov_kolmogorov(G, "s", "t", cutoff=k)
+        assert k <= R.graph["flow_value"] <= (2 * k)
+
+    def test_complete_graph_cutoff(self):
+        G = nx.complete_graph(5)
+        nx.set_edge_attributes(G, {(u, v): 1 for u, v in G.edges()}, "capacity")
+        for flow_func in [
+            shortest_augmenting_path,
+            edmonds_karp,
+            dinitz,
+            boykov_kolmogorov,
+        ]:
+            for cutoff in [3, 2, 1]:
+                result = nx.maximum_flow_value(
+                    G, 0, 4, flow_func=flow_func, cutoff=cutoff
+                )
+                assert cutoff == result, f"cutoff error in {flow_func.__name__}"
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py
new file mode 100644
index 00000000..b395cbc8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py
@@ -0,0 +1,156 @@
+"""Maximum flow algorithms test suite on large graphs."""
+
+import bz2
+import importlib.resources
+import os
+import pickle
+
+import pytest
+
+import networkx as nx
+from networkx.algorithms.flow import (
+    boykov_kolmogorov,
+    build_flow_dict,
+    build_residual_network,
+    dinitz,
+    edmonds_karp,
+    preflow_push,
+    shortest_augmenting_path,
+)
+
+flow_funcs = [
+    boykov_kolmogorov,
+    dinitz,
+    edmonds_karp,
+    preflow_push,
+    shortest_augmenting_path,
+]
+
+
+def gen_pyramid(N):
+    # This graph admits a flow of value 1 for which every arc is at
+    # capacity (except the arcs incident to the sink which have
+    # infinite capacity).
+    G = nx.DiGraph()
+
+    for i in range(N - 1):
+        cap = 1.0 / (i + 2)
+        for j in range(i + 1):
+            G.add_edge((i, j), (i + 1, j), capacity=cap)
+            cap = 1.0 / (i + 1) - cap
+            G.add_edge((i, j), (i + 1, j + 1), capacity=cap)
+            cap = 1.0 / (i + 2) - cap
+
+    for j in range(N):
+        G.add_edge((N - 1, j), "t")
+
+    return G
+
+
+def read_graph(name):
+    fname = (
+        importlib.resources.files("networkx.algorithms.flow.tests")
+        / f"{name}.gpickle.bz2"
+    )
+
+    with bz2.BZ2File(fname, "rb") as f:
+        G = pickle.load(f)
+    return G
+
+
+def validate_flows(G, s, t, soln_value, R, flow_func):
+    flow_value = R.graph["flow_value"]
+    flow_dict = build_flow_dict(G, R)
+    errmsg = f"Assertion failed in function: {flow_func.__name__}"
+    assert soln_value == flow_value, errmsg
+    assert set(G) == set(flow_dict), errmsg
+    for u in G:
+        assert set(G[u]) == set(flow_dict[u]), errmsg
+    excess = {u: 0 for u in flow_dict}
+    for u in flow_dict:
+        for v, flow in flow_dict[u].items():
+            assert flow <= G[u][v].get("capacity", float("inf")), errmsg
+            assert flow >= 0, errmsg
+            excess[u] -= flow
+            excess[v] += flow
+    for u, exc in excess.items():
+        if u == s:
+            assert exc == -soln_value, errmsg
+        elif u == t:
+            assert exc == soln_value, errmsg
+        else:
+            assert exc == 0, errmsg
+
+
+class TestMaxflowLargeGraph:
+    def test_complete_graph(self):
+        N = 50
+        G = nx.complete_graph(N)
+        nx.set_edge_attributes(G, 5, "capacity")
+        R = build_residual_network(G, "capacity")
+        kwargs = {"residual": R}
+
+        for flow_func in flow_funcs:
+            kwargs["flow_func"] = flow_func
+            errmsg = f"Assertion failed in function: {flow_func.__name__}"
+            flow_value = nx.maximum_flow_value(G, 1, 2, **kwargs)
+            assert flow_value == 5 * (N - 1), errmsg
+
+    def test_pyramid(self):
+        N = 10
+        # N = 100 # this gives a graph with 5051 nodes
+        G = gen_pyramid(N)
+        R = build_residual_network(G, "capacity")
+        kwargs = {"residual": R}
+
+        for flow_func in flow_funcs:
+            kwargs["flow_func"] = flow_func
+            errmsg = f"Assertion failed in function: {flow_func.__name__}"
+            flow_value = nx.maximum_flow_value(G, (0, 0), "t", **kwargs)
+            assert flow_value == pytest.approx(1.0, abs=1e-7)
+
+    def test_gl1(self):
+        G = read_graph("gl1")
+        s = 1
+        t = len(G)
+        R = build_residual_network(G, "capacity")
+        kwargs = {"residual": R}
+
+        # do one flow_func to save time
+        flow_func = flow_funcs[0]
+        validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), flow_func)
+
+    #        for flow_func in flow_funcs:
+    #            validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs),
+    #                           flow_func)
+
+    @pytest.mark.slow
+    def test_gw1(self):
+        G = read_graph("gw1")
+        s = 1
+        t = len(G)
+        R = build_residual_network(G, "capacity")
+        kwargs = {"residual": R}
+
+        for flow_func in flow_funcs:
+            validate_flows(G, s, t, 1202018, flow_func(G, s, t, **kwargs), flow_func)
+
+    def test_wlm3(self):
+        G = read_graph("wlm3")
+        s = 1
+        t = len(G)
+        R = build_residual_network(G, "capacity")
+        kwargs = {"residual": R}
+
+        # do one flow_func to save time
+        flow_func = flow_funcs[0]
+        validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), flow_func)
+
+    #        for flow_func in flow_funcs:
+    #            validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs),
+    #                           flow_func)
+
+    def test_preflow_push_global_relabel(self):
+        G = read_graph("gw1")
+        R = preflow_push(G, 1, len(G), global_relabel_freq=50)
+        assert R.graph["flow_value"] == 1202018
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_mincost.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_mincost.py
new file mode 100644
index 00000000..5b1794b1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_mincost.py
@@ -0,0 +1,476 @@
+import bz2
+import importlib.resources
+import os
+import pickle
+
+import pytest
+
+import networkx as nx
+
+
+class TestMinCostFlow:
+    def test_simple_digraph(self):
+        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, H = nx.network_simplex(G)
+        soln = {"a": {"b": 4, "c": 1}, "b": {"d": 4}, "c": {"d": 1}, "d": {}}
+        assert flowCost == 24
+        assert nx.min_cost_flow_cost(G) == 24
+        assert H == soln
+        assert nx.min_cost_flow(G) == soln
+        assert nx.cost_of_flow(G, H) == 24
+
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == 24
+        assert nx.cost_of_flow(G, H) == 24
+        assert H == soln
+
+    def test_negcycle_infcap(self):
+        G = nx.DiGraph()
+        G.add_node("s", demand=-5)
+        G.add_node("t", demand=5)
+        G.add_edge("s", "a", weight=1, capacity=3)
+        G.add_edge("a", "b", weight=3)
+        G.add_edge("c", "a", weight=-6)
+        G.add_edge("b", "d", weight=1)
+        G.add_edge("d", "c", weight=-2)
+        G.add_edge("d", "t", weight=1, capacity=3)
+        pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G)
+
+    def test_sum_demands_not_zero(self):
+        G = nx.DiGraph()
+        G.add_node("s", demand=-5)
+        G.add_node("t", demand=4)
+        G.add_edge("s", "a", weight=1, capacity=3)
+        G.add_edge("a", "b", weight=3)
+        G.add_edge("a", "c", weight=-6)
+        G.add_edge("b", "d", weight=1)
+        G.add_edge("c", "d", weight=-2)
+        G.add_edge("d", "t", weight=1, capacity=3)
+        pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G)
+
+    def test_no_flow_satisfying_demands(self):
+        G = nx.DiGraph()
+        G.add_node("s", demand=-5)
+        G.add_node("t", demand=5)
+        G.add_edge("s", "a", weight=1, capacity=3)
+        G.add_edge("a", "b", weight=3)
+        G.add_edge("a", "c", weight=-6)
+        G.add_edge("b", "d", weight=1)
+        G.add_edge("c", "d", weight=-2)
+        G.add_edge("d", "t", weight=1, capacity=3)
+        pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G)
+
+    def test_transshipment(self):
+        G = nx.DiGraph()
+        G.add_node("a", demand=1)
+        G.add_node("b", demand=-2)
+        G.add_node("c", demand=-2)
+        G.add_node("d", demand=3)
+        G.add_node("e", demand=-4)
+        G.add_node("f", demand=-4)
+        G.add_node("g", demand=3)
+        G.add_node("h", demand=2)
+        G.add_node("r", demand=3)
+        G.add_edge("a", "c", weight=3)
+        G.add_edge("r", "a", weight=2)
+        G.add_edge("b", "a", weight=9)
+        G.add_edge("r", "c", weight=0)
+        G.add_edge("b", "r", weight=-6)
+        G.add_edge("c", "d", weight=5)
+        G.add_edge("e", "r", weight=4)
+        G.add_edge("e", "f", weight=3)
+        G.add_edge("h", "b", weight=4)
+        G.add_edge("f", "d", weight=7)
+        G.add_edge("f", "h", weight=12)
+        G.add_edge("g", "d", weight=12)
+        G.add_edge("f", "g", weight=-1)
+        G.add_edge("h", "g", weight=-10)
+        flowCost, H = nx.network_simplex(G)
+        soln = {
+            "a": {"c": 0},
+            "b": {"a": 0, "r": 2},
+            "c": {"d": 3},
+            "d": {},
+            "e": {"r": 3, "f": 1},
+            "f": {"d": 0, "g": 3, "h": 2},
+            "g": {"d": 0},
+            "h": {"b": 0, "g": 0},
+            "r": {"a": 1, "c": 1},
+        }
+        assert flowCost == 41
+        assert nx.min_cost_flow_cost(G) == 41
+        assert H == soln
+        assert nx.min_cost_flow(G) == soln
+        assert nx.cost_of_flow(G, H) == 41
+
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == 41
+        assert nx.cost_of_flow(G, H) == 41
+        assert H == soln
+
+    def test_max_flow_min_cost(self):
+        G = nx.DiGraph()
+        G.add_edge("s", "a", bandwidth=6)
+        G.add_edge("s", "c", bandwidth=10, cost=10)
+        G.add_edge("a", "b", cost=6)
+        G.add_edge("b", "d", bandwidth=8, cost=7)
+        G.add_edge("c", "d", cost=10)
+        G.add_edge("d", "t", bandwidth=5, cost=5)
+        soln = {
+            "s": {"a": 5, "c": 0},
+            "a": {"b": 5},
+            "b": {"d": 5},
+            "c": {"d": 0},
+            "d": {"t": 5},
+            "t": {},
+        }
+        flow = nx.max_flow_min_cost(G, "s", "t", capacity="bandwidth", weight="cost")
+        assert flow == soln
+        assert nx.cost_of_flow(G, flow, weight="cost") == 90
+
+        G.add_edge("t", "s", cost=-100)
+        flowCost, flow = nx.capacity_scaling(G, capacity="bandwidth", weight="cost")
+        G.remove_edge("t", "s")
+        assert flowCost == -410
+        assert flow["t"]["s"] == 5
+        del flow["t"]["s"]
+        assert flow == soln
+        assert nx.cost_of_flow(G, flow, weight="cost") == 90
+
+    def test_digraph1(self):
+        # From Bradley, S. P., Hax, A. C. and Magnanti, T. L. Applied
+        # Mathematical Programming. Addison-Wesley, 1977.
+        G = nx.DiGraph()
+        G.add_node(1, demand=-20)
+        G.add_node(4, demand=5)
+        G.add_node(5, demand=15)
+        G.add_edges_from(
+            [
+                (1, 2, {"capacity": 15, "weight": 4}),
+                (1, 3, {"capacity": 8, "weight": 4}),
+                (2, 3, {"weight": 2}),
+                (2, 4, {"capacity": 4, "weight": 2}),
+                (2, 5, {"capacity": 10, "weight": 6}),
+                (3, 4, {"capacity": 15, "weight": 1}),
+                (3, 5, {"capacity": 5, "weight": 3}),
+                (4, 5, {"weight": 2}),
+                (5, 3, {"capacity": 4, "weight": 1}),
+            ]
+        )
+        flowCost, H = nx.network_simplex(G)
+        soln = {
+            1: {2: 12, 3: 8},
+            2: {3: 8, 4: 4, 5: 0},
+            3: {4: 11, 5: 5},
+            4: {5: 10},
+            5: {3: 0},
+        }
+        assert flowCost == 150
+        assert nx.min_cost_flow_cost(G) == 150
+        assert H == soln
+        assert nx.min_cost_flow(G) == soln
+        assert nx.cost_of_flow(G, H) == 150
+
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == 150
+        assert H == soln
+        assert nx.cost_of_flow(G, H) == 150
+
+    def test_digraph2(self):
+        # Example from ticket #430 from mfrasca. Original source:
+        # http://www.cs.princeton.edu/courses/archive/spr03/cs226/lectures/mincost.4up.pdf, slide 11.
+        G = nx.DiGraph()
+        G.add_edge("s", 1, capacity=12)
+        G.add_edge("s", 2, capacity=6)
+        G.add_edge("s", 3, capacity=14)
+        G.add_edge(1, 2, capacity=11, weight=4)
+        G.add_edge(2, 3, capacity=9, weight=6)
+        G.add_edge(1, 4, capacity=5, weight=5)
+        G.add_edge(1, 5, capacity=2, weight=12)
+        G.add_edge(2, 5, capacity=4, weight=4)
+        G.add_edge(2, 6, capacity=2, weight=6)
+        G.add_edge(3, 6, capacity=31, weight=3)
+        G.add_edge(4, 5, capacity=18, weight=4)
+        G.add_edge(5, 6, capacity=9, weight=5)
+        G.add_edge(4, "t", capacity=3)
+        G.add_edge(5, "t", capacity=7)
+        G.add_edge(6, "t", capacity=22)
+        flow = nx.max_flow_min_cost(G, "s", "t")
+        soln = {
+            1: {2: 6, 4: 5, 5: 1},
+            2: {3: 6, 5: 4, 6: 2},
+            3: {6: 20},
+            4: {5: 2, "t": 3},
+            5: {6: 0, "t": 7},
+            6: {"t": 22},
+            "s": {1: 12, 2: 6, 3: 14},
+            "t": {},
+        }
+        assert flow == soln
+
+        G.add_edge("t", "s", weight=-100)
+        flowCost, flow = nx.capacity_scaling(G)
+        G.remove_edge("t", "s")
+        assert flow["t"]["s"] == 32
+        assert flowCost == -3007
+        del flow["t"]["s"]
+        assert flow == soln
+        assert nx.cost_of_flow(G, flow) == 193
+
+    def test_digraph3(self):
+        """Combinatorial Optimization: Algorithms and Complexity,
+        Papadimitriou Steiglitz at page 140 has an example, 7.1, but that
+        admits multiple solutions, so I alter it a bit. From ticket #430
+        by mfrasca."""
+
+        G = nx.DiGraph()
+        G.add_edge("s", "a")
+        G["s"]["a"].update({0: 2, 1: 4})
+        G.add_edge("s", "b")
+        G["s"]["b"].update({0: 2, 1: 1})
+        G.add_edge("a", "b")
+        G["a"]["b"].update({0: 5, 1: 2})
+        G.add_edge("a", "t")
+        G["a"]["t"].update({0: 1, 1: 5})
+        G.add_edge("b", "a")
+        G["b"]["a"].update({0: 1, 1: 3})
+        G.add_edge("b", "t")
+        G["b"]["t"].update({0: 3, 1: 2})
+
+        "PS.ex.7.1: testing main function"
+        sol = nx.max_flow_min_cost(G, "s", "t", capacity=0, weight=1)
+        flow = sum(v for v in sol["s"].values())
+        assert 4 == flow
+        assert 23 == nx.cost_of_flow(G, sol, weight=1)
+        assert sol["s"] == {"a": 2, "b": 2}
+        assert sol["a"] == {"b": 1, "t": 1}
+        assert sol["b"] == {"a": 0, "t": 3}
+        assert sol["t"] == {}
+
+        G.add_edge("t", "s")
+        G["t"]["s"].update({1: -100})
+        flowCost, sol = nx.capacity_scaling(G, capacity=0, weight=1)
+        G.remove_edge("t", "s")
+        flow = sum(v for v in sol["s"].values())
+        assert 4 == flow
+        assert sol["t"]["s"] == 4
+        assert flowCost == -377
+        del sol["t"]["s"]
+        assert sol["s"] == {"a": 2, "b": 2}
+        assert sol["a"] == {"b": 1, "t": 1}
+        assert sol["b"] == {"a": 0, "t": 3}
+        assert sol["t"] == {}
+        assert nx.cost_of_flow(G, sol, weight=1) == 23
+
+    def test_zero_capacity_edges(self):
+        """Address issue raised in ticket #617 by arv."""
+        G = nx.DiGraph()
+        G.add_edges_from(
+            [
+                (1, 2, {"capacity": 1, "weight": 1}),
+                (1, 5, {"capacity": 1, "weight": 1}),
+                (2, 3, {"capacity": 0, "weight": 1}),
+                (2, 5, {"capacity": 1, "weight": 1}),
+                (5, 3, {"capacity": 2, "weight": 1}),
+                (5, 4, {"capacity": 0, "weight": 1}),
+                (3, 4, {"capacity": 2, "weight": 1}),
+            ]
+        )
+        G.nodes[1]["demand"] = -1
+        G.nodes[2]["demand"] = -1
+        G.nodes[4]["demand"] = 2
+
+        flowCost, H = nx.network_simplex(G)
+        soln = {1: {2: 0, 5: 1}, 2: {3: 0, 5: 1}, 3: {4: 2}, 4: {}, 5: {3: 2, 4: 0}}
+        assert flowCost == 6
+        assert nx.min_cost_flow_cost(G) == 6
+        assert H == soln
+        assert nx.min_cost_flow(G) == soln
+        assert nx.cost_of_flow(G, H) == 6
+
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == 6
+        assert H == soln
+        assert nx.cost_of_flow(G, H) == 6
+
+    def test_digon(self):
+        """Check if digons are handled properly. Taken from ticket
+        #618 by arv."""
+        nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})]
+        edges = [
+            (1, 2, {"capacity": 3, "weight": 600000}),
+            (2, 1, {"capacity": 2, "weight": 0}),
+            (2, 3, {"capacity": 5, "weight": 714285}),
+            (3, 2, {"capacity": 2, "weight": 0}),
+        ]
+        G = nx.DiGraph(edges)
+        G.add_nodes_from(nodes)
+        flowCost, H = nx.network_simplex(G)
+        soln = {1: {2: 0}, 2: {1: 0, 3: 4}, 3: {2: 0}}
+        assert flowCost == 2857140
+        assert nx.min_cost_flow_cost(G) == 2857140
+        assert H == soln
+        assert nx.min_cost_flow(G) == soln
+        assert nx.cost_of_flow(G, H) == 2857140
+
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == 2857140
+        assert H == soln
+        assert nx.cost_of_flow(G, H) == 2857140
+
+    def test_deadend(self):
+        """Check if one-node cycles are handled properly. Taken from ticket
+        #2906 from @sshraven."""
+        G = nx.DiGraph()
+
+        G.add_nodes_from(range(5), demand=0)
+        G.nodes[4]["demand"] = -13
+        G.nodes[3]["demand"] = 13
+
+        G.add_edges_from([(0, 2), (0, 3), (2, 1)], capacity=20, weight=0.1)
+        pytest.raises(nx.NetworkXUnfeasible, nx.min_cost_flow, G)
+
+    def test_infinite_capacity_neg_digon(self):
+        """An infinite capacity negative cost digon results in an unbounded
+        instance."""
+        nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})]
+        edges = [
+            (1, 2, {"weight": -600}),
+            (2, 1, {"weight": 0}),
+            (2, 3, {"capacity": 5, "weight": 714285}),
+            (3, 2, {"capacity": 2, "weight": 0}),
+        ]
+        G = nx.DiGraph(edges)
+        G.add_nodes_from(nodes)
+        pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G)
+
+    def test_finite_capacity_neg_digon(self):
+        """The digon should receive the maximum amount of flow it can handle.
+        Taken from ticket #749 by @chuongdo."""
+        G = nx.DiGraph()
+        G.add_edge("a", "b", capacity=1, weight=-1)
+        G.add_edge("b", "a", capacity=1, weight=-1)
+        min_cost = -2
+        assert nx.min_cost_flow_cost(G) == min_cost
+
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == -2
+        assert H == {"a": {"b": 1}, "b": {"a": 1}}
+        assert nx.cost_of_flow(G, H) == -2
+
+    def test_multidigraph(self):
+        """Multidigraphs are acceptable."""
+        G = nx.MultiDiGraph()
+        G.add_weighted_edges_from([(1, 2, 1), (2, 3, 2)], weight="capacity")
+        flowCost, H = nx.network_simplex(G)
+        assert flowCost == 0
+        assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}}
+
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == 0
+        assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}}
+
+    def test_negative_selfloops(self):
+        """Negative selfloops should cause an exception if uncapacitated and
+        always be saturated otherwise.
+        """
+        G = nx.DiGraph()
+        G.add_edge(1, 1, weight=-1)
+        pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G)
+        G[1][1]["capacity"] = 2
+        flowCost, H = nx.network_simplex(G)
+        assert flowCost == -2
+        assert H == {1: {1: 2}}
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == -2
+        assert H == {1: {1: 2}}
+
+        G = nx.MultiDiGraph()
+        G.add_edge(1, 1, "x", weight=-1)
+        G.add_edge(1, 1, "y", weight=1)
+        pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G)
+        G[1][1]["x"]["capacity"] = 2
+        flowCost, H = nx.network_simplex(G)
+        assert flowCost == -2
+        assert H == {1: {1: {"x": 2, "y": 0}}}
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == -2
+        assert H == {1: {1: {"x": 2, "y": 0}}}
+
+    def test_bone_shaped(self):
+        # From #1283
+        G = nx.DiGraph()
+        G.add_node(0, demand=-4)
+        G.add_node(1, demand=2)
+        G.add_node(2, demand=2)
+        G.add_node(3, demand=4)
+        G.add_node(4, demand=-2)
+        G.add_node(5, demand=-2)
+        G.add_edge(0, 1, capacity=4)
+        G.add_edge(0, 2, capacity=4)
+        G.add_edge(4, 3, capacity=4)
+        G.add_edge(5, 3, capacity=4)
+        G.add_edge(0, 3, capacity=0)
+        flowCost, H = nx.network_simplex(G)
+        assert flowCost == 0
+        assert H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}}
+        flowCost, H = nx.capacity_scaling(G)
+        assert flowCost == 0
+        assert H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}}
+
+    def test_exceptions(self):
+        G = nx.Graph()
+        pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXNotImplemented, nx.capacity_scaling, G)
+        G = nx.MultiGraph()
+        pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXNotImplemented, nx.capacity_scaling, G)
+        G = nx.DiGraph()
+        pytest.raises(nx.NetworkXError, nx.network_simplex, G)
+        # pytest.raises(nx.NetworkXError, nx.capacity_scaling, G)
+        G.add_node(0, demand=float("inf"))
+        pytest.raises(nx.NetworkXError, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G)
+        G.nodes[0]["demand"] = 0
+        G.add_node(1, demand=0)
+        G.add_edge(0, 1, weight=-float("inf"))
+        pytest.raises(nx.NetworkXError, nx.network_simplex, G)
+        pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G)
+        G[0][1]["weight"] = 0
+        G.add_edge(0, 0, weight=float("inf"))
+        pytest.raises(nx.NetworkXError, nx.network_simplex, G)
+        # pytest.raises(nx.NetworkXError, nx.capacity_scaling, G)
+        G[0][0]["weight"] = 0
+        G[0][1]["capacity"] = -1
+        pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)
+        # pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G)
+        G[0][1]["capacity"] = 0
+        G[0][0]["capacity"] = -1
+        pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)
+        # pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G)
+
+    def test_large(self):
+        fname = (
+            importlib.resources.files("networkx.algorithms.flow.tests")
+            / "netgen-2.gpickle.bz2"
+        )
+        with bz2.BZ2File(fname, "rb") as f:
+            G = pickle.load(f)
+        flowCost, flowDict = nx.network_simplex(G)
+        assert 6749969302 == flowCost
+        assert 6749969302 == nx.cost_of_flow(G, flowDict)
+        flowCost, flowDict = nx.capacity_scaling(G)
+        assert 6749969302 == flowCost
+        assert 6749969302 == nx.cost_of_flow(G, flowDict)
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py
new file mode 100644
index 00000000..5b3b5f6d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py
@@ -0,0 +1,387 @@
+import bz2

+import importlib.resources

+import os

+import pickle

+

+import pytest

+

+import networkx as nx

+

+

+@pytest.fixture

+def simple_flow_graph():

+    G = nx.DiGraph()

+    G.add_node("a", demand=0)

+    G.add_node("b", demand=-5)

+    G.add_node("c", demand=50000000)

+    G.add_node("d", demand=-49999995)

+    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)

+    return G

+

+

+@pytest.fixture

+def simple_no_flow_graph():

+    G = nx.DiGraph()

+    G.add_node("s", demand=-5)

+    G.add_node("t", demand=5)

+    G.add_edge("s", "a", weight=1, capacity=3)

+    G.add_edge("a", "b", weight=3)

+    G.add_edge("a", "c", weight=-6)

+    G.add_edge("b", "d", weight=1)

+    G.add_edge("c", "d", weight=-2)

+    G.add_edge("d", "t", weight=1, capacity=3)

+    return G

+

+

+def get_flowcost_from_flowdict(G, flowDict):

+    """Returns flow cost calculated from flow dictionary"""

+    flowCost = 0

+    for u in flowDict:

+        for v in flowDict[u]:

+            flowCost += flowDict[u][v] * G[u][v]["weight"]

+    return flowCost

+

+

+def test_infinite_demand_raise(simple_flow_graph):

+    G = simple_flow_graph

+    inf = float("inf")

+    nx.set_node_attributes(G, {"a": {"demand": inf}})

+    pytest.raises(nx.NetworkXError, nx.network_simplex, G)

+

+

+def test_neg_infinite_demand_raise(simple_flow_graph):

+    G = simple_flow_graph

+    inf = float("inf")

+    nx.set_node_attributes(G, {"a": {"demand": -inf}})

+    pytest.raises(nx.NetworkXError, nx.network_simplex, G)

+

+

+def test_infinite_weight_raise(simple_flow_graph):

+    G = simple_flow_graph

+    inf = float("inf")

+    nx.set_edge_attributes(

+        G, {("a", "b"): {"weight": inf}, ("b", "d"): {"weight": inf}}

+    )

+    pytest.raises(nx.NetworkXError, nx.network_simplex, G)

+

+

+def test_nonzero_net_demand_raise(simple_flow_graph):

+    G = simple_flow_graph

+    nx.set_node_attributes(G, {"b": {"demand": -4}})

+    pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)

+

+

+def test_negative_capacity_raise(simple_flow_graph):

+    G = simple_flow_graph

+    nx.set_edge_attributes(G, {("a", "b"): {"weight": 1}, ("b", "d"): {"capacity": -9}})

+    pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)

+

+

+def test_no_flow_satisfying_demands(simple_no_flow_graph):

+    G = simple_no_flow_graph

+    pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)

+

+

+def test_sum_demands_not_zero(simple_no_flow_graph):

+    G = simple_no_flow_graph

+    nx.set_node_attributes(G, {"t": {"demand": 4}})

+    pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)

+

+

+def test_google_or_tools_example():

+    """

+    https://developers.google.com/optimization/flow/mincostflow

+    """

+    G = nx.DiGraph()

+    start_nodes = [0, 0, 1, 1, 1, 2, 2, 3, 4]

+    end_nodes = [1, 2, 2, 3, 4, 3, 4, 4, 2]

+    capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5]

+    unit_costs = [4, 4, 2, 2, 6, 1, 3, 2, 3]

+    supplies = [20, 0, 0, -5, -15]

+    answer = 150

+

+    for i in range(len(supplies)):

+        G.add_node(i, demand=(-1) * supplies[i])  # supplies are negative of demand

+

+    for i in range(len(start_nodes)):

+        G.add_edge(

+            start_nodes[i], end_nodes[i], weight=unit_costs[i], capacity=capacities[i]

+        )

+

+    flowCost, flowDict = nx.network_simplex(G)

+    assert flowCost == answer

+    assert flowCost == get_flowcost_from_flowdict(G, flowDict)

+

+

+def test_google_or_tools_example2():

+    """

+    https://developers.google.com/optimization/flow/mincostflow

+    """

+    G = nx.DiGraph()

+    start_nodes = [0, 0, 1, 1, 1, 2, 2, 3, 4, 3]

+    end_nodes = [1, 2, 2, 3, 4, 3, 4, 4, 2, 5]

+    capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5, 10]

+    unit_costs = [4, 4, 2, 2, 6, 1, 3, 2, 3, 4]

+    supplies = [23, 0, 0, -5, -15, -3]

+    answer = 183

+

+    for i in range(len(supplies)):

+        G.add_node(i, demand=(-1) * supplies[i])  # supplies are negative of demand

+

+    for i in range(len(start_nodes)):

+        G.add_edge(

+            start_nodes[i], end_nodes[i], weight=unit_costs[i], capacity=capacities[i]

+        )

+

+    flowCost, flowDict = nx.network_simplex(G)

+    assert flowCost == answer

+    assert flowCost == get_flowcost_from_flowdict(G, flowDict)

+

+

+def test_large():

+    fname = (

+        importlib.resources.files("networkx.algorithms.flow.tests")

+        / "netgen-2.gpickle.bz2"

+    )

+

+    with bz2.BZ2File(fname, "rb") as f:

+        G = pickle.load(f)

+    flowCost, flowDict = nx.network_simplex(G)

+    assert 6749969302 == flowCost

+    assert 6749969302 == nx.cost_of_flow(G, flowDict)

+

+

+def test_simple_digraph():

+    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, H = nx.network_simplex(G)

+    soln = {"a": {"b": 4, "c": 1}, "b": {"d": 4}, "c": {"d": 1}, "d": {}}

+    assert flowCost == 24

+    assert nx.min_cost_flow_cost(G) == 24

+    assert H == soln

+

+

+def test_negcycle_infcap():

+    G = nx.DiGraph()

+    G.add_node("s", demand=-5)

+    G.add_node("t", demand=5)

+    G.add_edge("s", "a", weight=1, capacity=3)

+    G.add_edge("a", "b", weight=3)

+    G.add_edge("c", "a", weight=-6)

+    G.add_edge("b", "d", weight=1)

+    G.add_edge("d", "c", weight=-2)

+    G.add_edge("d", "t", weight=1, capacity=3)

+    pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)

+

+

+def test_transshipment():

+    G = nx.DiGraph()

+    G.add_node("a", demand=1)

+    G.add_node("b", demand=-2)

+    G.add_node("c", demand=-2)

+    G.add_node("d", demand=3)

+    G.add_node("e", demand=-4)

+    G.add_node("f", demand=-4)

+    G.add_node("g", demand=3)

+    G.add_node("h", demand=2)

+    G.add_node("r", demand=3)

+    G.add_edge("a", "c", weight=3)

+    G.add_edge("r", "a", weight=2)

+    G.add_edge("b", "a", weight=9)

+    G.add_edge("r", "c", weight=0)

+    G.add_edge("b", "r", weight=-6)

+    G.add_edge("c", "d", weight=5)

+    G.add_edge("e", "r", weight=4)

+    G.add_edge("e", "f", weight=3)

+    G.add_edge("h", "b", weight=4)

+    G.add_edge("f", "d", weight=7)

+    G.add_edge("f", "h", weight=12)

+    G.add_edge("g", "d", weight=12)

+    G.add_edge("f", "g", weight=-1)

+    G.add_edge("h", "g", weight=-10)

+    flowCost, H = nx.network_simplex(G)

+    soln = {

+        "a": {"c": 0},

+        "b": {"a": 0, "r": 2},

+        "c": {"d": 3},

+        "d": {},

+        "e": {"r": 3, "f": 1},

+        "f": {"d": 0, "g": 3, "h": 2},

+        "g": {"d": 0},

+        "h": {"b": 0, "g": 0},

+        "r": {"a": 1, "c": 1},

+    }

+    assert flowCost == 41

+    assert H == soln

+

+

+def test_digraph1():

+    # From Bradley, S. P., Hax, A. C. and Magnanti, T. L. Applied

+    # Mathematical Programming. Addison-Wesley, 1977.

+    G = nx.DiGraph()

+    G.add_node(1, demand=-20)

+    G.add_node(4, demand=5)

+    G.add_node(5, demand=15)

+    G.add_edges_from(

+        [

+            (1, 2, {"capacity": 15, "weight": 4}),

+            (1, 3, {"capacity": 8, "weight": 4}),

+            (2, 3, {"weight": 2}),

+            (2, 4, {"capacity": 4, "weight": 2}),

+            (2, 5, {"capacity": 10, "weight": 6}),

+            (3, 4, {"capacity": 15, "weight": 1}),

+            (3, 5, {"capacity": 5, "weight": 3}),

+            (4, 5, {"weight": 2}),

+            (5, 3, {"capacity": 4, "weight": 1}),

+        ]

+    )

+    flowCost, H = nx.network_simplex(G)

+    soln = {

+        1: {2: 12, 3: 8},

+        2: {3: 8, 4: 4, 5: 0},

+        3: {4: 11, 5: 5},

+        4: {5: 10},

+        5: {3: 0},

+    }

+    assert flowCost == 150

+    assert nx.min_cost_flow_cost(G) == 150

+    assert H == soln

+

+

+def test_zero_capacity_edges():

+    """Address issue raised in ticket #617 by arv."""

+    G = nx.DiGraph()

+    G.add_edges_from(

+        [

+            (1, 2, {"capacity": 1, "weight": 1}),

+            (1, 5, {"capacity": 1, "weight": 1}),

+            (2, 3, {"capacity": 0, "weight": 1}),

+            (2, 5, {"capacity": 1, "weight": 1}),

+            (5, 3, {"capacity": 2, "weight": 1}),

+            (5, 4, {"capacity": 0, "weight": 1}),

+            (3, 4, {"capacity": 2, "weight": 1}),

+        ]

+    )

+    G.nodes[1]["demand"] = -1

+    G.nodes[2]["demand"] = -1

+    G.nodes[4]["demand"] = 2

+

+    flowCost, H = nx.network_simplex(G)

+    soln = {1: {2: 0, 5: 1}, 2: {3: 0, 5: 1}, 3: {4: 2}, 4: {}, 5: {3: 2, 4: 0}}

+    assert flowCost == 6

+    assert nx.min_cost_flow_cost(G) == 6

+    assert H == soln

+

+

+def test_digon():

+    """Check if digons are handled properly. Taken from ticket

+    #618 by arv."""

+    nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})]

+    edges = [

+        (1, 2, {"capacity": 3, "weight": 600000}),

+        (2, 1, {"capacity": 2, "weight": 0}),

+        (2, 3, {"capacity": 5, "weight": 714285}),

+        (3, 2, {"capacity": 2, "weight": 0}),

+    ]

+    G = nx.DiGraph(edges)

+    G.add_nodes_from(nodes)

+    flowCost, H = nx.network_simplex(G)

+    soln = {1: {2: 0}, 2: {1: 0, 3: 4}, 3: {2: 0}}

+    assert flowCost == 2857140

+

+

+def test_deadend():

+    """Check if one-node cycles are handled properly. Taken from ticket

+    #2906 from @sshraven."""

+    G = nx.DiGraph()

+

+    G.add_nodes_from(range(5), demand=0)

+    G.nodes[4]["demand"] = -13

+    G.nodes[3]["demand"] = 13

+

+    G.add_edges_from([(0, 2), (0, 3), (2, 1)], capacity=20, weight=0.1)

+    pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G)

+

+

+def test_infinite_capacity_neg_digon():

+    """An infinite capacity negative cost digon results in an unbounded

+    instance."""

+    nodes = [(1, {}), (2, {"demand": -4}), (3, {"demand": 4})]

+    edges = [

+        (1, 2, {"weight": -600}),

+        (2, 1, {"weight": 0}),

+        (2, 3, {"capacity": 5, "weight": 714285}),

+        (3, 2, {"capacity": 2, "weight": 0}),

+    ]

+    G = nx.DiGraph(edges)

+    G.add_nodes_from(nodes)

+    pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G)

+

+

+def test_multidigraph():

+    """Multidigraphs are acceptable."""

+    G = nx.MultiDiGraph()

+    G.add_weighted_edges_from([(1, 2, 1), (2, 3, 2)], weight="capacity")

+    flowCost, H = nx.network_simplex(G)

+    assert flowCost == 0

+    assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}}

+

+

+def test_negative_selfloops():

+    """Negative selfloops should cause an exception if uncapacitated and

+    always be saturated otherwise.

+    """

+    G = nx.DiGraph()

+    G.add_edge(1, 1, weight=-1)

+    pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G)

+

+    G[1][1]["capacity"] = 2

+    flowCost, H = nx.network_simplex(G)

+    assert flowCost == -2

+    assert H == {1: {1: 2}}

+

+    G = nx.MultiDiGraph()

+    G.add_edge(1, 1, "x", weight=-1)

+    G.add_edge(1, 1, "y", weight=1)

+    pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G)

+

+    G[1][1]["x"]["capacity"] = 2

+    flowCost, H = nx.network_simplex(G)

+    assert flowCost == -2

+    assert H == {1: {1: {"x": 2, "y": 0}}}

+

+

+def test_bone_shaped():

+    # From #1283

+    G = nx.DiGraph()

+    G.add_node(0, demand=-4)

+    G.add_node(1, demand=2)

+    G.add_node(2, demand=2)

+    G.add_node(3, demand=4)

+    G.add_node(4, demand=-2)

+    G.add_node(5, demand=-2)

+    G.add_edge(0, 1, capacity=4)

+    G.add_edge(0, 2, capacity=4)

+    G.add_edge(4, 3, capacity=4)

+    G.add_edge(5, 3, capacity=4)

+    G.add_edge(0, 3, capacity=0)

+    flowCost, H = nx.network_simplex(G)

+    assert flowCost == 0

+    assert H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}}

+

+

+def test_graphs_type_exceptions():

+    G = nx.Graph()

+    pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G)

+    G = nx.MultiGraph()

+    pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G)

+    G = nx.DiGraph()

+    pytest.raises(nx.NetworkXError, nx.network_simplex, G)

diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2
new file mode 100644
index 00000000..8ce935a8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2
Binary files differ