Search code examples
algorithmnetworkxdirected-graphmax-flowweighted-graph

Maximum flow with min cost that doesn't satisfy all demands


I'm using NetworkX to solve a maximum-flow problem with more than one source and sink. I found a function that works relatively well in NetworkX called max_cost_flow however the issue I'm having is that it requires that the net demand be zero, in other words no sink should get less than it needs, otherwise an error is raised.

What can I use (or how can I modify this algorithm) to allow it to calculate the best possible flow and not necessarily the one satisfies all conditions?

Per kraskevich's suggestion:

import networkx as nx

def convert(graph):

    allNodes = graph.nodes()

    newSource = len(allNodes) + 1
    newSink = len(allNodes) + 2

    graph.add_node(newSource)
    graph.add_node(newSink)


    for currentNode in allNodes:

        demand = graph.node[currentNode]['demand']

        if demand < 0 :
            graph.add_edge(newSource, currentNode, weight=0, capacity=demand)


        if demand > 0:
            graph.add_edge(newSink, currentNode, weight=0, capacity=demand)

    return graph



g = nx.DiGraph()

g.add_node(1, demand = 1)
g.add_node(2, demand = -2)
g.add_node(3, demand = 2)
g.add_node(4, demand = -4)

g.add_edge(1, 2, weight=4, capacity=100)
g.add_edge(1, 4, weight=3, capacity=100)
g.add_edge(3, 2, weight=5, capacity=100)
g.add_edge(3, 4, weight=2, capacity=100)
g.add_edge(3, 1, weight=1)
newGraph = convert(g)
print(nx.max_flow_min_cost(g, newGraph.nodes()[-2],newGraph.nodes()[-1]))

Solution

    1. You can convert a multi-source flow problem to a single-source problem by creating a new source vertex and adding edges with zero cost and the old value of demand from it to all old sources.

    2. You can do the same thing think with all sinks (but the edges should from the old sinks to a new one).

    3. After that, you can use the max_flow_min_cost function to find the maximum flow with the smallest cost (it doesn't require all demands to be satisfied).

    Upd: there're a few bugs in your code. Here's a working example (I have slightly changed the graph so that the flow is non-zero):

    import networkx as nx
    
    def convert(graph):
        allNodes = graph.nodes()
        newSource = len(allNodes) + 1
        newSink = len(allNodes) + 2
    
        graph.add_node(newSource)
        graph.add_node(newSink)
    
        for currentNode in allNodes:
            demand = graph.node[currentNode]['demand']
            # Direction matters
            # It goes FROM the new source and TO the new sink
            if demand < 0:
                graph.add_edge(newSource, currentNode, weight=0, capacity=-demand)
            if demand > 0:
                graph.add_edge(currentNode, newSink, weight=0, capacity=demand)
            # We also need to zero out all demands
            graph.node[currentNode]['demand'] = 0
        return graph
    
    
    
    g = nx.DiGraph()
    
    g.add_node(1, demand = 1)
    g.add_node(2, demand = -2)
    g.add_node(3, demand = 2)
    g.add_node(4, demand = -4)
    
    g.add_edge(1, 2, weight=4, capacity=100)
    g.add_edge(1, 4, weight=3, capacity=100)
    g.add_edge(2, 3, weight=5, capacity=100)
    g.add_edge(4, 3, weight=2, capacity=100)
    g.add_edge(1, 3, weight=1)
    newGraph = convert(g)
    # The order of s and t matters here, too
    print(nx.max_flow_min_cost(g, g.nodes()[-2], g.nodes()[-1]))