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) assert_raises(nx.NetworkXUnbounded, nx.network_simplex, G) assert_raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) G[1][1]['capacity'] = 2 flowCost, H = nx.network_simplex(G) assert_equal(flowCost, -2) assert_equal(H, {1: {1: 2}}) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, -2) assert_equal(H, {1: {1: 2}}) G = nx.MultiDiGraph() G.add_edge(1, 1, 'x', weight=-1) G.add_edge(1, 1, 'y', weight=1) assert_raises(nx.NetworkXUnbounded, nx.network_simplex, G) assert_raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) G[1][1]['x']['capacity'] = 2 flowCost, H = nx.network_simplex(G) assert_equal(flowCost, -2) assert_equal(H, {1: {1: {'x': 2, 'y': 0}}}) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, -2) assert_equal(H, {1: {1: {'x': 2, 'y': 0}}})
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_equal(flowCost, 150) assert_equal(nx.min_cost_flow_cost(G), 150) assert_equal(H, soln) assert_equal(nx.min_cost_flow(G), soln) assert_equal(nx.cost_of_flow(G, H), 150) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 150) assert_equal(H, soln) assert_equal(nx.cost_of_flow(G, H), 150)
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_equal(flowCost, 6) assert_equal(nx.min_cost_flow_cost(G), 6) assert_equal(H, soln) assert_equal(nx.min_cost_flow(G), soln) assert_equal(nx.cost_of_flow(G, H), 6) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 6) assert_equal(H, soln) assert_equal(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_equal(flowCost, 2857140) assert_equal(nx.min_cost_flow_cost(G), 2857140) assert_equal(H, soln) assert_equal(nx.min_cost_flow(G), soln) assert_equal(nx.cost_of_flow(G, H), 2857140) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 2857140) assert_equal(H, soln) assert_equal(nx.cost_of_flow(G, H), 2857140)
def run_random_trial(self): G = nx.MultiDiGraph() nodes = range(1, 10) edges = generate_edges(nodes, 50) G.add_edges_from(edges) source = random.choice(G.nodes()) while True: target = random.choice(G.nodes()) if target != source: break amount = random.randint(1, 10) G.node[source]['demand'] = -amount G.node[target]['demand'] = amount cost, flow_dict, exception = None, None, None try: cost, flow_dict = min_cost_flow(G) except nx.NetworkXException as e: exception = e H = unmulti(G) try: cost2, flow_dict2 = nx.network_simplex(H) except nx.NetworkXException as e: self.assertEquals(type(e) != type(exception)) self.assertEquals(cost, None) else: self.assertEquals(cost, cost2) self.assertEquals(exception, None)
def test_large(self): fname = os.path.join(os.path.dirname(__file__), 'netgen-2.gpickle.bz2') G = nx.read_gpickle(fname) flowCost, flowDict = nx.network_simplex(G) assert_equal(6749969302, flowCost) assert_equal(6749969302, nx.cost_of_flow(G, flowDict)) flowCost, flowDict = nx.capacity_scaling(G) assert_equal(6749969302, flowCost) assert_equal(6749969302, nx.cost_of_flow(G, flowDict))
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_equal(flowCost, 0) assert_equal(H, {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}}) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 0) assert_equal(H, {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}})
def processWiki(page, p=None, ignoreConditionalProbabilities=False): if p == None: p = readDict("data/wpairs") pe = readCounts("data/unigram-counts/" + page + ".en.tok.ucounts") pf = readCounts("data/unigram-counts/" + page + ".fr.tok.ucounts") G = nx.DiGraph() # 1 is source (F), 2 is sink (E) # 3 is F-null, 4 is E-null G.add_node(1, {'demand': -1, 'name': '*SOURCE*'}) G.add_node(2, {'demand': 1, 'name': '*SINK*'}) G.add_node(3, {'name': '*F-NULL*'}) G.add_node(4, {'name': '*E-NULL*'}) G.add_edge(1, 3, {'capacity': 1, 'weight': 100000}) G.add_edge(4, 2, {'capacity': 1, 'weight': 100000}) nCnt = 5 fID = {} for f in pf.iterkeys(): fID[f] = nCnt G.add_node(nCnt, {'name': f, 'lang': 'f'}) G.add_edge(1, nCnt, {'capacity': pf[f], 'weight': 1}) G.add_edge(nCnt, 4, {'capacity': 1, 'weight': 100000}) nCnt += 1 eID = {} for e in pe.iterkeys(): eID[e] = nCnt G.add_node(nCnt, {'name': e, 'lang': 'e'}) G.add_edge(nCnt, 2, {'capacity': pe[e], 'weight': 1}) G.add_edge(3, nCnt, {'capacity': 1, 'weight': 100000}) nCnt += 1 for f in pf.iterkeys(): nf = fID[f] if p.has_key(f): for e in p[f].iterkeys(): if eID.has_key(e): ne = eID[e] cap = p[f][e] if ignoreConditionalProbabilities: cap = 1 G.add_edge(nf, ne, {'capacity': cap, 'weight': 1}) flowCost,flowDict = nx.network_simplex(G) return G,flowDict
def match(self, riders, ridees): graph = nx.DiGraph() for rider in riders: graph.add_node(rider.household_id, demand = - rider.capacity) for ridee in ridees: graph.add_node(ridee.household_id, demand = 1) for rider in riders: for ridee in ridees: distance = this._get_distance(rider.location, ridee.location) graph.add_edge(rider.household_id, ridee.household_id, weight = distance, capacity = 1) flowCost, flowDict = nx.network_simplex(graph) return flowDict
def nxMCF(startNodes, endNodes, capacities, costs, supplies): G = nx.DiGraph() for n, s in enumerate(supplies): G.add_node(n, demand=-s) for edgei in range(len(startNodes)): G.add_edge(startNodes[edgei], endNodes[edgei], weight=costs[edgei], capacity=capacities[edgei]) cost, flow = nx.network_simplex(G, demand='demand', capacity='capacity', weight='weight') totalFlow = 0 for k1,v1 in flow.items(): for k2,v2 in v1.items(): totalFlow += v2 return cost, totalFlow
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_equal(flowCost, 41) assert_equal(nx.min_cost_flow_cost(G), 41) assert_equal(H, soln) assert_equal(nx.min_cost_flow(G), soln) assert_equal(nx.cost_of_flow(G, H), 41) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 41) assert_equal(nx.cost_of_flow(G, H), 41) assert_equal(H, soln)
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_equal(flowCost, 24) assert_equal(nx.min_cost_flow_cost(G), 24) assert_equal(H, soln) assert_equal(nx.min_cost_flow(G), soln) assert_equal(nx.cost_of_flow(G, H), 24)
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_equal(flowCost, 0) assert_equal( H, {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}}) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 0) assert_equal( H, {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}})
def network_simplex(play: dict): DG = nx.DiGraph(big_dimat_df(play)) res = nx.network_simplex(DG) return res
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 route(PP, source=None, destination=None, view=False, debug=False): nPaths = len(PP) MainGraph = nx.DiGraph() tmp = [] j = 0 epsilon = 0.0000000001 nodes = dict() all_edges = dict() G = [None] * nPaths for c, ip in zip(COLORS, xrange(nPaths)): Path = PP[ip] G[ip] = nx.DiGraph() k = j for x in Path: nodes[j] = x tmp.append([x, j]) j += 1 G[ip].add_nodes_from(nodes.keys()) the_edges = [(i, i + 1) for i in xrange(k, j - 1)] all_edges[ip] = the_edges G[ip].add_edges_from(the_edges) # Add to Unified Graph MainGraph.add_nodes_from(nodes.keys()) MainGraph.add_edges_from([(i, i + 1) for i in xrange(k, j - 1)]) # Connecting the graph(s) for u in tmp: for v in tmp: if u != v: if u[0] == v[0]: e = (u[1], v[1]) if e in MainGraph.edges(): # TODO add capacity here? if debug: print ' %s already there.' % list(e) else: if debug: print ' Adding %s to graph.' % list(e) MainGraph.add_edge(e[0], e[1]) n = len(MainGraph.nodes()) source_node = LatLngtoNode(source, nodes) destination_node = LatLngtoNode(destination, nodes) # Optimization Graph OG = nx.DiGraph() m = 3 # max capacity TODO randomly? w = 1 for e in MainGraph.edges(): OG.add_edge(e[0], e[1], weight=w, capacity=m) OG.add_node(source_node, demand=-1) OG.add_node(destination_node, demand=1) try: flowCost, flowDict = nx.network_simplex(OG) print 'shortest_path_length? ', flowCost == nx.shortest_path_length( OG, source_node, destination_node, weight='weight') except Exception as e: print('Pick another option (%s)' % e) print("(Keep it, not congested)") return -1 E = [] print 'flowDict : ' for u in flowDict: for v in flowDict[u]: if flowDict[u][v] != 0: print '\t', u, ' -> ', v, ' : ', flowDict[u][v] E.append((u, v)) print("Optimum = %s" % flowCost) for e in E: print e print '----- leaving route() ---------------------------------' return E, flowCost
nz_idx = pd.Series(np.nonzero(C_transfers.values)[0]) for i in range(abs(dif)): C_transfers.iloc[nz_idx[i]] -= direct for i in CG.nodes(): CG.node[i]['load'] = C_loads[i] CG.node[i]['gen'] = C_gen[i] CG.node[i]['trans'] = C_transfers[i] for i in CG.nodes(): CG.node[i]['MW_net'] = CG.node[i]['gen'] - CG.node[i]['load'] - CG.node[i]['trans'] DG = CG.to_directed() NS = nx.network_simplex(DG, demand='MW_net', weight='R', capacity='tot_MW_cap') #### EVERYTHING BELOW DOESN'T WORK!!! for i in G.nodes(): kv_list = [G.adj[i][j]['tot_kv'] for j in G.adj[i].keys() if isinstance(j, int)] kv_max, kv_min = max(kv_list), min(kv_list) G[i]['max_volt'] = kv_max G[i]['min_volt'] = kv_min #### GET GRID VOLTAGES FROM EIA FORM DATA mwkv = pd.DataFrame(np.zeros(len(G.nodes())), index=G.nodes()) for x in ['load', 'gen', 'trans', 'min_volt', 'max_volt']: mwkv_col = pd.DataFrame(np.vstack([tuple([i, G[i][x]]) for i in G.nodes() if x in G[i].keys()])).rename(columns={1 : x}).set_index(0) mwkv = pd.concat([mwkv, mwkv_col], axis=1)
generator = [j] for i in range(7): hdi = energize_hood_neighbor(hdi) if largest_hdi < len(hdi): largest_hdi = len(hdi) best = generator for i in range(7): plt.subplot(331 + i) plt.title(i) nx.draw(g, gpos, node_color=red_coloring(best), alph=0.7) best = energize_hood_neighbor(best) print(best) plt.show() # Calculate a valid network flow. nx.network_simplex(g) plt.close() # Graph with edge width determined by simplex flow flowCost, flowDict = nx.network_simplex(g) G = nx.Graph() widths = [] for u in flowDict: for v in flowDict[u]: if flowDict[u][v] != 0: G.add_edge(u, v) widths.append(flowDict[u][v]) plt.figure(figsize=(10, 5)) gpos = nx.spring_layout(G) nx.draw_networkx_nodes(G, gpos, node_size=700) nx.draw_networkx_edges(G, gpos, width=widths)
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. >>> import networkx as nx >>> 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 optimiseFlows(self, max_iter=500, bKLDivergence=False): iter = 0 eLambda = (self.phi + self.DELTA) * self.lengths if bKLDivergence: NLL1 = self._KDivergence(eLambda, self.mask) else: NLL1 = self._FDivergence(eLambda, self.mask) print(str(iter) + "," + str(NLL1)) for gene, biGraph in self.biGraphs.items(): biGraph.addSourceSinkShunt() while iter < max_iter: #first compute phi gradient in matrix format eLambda = (self.phi + self.DELTA) * self.lengths R = self.X / eLambda if bKLDivergence: gradPhi = -R * self.mask + self.lengths else: gradPhi = (eLambda - self.X) * self.mask * self.lengths if self.bLasso: gradPhi += self.fLambda newPhi = np.copy(self.phi) for gene, biGraph in self.biGraphs.items(): biGraph.updateCosts(gradPhi, self.mapGeneIdx[gene]) residualGraph = ResidualBiGraph.createResidualGraph( biGraph.diGraph) #residualGraph.add_edge('sink+','source+') #residualGraph.add_edge('source+','sink+') #for n1, d in residualGraph.nodes(data=True): # d.pop('demand',None) #attrs = {'source+': {'demand': 0.01*INT_SCALE}, 'sink+': {'demand': -0.01*INT_SCALE}} #nx.set_node_attributes(residualGraph, attrs) flowCost, flowDict = nx.network_simplex(residualGraph) pflow = 0.01 DeltaF = biGraph.deltaF(flowDict, pflow, self.X, eLambda, self.mapGeneIdx[gene], self.lengths, bKLDivergence, self.bLasso, self.fLambda) weight = biGraph.transformFlowCost(flowCost) i = 0 while DeltaF > pflow * weight * BETA and i < 10: pflow *= TAU DeltaF = biGraph.deltaF(flowDict, pflow, self.X, eLambda, self.mapGeneIdx[gene], self.lengths, bKLDivergence, self.bLasso, self.fLambda) i += 1 if pflow > 0. and i < 10: biGraph.updateFlows(flowDict, pflow) biGraph.updatePhi(newPhi, self.mapGeneIdx[gene]) eLambda1 = (newPhi + self.DELTA) * self.lengths if bKLDivergence: NLL1 = self._KDivergence(eLambda1, self.mask) else: NLL1 = self._FDivergence(eLambda1, self.mask) if iter % 1 == 0: print(str(iter) + "," + str(NLL1)) #print(str(iter) + "," + str(NLL3)) self.phi = newPhi iter = iter + 1 for gene, biGraph in self.biGraphs.items(): biGraph.removeSourceSinkShunt()
def decompose(self): """ Calls the network simplex to run the MCF algorithm. Computes the fairlets and fairlet centers. Returns: fairlets (list) fairlet_centers (list) costs (list) """ start_time = time.time() flow_cost, flow_dict = nx.network_simplex(self.G) print("Time taken to compute MCF solution - %.3f seconds." % (time.time() - start_time)) fairlets = {} # Assumes mapping from blue nodes to the red nodes for i in flow_dict.keys(): if 'B' in i and '_' in i: if sum(flow_dict[i].values()) == 1: for j in flow_dict[i].keys(): if flow_dict[i][j] == 1: if j.split('_')[0] not in fairlets: fairlets[j.split('_')[0]] = [i.split('_')[0]] else: fairlets[j.split('_')[0]].append( i.split('_')[0]) fairlets = [([a] + b) for a, b in fairlets.items()] fairlets2 = [] for i in fairlets: curr_fairlet = [] for j in i: if 'R' in j: d = self.reds else: d = self.blues curr_fairlet.append(d[int(j[1:]) - 1]) fairlets2.append(curr_fairlet) fairlets = fairlets2 del fairlets2 # Choosing fairlet centers fairlet_centers = [] fairlet_costs = [] for f in fairlets: cost_list = [ (i, max([distance(self.data[i], self.data[j]) for j in f])) for i in f ] cost_list = sorted(cost_list, key=lambda x: x[1], reverse=False) center, cost = cost_list[0][0], cost_list[0][1] fairlet_centers.append(center) fairlet_costs.append(cost) print("%d fairlets have been identified." % (len(fairlet_centers))) assert len(fairlets) == len(fairlet_centers) assert len(fairlet_centers) == len(fairlet_costs) return fairlets, fairlet_centers, fairlet_costs
import numpy as np
def optimiseFlows(self, max_iter=100, minChange=1.0): iter = 0 lNLL1 = self._devF() print(str(iter) + "," + str(lNLL1)) #self.biGraph.addSourceSinkShunt() deltaF = minChange * 2. while iter < max_iter or deltaF > minChange: #first compute phi gradient in matrix format dNeta = 1. / ((1.0 - self.Eta + self.minDelta) * (self.Eta + self.minDelta)) gradEta = (self.Theta - self.thetaStar) * dNeta newNeta = np.copy(self.Eta) self.biGraph.updateCosts(gradEta, self.mapIdx) residualGraph = ResidualBiGraph.createResidualGraph( self.biGraph.diGraph) flowCost, flowDict = nx.network_simplex(residualGraph) pflow = 0.1 DeltaF = self.biGraph.deltaFF(flowDict, pflow, self.thetaStar, self.Eta, self.Theta, self.mapIdx, self.minDelta) weight = self.biGraph.transformFlowCost(flowCost) i = 0 while DeltaF > pflow * weight * BETA and i < 10: pflow *= TAU DeltaF = self.biGraph.deltaFF(flowDict, pflow, self.thetaStar, self.Eta, self.Theta, self.mapIdx, self.minDelta) i += 1 if pflow > 0. and i < 10: self.biGraph.updateFlows(flowDict, pflow) self.biGraph.updatePhi(newNeta, self.mapIdx) self.Eta = newNeta self._updateTheta() NLL1 = self._devF() deltaF = abs(NLL1 - lNLL1) lNLL1 = NLL1 if iter % 10 == 0: print(str(iter) + "," + str(NLL1) + "," + str(deltaF)) iter = iter + 1
def optimiseFlows(self, alpha=1.): iter = 0 eLambda = (np.dot(self.phi, self.gamma) + self.DELTA) * self.lengths[:, np.newaxis] NLL1 = np.sum(eLambda - self.X * np.log(eLambda)) print(str(iter) + "," + str(NLL1)) while iter < 200: #first compute phi gradient in matrix format eLambda = (np.dot(self.phi, self.gamma) + self.DELTA) * self.lengths[:, np.newaxis] gSum = np.sum(self.gamma, axis=1) R = self.X / eLambda gradPhi = (-np.dot(R, self.gamma.transpose()) + gSum[np.newaxis, :]) * self.lengths[:, np.newaxis] gradPhi += -(alpha - 1.) / (self.phi + self.PRECISION) + ( alpha - 1.) / (1.0 - self.phi + self.PRECISION) newPhi = np.copy(self.phi) for g in range(self.G): self.biGraphs[g].updateCosts(gradPhi[:, g], self.mapIdx) residualGraph = ResidualBiGraph.createResidualGraph( self.biGraphs[g].diGraph) flowCost, flowDict = nx.network_simplex(residualGraph) pflow = 0.1 DeltaF = self.biGraphs[g].deltaF(flowDict, pflow, self.X, eLambda, self.mapIdx, self.lengths, g, self.gamma) weight = flowCost / float(INT_SCALE) i = 0 while DeltaF > pflow * weight * BETA and i < 10: pflow *= TAU DeltaF = self.biGraphs[g].deltaF(flowDict, pflow, self.X, eLambda, self.mapIdx, self.lengths, g, self.gamma) #print(str(i) + "," + str(pflow) + "," + str(DeltaF) + "," + str(pflow*weight*BETA)) i += 1 if pflow > 0. and i < 10: self.biGraphs[g].updateFlows(flowDict, pflow) self.biGraphs[g].updatePhi(newPhi, g, self.mapIdx) eLambda1 = (np.dot(newPhi, self.gamma) + self.DELTA) * self.lengths[:, np.newaxis] NLL1 = np.sum(eLambda1 - self.X * np.log(eLambda1)) print(str(iter) + "," + str(NLL1)) pL = self.phi * self.lengths[:, np.newaxis] pSum = np.sum(pL, axis=0) if self.bARD: pSum += self.lambda_g self.gamma = self.gamma * (np.dot(np.transpose(pL), R) / pSum[:, np.newaxis]) #self.gamma[self.gamma < 0] = 0. eLambda3 = (np.dot(newPhi, self.gamma) + self.DELTA) * self.lengths[:, np.newaxis] NLL3 = np.sum(eLambda3 - self.X * np.log(eLambda3)) if self.bARD: self.alpha_g = self.alphaG + self.S self.beta_g = self.betaG + np.sum(self.gamma, axis=1) self.lambda_g = self.alpha_g / self.beta_g print(str(iter) + "," + str(NLL3)) self.phi = newPhi iter = iter + 1
def test_large(): fname = os.path.join(os.path.dirname(__file__), "netgen-2.gpickle.bz2") G = nx.read_gpickle(fname) flowCost, flowDict = nx.network_simplex(G) assert 6749969302 == flowCost assert 6749969302 == nx.cost_of_flow(G, flowDict)
def printError(n, n2): file_name = '-'.join([n, n2]) file = open('data/output/' + file_name + '.txt', 'w') file.write('Optimal route:' + '\n') file.write('There`s no an optimal route between these stops') file.close() # ======================================= # Main # ======================================= if __name__ == "__main__": file = open('data/inputfile.txt', 'r') for line in file: data = line.split('-') name = data[0] name2 = data[1] time = int(data[2]) graph = MGraph() try: graph.findStartNode(name, time) graph.G.add_node(name2, demand=1) flowCost, flowDict = nx.network_simplex(graph.G) printOptimalRoute(name + ' Start', name2, flowDict, flowCost) except: printError(name, name2)
def rig_component(G, x, y, maxW): """ Compute the RIG metric on a single component. Parameters ---------- G : nx.Graph A connected graph of weighted edges x : pd.Series Vector of nodes and their abundance in sample x within the connected graph G y : pd.Series Vector of nodes and their abundance in sample y within the connected graph G maxW : float The cost of an insertion step Returns ------- float : Distance between sample x and sample y Note ---- If x or y is None, then 1 will be added to the total distance. If they are both None, then the distance will be zero. Also, the weights of the edges must be contained in `'weight'`. """ # Both samples don't contain any metabolites if len(x) == 0 and len(y) == 0: return 0 xtotal = int(max([x.sum(), 1])) ytotal = int(max([y.sum(), 1])) # Convert everything to fractions if x.sum() != 0: x = pd.Series([Fraction(i, xtotal) for i in np.ravel(x.values)], index=x.index) if y.sum() != 0: y = pd.Series([Fraction(i, ytotal) for i in np.ravel(y.values)], index=y.index) if x.equals(y): return 0 # The component being analyzed has only 1 node. # So the networkx simplex algorithm cannot be run # since there are no edges. if len(list(G.nodes())) == 1: return maxW cost = 0 edges = G.edges(data="weight") # If there one of the samples doesn't have any metabolites # on the component, arbituarily pick two metabolites # and append them to the set. This to address the issue of # measuring distance between unshared components. if len(x) == 0 or x.sum() == 0: x = pd.Series({y.index[0]: Fraction(1, 1)}) weight = maxW elif len(y) == 0 or y.sum() == 0: y = pd.Series({x.index[0]: Fraction(1, 1)}) weight = maxW else: weight = 0 _G = copy.deepcopy(G) xarr = pd.Series({n: (x[n] if n in x else 0) for n in G.nodes()}) yarr = pd.Series({n: (y[n] if n in y else 0) for n in G.nodes()}) d = 0 maxxD = max(map(lambda k: k.denominator, x)) maxyD = max(map(lambda k: k.denominator, y)) for node in _G.nodes(): dmd = int((xarr[node] - yarr[node]) * xtotal * ytotal) _G.node[node]["demand"] = dmd d += dmd W, _ = nx.network_simplex(_G.to_directed()) cost += W + weight return cost
def generate_path(G, operations, directory): ''' Generates optimal path/sub_graph using different strategies # Arguments G: networkx graph operations: Graph operations to be performed greedy: Generates path in a greedy way from a networkx graph generated by MultiChannelNet dag_longest: Generates path using networkx dag_longest_path using the architecture weights as cost of each edge https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.dag.dag_longest_path.html beam_search: Generates approximate longest path using beam search by computing a weighted degree of each node https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.traversal.beamsearch.bfs_beam_edges.html flow_with_demand: Generates a subgraph using networkx capacity_scaling with the demand parameter passed earlier https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.flow.capacity_scaling.html#networkx.algorithms.flow.capacity_scaling iterative_cost_search: Runs an iterative cost search using network_simplex from networkx with the demand scaling from 1 to the demand passed with each step being the parameter demand_step https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.flow.network_simplex.html#networkx.algorithms.flow.network_simplex directory: File directory for the output to be stored ''' print('Optimal path: ') if 'greedy' in operations: bottom_up_greedy = gen_greedy_path(G, strategy="bottom_up") top_down_greedy = gen_greedy_path(G, strategy="top_down") print('Greedy: ') print('\tBottom up:') print('\t', bottom_up_greedy) print('\t', top_down_greedy) if 'dag_longest' in operations: dag_optimal_path = nx.algorithms.dag.dag_longest_path(G) print('DAG Longest Path: ') print(dag_optimal_path) if 'beam_search' in operations: # TODO test and save output weighted_degree = dict(list(G.degree(weight='weight'))) beam_edges = nx.algorithms.traversal.beamsearch.bfs_beam_edges( G, 'Source', weighted_degree.get, width=args.beam_width) if 'flow_with_demand' in operations: G.nodes["Source"]['demand'] = -args.flow_demand G.nodes["Linear"]['demand'] = args.flow_demand fl_cost, fl_dict = nx.capacity_scaling(G, demand='demand', weight='capacity', capacity='weight_int') new_g = nx.DiGraph() new_path = new_g.add_edges_from(min_cost_flow_edge) nx.write_pickle(new_path, os.path.join(directory_name, "capacity_scaled.graph")) print('Capacity Scaling: ') print(new_path.edges) elif 'iterative_cost_search' in operations: demand_cost_list = [] for demand in range(1, args.flow_demand, args.demand_step): G.nodes["Source"]['demand'] = -args.flow_demand G.nodes["Linear"]['demand'] = args.flow_demand try: flow_cost, flow_dict = nx.network_simplex( cnn_model.G, weight='capacity', capacity='weight_int') except nx.exception.NetworkXUnfeasible: print('There is no flow satisfying the demand ', demand) continue min_cost_flow_edges = [(u, v) for u in flow_dict for v in flow_dict[u] if flow_dict[u][v] > args.flow_cut] if len(min_cost_flow_edges) != 0: demand_cost_list.append(demand, fl_cost) print('Iterative cost search with demand', args.flow_demand, 'demand_step', args.demand_step, ':') print(demand_cost_list) plt.xlabel('Demand') plt.ylabel('Cost') plt.scatter(*zip(*demand_cost_list)) plt.savefig( os.path.join(directory_name, "iterative_cost_search_graph.png"))
def min_cost_flow(G, demand='demand', capacity='capacity', weight='weight'): r"""Return 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. >>> import networkx as nx >>> 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 flow_fail_sim(G, demand_value, capacity_factor, default_capacity, trigger_edge, g_name, result_file_path, run, adjust_capacities, net_name, set_edge_capacities_by_type, select_supply_demand_at_random, trigger_until_cascading): ### variables for removing nodes and edges remove_nodes_over = False remove_edges_over = True ### variables for testing print_test_outputs = False find_alt_routes = False checking_flow_demand = True ### what to do on failure fail_print_nodes = False fail_print_edges = True ### what to do on completion print_nodes = False print_edges = False ## set result file path if run != None: result_file_path = result_file_path + '\\result_%s_run_%s.txt' % ( g_name, run) else: result_file_path = result_file_path + '\\result_%s.txt' % g_name ### open results file results_file = open(result_file_path, 'w') ### set demand value based on the number of nodes in the network #demand_value = nx.number_of_nodes(G)/2.0 #default_capacity = nx.number_of_nodes(G)/30.0 #default_capacity = nx.number_of_edges(G)/100.0 ### start of model #create containers to store removed edges and nodes graph_edges_removed = [] graph_nodes_removed = [] # add a random capacity value to all nodes and edges #G = maxflow_tools.set_random_capacities(G,3,8,'flow_capacity') if print_test_outputs == True: print '## Creating super nodes if needed' # create super nodes for supply and demand G, supply_nodes, demand_nodes, added_nodes, added_edges = maxflow_tools.topological_changes( G).check_for_demand_supply_nodes() if set_edge_capacities_by_type == True: #set edge capacities based on the network type (given the name) G = func_set_edge_capacities(G, net_name) else: #set flow capacity for edges for edge in G.edges(): G[edge[0]][edge[1]]['flow_capacity'] = default_capacity #print G[edge[0]][edge[1]]['flow_capacity'] for node in G.nodes(): G.node[node]['flow_capacity'] = default_capacity if select_supply_demand_at_random == True: #select a single supply and demand node at random #reseats the roles of all other nodes adn edges as well G = set_single_supply_demand_randomly(G) # convert topology G, supply_nodes, demand_nodes, super_supply_node, super_demand_node = maxflow_tools.topological_changes( G).convert_topo('demand', 'supply', 'intermediate', 'flow_capacity') ''' print '--------------------------------' print 'Supply node(s):', supply_nodes print 'Demand node(s):', demand_nodes print '--------------------------------' ''' #reset flow values to zero G = maxflow_tools.other(G).reset_flow_values() #set demand values # set value of zero for all nodes for nd in G.nodes(): G.node[nd]['demand'] = 0 #set demand values for demand node(s) if super_demand_node != False: G.node[super_demand_node]['demand'] = demand_value else: split_demand_value = demand_value / len(demand_nodes) for nd in demand_nodes: print 'Assigning a demand to node', nd, 'of', split_demand_value G.node[nd]['demand'] = split_demand_value # set demand values for supply node(s) if super_supply_node != False: supply_nd = super_demand_node G.node[super_supply_node]['demand'] = -demand_value else: split_demand_value = demand_value / len(supply_nodes) for nd in supply_nodes: print 'Assinging a demand to node', nd, 'of', -split_demand_value supply_nd = nd G.node[nd]['demand'] = -split_demand_value #set flow capacity for edges #set capacities as equal to the demand in the network for all nodes and egdes #for edge in G.edges(): G[edge[0]][edge[1]]['flow_capacity'] = default_capacity #print 'A supply of %s is available from node %s.' %(G.node[supply_nodes[0]]['demand'],supply_nodes[0]) #print 'A demand of %s must be met for node %s.' %(G.node[demand_nodes[0]]['demand'],demand_nodes[0]) #print 'Running network simplex' # run network simplex try: cost, edge_flows = nx.network_simplex(G, demand='demand', capacity='flow_capacity', weight='weight') except: print 'Probably no flow satisfying all demands' return print 'b' for edge in G.edges(): if int(G[edge[0]][edge[1]]['flow_capacity']) != 4: print 'some edges have wrong capacity' break # assign flow values to network G = maxflow_tools.flow(G).assign_edge_node_flows(edge_flows) #print 'Setting capacities based on flows' if adjust_capacities == True: print '### Adjusting capacities based on flow values' # set capacities based on flow values G = maxflow_tools.other(G).set_capacity_values(supply_nd, capacity_factor, default_capacity, 'flow_capacity') # initiate cascading failure trigger_edges = [] G, trigger_edges, graph_edges_removed = func_trigger_edge( G, trigger_edge, trigger_edges, super_supply_node, super_demand_node, supply_nodes, demand_nodes, added_nodes, results_file) print '## Running cascading failure' terminate = False step_count = 1 trigger_step = 1 graph_nodes_removed.append([]) while terminate == False and step_count < 100 and trigger_step < 100: print '-------------------------------------' print 'Trigger step:', trigger_step print 'Step:', step_count results_file.write('\nCascading failure: step %s' % step_count) try: if print_test_outputs == True: print '### Calculate flows' G, cost, edge_flows, over_edges, demand_supplied, supply_used = func_calculate_edge_flows( G, demand_nodes, supply_nodes, super_supply_node, checking_flow_demand, fail_print_nodes, fail_print_edges) if print_test_outputs == True: print '### Resolved edge flows - (demand supplied: %s, supply_used: %s)' % ( demand_supplied, supply_used) #not 100% sure what this does G = maxflow_tools.other(G).track_flows(super_supply_node, supply_nodes, demand_nodes) # check after the routing of flows that all demands are met G, terminate = func_check_demands_met(G, fail_print_nodes, fail_print_edges, terminate) if terminate == True: break print '### Checking for edges over capacity' # check for edges over capacity edges_over, nodes_over = maxflow_tools.other( G).check_over_capacity(super_supply_node, super_demand_node, supply_nodes, demand_nodes) # this is optional at the moment until sure this is needed - need to check what this is doing if find_alt_routes == True: G = maxflow_tools.find_alternative_route(G) # if there is an edge over capacity, no longer need any trigger edges removed if len(edges_over) > 0: trigger_until_cascading = False else: # identify and remove the next trigger edge G, trigger_edges, trigger_edge = func_trigger_edge( G, trigger_edge, trigger_edges, super_supply_node, super_demand_node, supply_nodes, demand_nodes, added_nodes, results_file) trigger_edge = [] # iterate the trigger step trigger_step += 1 # take one of step count - one added again at end step_count -= 1 # remove any nodes over capacity if set to do so if remove_nodes_over == True and len(nodes_over) > 0: print '### Remove nodes over capacity' for u in nodes_over: print 'Removed node: %s' % u G.remove_node(u) # remove any edges over capacity if set to do so if remove_edges_over == True and len(edges_over) > 0: print '### Remove edges over capacity' # remove edges which are over capacity for u, v in edges_over: print 'Removed edge: (%s,%s)' % (u, v) G.remove_edge(u, v) # record the edges and nodes removed at each time step graph_edges_removed.append( edges_over) # only really interested in this graph_nodes_removed.append(nodes_over) results_file.write('\nEdges removed: %s' % edges_over) results_file.write('\nNodes removed: %s' % nodes_over) # need to look at subgraph methods - this is where it breaParkRun Replacement - icyks at the moment # need to think about creating super demand and supply nodes for subgraphs if print_test_outputs == True: print '### Check subgraphs in network' # need to remove subgraphs which cannot be computed G, demand_nodes = maxflow_tools.flow(G).handle_subgraphs( supply_nodes, demand_nodes, super_supply_node, super_demand_node) if G == None: # no subgraph has both a supply and demand node so run terminated text = 'No graphs with both supply and demand nodes left' terminate = maxflow_tools.other(G).simulation_completed( text, graph_edges_removed, print_edges, print_nodes) write_result_file_simulation_end(results_file, trigger_edges, graph_edges_removed, graph_nodes_removed) if print_test_outputs == True: print '### Check supply still left in network' # if the supply value now at zero, stop simulation demand_sum = sum(d['demand'] for v, d in G.nodes(data=True)) if demand_sum != 0: raise error_classes.DemandError( G, 'Demand across network does not equal zero as it should.', fail_print_nodes, fail_print_edges) # check demand in the network has not reached 0 - if not a super supply node then must add up if super_supply_node != False and terminate == False: if G.node[super_supply_node]['demand'] == 0: text = 'Supply in network is now zero' terminate = maxflow_tools.other(G).simulation_completed( text, graph_edges_removed, print_edges, print_nodes) write_result_file_simulation_end(results_file, trigger_edges, graph_edges_removed, graph_nodes_removed) elif terminate == False: supply_left = 0 for nd in supply_nodes: supply_left += -G.node[nd]['demand'] if supply_left == 0: text = 'Supply in network is now zero' terminate = maxflow_tools.other(G).simulation_completed( text, graph_edges_removed, print_edges, print_nodes) write_result_file_simulation_end(results_file, text, trigger_edges, graph_edges_removed, graph_nodes_removed) except nx.exception.NetworkXUnfeasible: text = 'No routes which allow demand(s) to be met' terminate = maxflow_tools.other(G).simulation_completed( text, graph_edges_removed, print_edges, print_nodes) write_result_file_simulation_end(results_file, text, trigger_edges, graph_edges_removed, graph_nodes_removed) #check if any changes since last step - if not terminate # this should only terminate if trigger untilc ascading is false - some cascading has occured if trigger_until_cascading == False and graph_edges_removed[ step_count] == [] and graph_nodes_removed[ step_count] == [] and terminate == False: text = 'Network has reached an equilibrium' terminate = maxflow_tools.other(G).simulation_completed( text, graph_edges_removed, print_edges, print_nodes) write_result_file_simulation_end(results_file, text, trigger_edges, graph_edges_removed, graph_nodes_removed) #iterate the step counter based on what has happend thus far step_count += 1
def min_cost_flow_cost(G, demand='demand', capacity='capacity', weight='weight'): """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 Examples -------- A simple example of a min cost flow problem. >>> import networkx as nx >>> 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 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_equal(flowCost, 41) assert_equal(nx.min_cost_flow_cost(G), 41) assert_equal(H, soln) assert_equal(nx.min_cost_flow(G), soln) assert_equal(nx.cost_of_flow(G, H), 41) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 41) assert_equal(nx.cost_of_flow(G, H), 41) assert_equal(H, soln)
def min_cost_flow(G, demand = 'demand', capacity = 'capacity', weight = 'weight'): r"""Return 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 Examples -------- A simple example of a min cost flow problem. >>> import networkx as nx >>> 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 mcf_sparse_nx(x, y, psi, capacity=None): points = np.vstack((x, y)).T num_points = points.shape[0] # Delaunay triangularization tri = Delaunay(points) simplex = tri.simplices simplex_neighbors = tri.neighbors num_simplex = simplex.shape[0] if capacity is None: cap_args = dict() else: cap_args = {'capacity': capacity} # get pseudo estimation of gradients and vertex edges psi_diff = W(psi[simplex] - psi[np.roll(simplex, 1, 1)]) edges = np.stack((np.roll(simplex, 1, 1), simplex), axis=2).reshape(-1, 2) # get corresponding simplex's edges orthogonal to original vertex edges simplex_edges = np.stack(( np.broadcast_to(np.arange(num_simplex)[:, None], simplex_neighbors.shape), np.roll(simplex_neighbors, -1, 1)), axis=2 ).reshape(-1, 2) # get demands demands = np.round(-psi_diff.sum(1) * 0.5 / np.pi).astype(np.int) psi_diff = psi_diff.flatten() G = nx.Graph() G.add_nodes_from(zip(range(num_simplex), [{'demand': d} for d in demands])) # set earth node index to -1, and its demand is the negative of the sum of all demands, # so the total demands is zero G.add_node(-1, demand=-demands.sum()) # set the edge weight to 1 whenever one of its nodes has zero demand demands_dummy = np.concatenate((demands, [-demands.sum()])) weights = np.any(demands_dummy[simplex_edges] == 0, 1) G.add_weighted_edges_from(zip(simplex_edges[:, 0], simplex_edges[:, 1], weights), **cap_args) # make graph to directed graph, so we can distinguish positive and negative flow G = G.to_directed() # perform MCF cost, flowdict = nx.network_simplex(G) # construct K matrix with the same shape as the edges K = np.empty(edges.shape[0]) # add the flow to their orthogonal edge for i, (u, v) in enumerate(simplex_edges): K[i] = -flowdict[u][v] + flowdict[v][u] # derive correct gradients psi_diff += K * 2 * np.pi # construct temporary dict that hold all edge gradients from different direction psi_dict = {i: {} for i in range(num_points)} for diff, (u, v) in zip(psi_diff, edges): psi_dict[u][v] = diff # integrate the gradients result = psi.copy() # choose an integration path, here let's use BFS traverse_G = nx.DiGraph(edges.tolist()) for u, v in nx.algorithms.traversal.breadth_first_search.bfs_edges(traverse_G, 0): result[v] = result[u] + psi_dict[u][v] return result
nz_idx = pd.Series(np.nonzero(C_transfers.values)[0]) for i in range(abs(dif)): C_transfers.iloc[nz_idx[i]] -= direct for i in CG.nodes(): CG.node[i]['load'] = C_loads[i] CG.node[i]['gen'] = C_gen[i] CG.node[i]['trans'] = C_transfers[i] for i in CG.nodes(): CG.node[i]['MW_net'] = CG.node[i]['gen'] - CG.node[i]['load'] - CG.node[i][ 'trans'] DG = CG.to_directed() NS = nx.network_simplex(DG, demand='MW_net', weight='R', capacity='tot_MW_cap') #### EVERYTHING BELOW DOESN'T WORK!!! for i in G.nodes(): kv_list = [ G.adj[i][j]['tot_kv'] for j in G.adj[i].keys() if isinstance(j, int) ] kv_max, kv_min = max(kv_list), min(kv_list) G[i]['max_volt'] = kv_max G[i]['min_volt'] = kv_min #### GET GRID VOLTAGES FROM EIA FORM DATA mwkv = pd.DataFrame(np.zeros(len(G.nodes())), index=G.nodes()) for x in ['load', 'gen', 'trans', 'min_volt', 'max_volt']:
def mcf_nx(x: np.ndarray, capacity=None): assert x.ndim == 2, "Input x should be a 2d array!" # construct index for each node N, M = x.shape index = np.arange(N * M).reshape(N, M) if capacity is None: cap_args = dict() else: cap_args = {'capacity': capacity} # get pseudo estimation of gradients along x and y axis psi1 = W(np.diff(x, axis=0)) psi2 = W(np.diff(x, axis=1)) G = nx.Graph() demands = np.round(-(psi1[:, 1:] - psi1[:, :-1] - psi2[1:, :] + psi2[:-1, :]) * 0.5 / np.pi).astype(np.int) # for convenience let's pad the demands so it match the shape of image # this add N + M - 1 dummy nodes with 0 demand demands = np.pad(demands, ((0, 1),) * 2, 'constant', constant_values=0) G.add_nodes_from(zip(index.ravel(), [{'demand': d} for d in demands.ravel()])) # set earth node index to -1, and its demand is the negative of the sum of all demands, # so the total demands is zero G.add_node(-1, demand=-demands.sum()) # edges along x and y axis edges = np.vstack(( np.vstack((index[:, :-1].ravel(), index[:, 1:].ravel())).T, np.vstack((index[:-1].ravel(), index[1:].ravel())).T) ) # set the edge weight to 1 when its left (upper) node demands is equal to zero # I found it achieve very stable result weights = np.concatenate(((demands[:, :-1] == 0).ravel(), (demands[:-1] == 0).ravel())) G.add_weighted_edges_from(zip(edges[:, 0], edges[:, 1], weights), **cap_args) # add the remaining edges that connected to earth node G.add_edges_from(zip([-1] * M, range(M)), **cap_args) G.add_edges_from(zip([-1] * M, range((N - 1) * M, N * M)), **cap_args) G.add_edges_from(zip([-1] * N, range(0, N * M, M)), **cap_args) G.add_edges_from(zip([-1] * N, range(M - 1, N * M, M)), **cap_args) # make graph to directed graph, so we can distinguish positive and negative flow G = G.to_directed() # perform MCF cost, flowdict = nx.network_simplex(G) # construct K matrix with the same shape as the gradients K2 = np.empty((N, M - 1)) K1 = np.empty((N - 1, M)) # add the flow to their orthogonal edge # the sign of the flow depends on those 4 vectors direction (clockwise or counter-clockwise) # when calculating the demands for i in range(N - 1): for j in range(M): if j == 0: K1[i][0] = -flowdict[-1][i * M] + flowdict[i * M][-1] else: K1[i][j] = -flowdict[i * M + j - 1][i * M + j] + flowdict[i * M + j][i * M + j - 1] for i in range(N): for j in range(M - 1): if i == 0: K2[i][j] = flowdict[-1][j] - flowdict[j][-1] else: K2[i][j] = flowdict[(i - 1) * M + j][i * M + j] - flowdict[i * M + j][(i - 1) * M + j] # the boundary node with index = 0 have only one edge to earth node, # so set one of its edge's K to zero K2[0, 0] = 0 # derive correct gradients psi1 += K1 * 2 * np.pi psi2 += K2 * 2 * np.pi # integrate the gradients y = np.full_like(x, x[0, 0]) y[1:, 0] += np.cumsum(psi1[:, 0]) y[:, 1:] = np.cumsum(psi2, axis=1) + y[:, :1] return y
def generalized_assignment_problem(node_demand, node_supply, connection_list, overload_supplies=False, overload_threshold=None, risky=False): """ A solution to the unweighted generalized assignment problem. Uses the network simplex algorithm to get an LP relaxation. A 2-approximation (on supply overloads) is then used to recover a non-fractional assignment. Algorithm based on this theory: https://theory.stanford.edu/~jvondrak/CS369P/lec12.pdf but also deals with unassigned nodes. A heuristic of weighting edges by the supply value is used. Options exist to allocate demands by connecting to overloaded supplies Parameters ---------- node_demand: dict The demand nodes (or jobs). Job i must be entirely assigned to one supply with amount node_demand[i] node_demand[i] assumed to be integer for convergence of network simplex node_supply: dict The supply nodes (or machines). Machine j can have any number of jobs attached with at most node_supply[j] allocated node_supply[i] assumed to be integer for convergence of network simplex connection_list: dict A dictionary that maps the supply nodes that demand i can be assigned to overload_supplies: float, optional A flag indicating whether supply nodes should be overloaded if there exist unassigned jobs overload_threshold: float, optional The amount that we're willing to overload supply nodes not assigned with the (worst case) 2-approximation ratio risky: bool, optional A flag to try removing multiple single or two degree supplies simultaneously. The correct approach is to resolve the LP each time to speed things up. This may create incorrect solutions. However, with the heuristic used this is likely not a problem, since priority assigned to larger supplies (Proof required for that theory though...) """ G = nx.DiGraph() for i in connection_list: for j in connection_list[i]: G.add_edge( i, j, weight=node_supply[j] * -1, capacity=node_demand[i] ) #A heuristic that may help get more integer solutions? for i in node_demand: G.add_node(i, demand=node_demand[i] * -1) for i in node_supply: G.add_node(i, demand=node_supply[i]) original_supply = {i: v for i, v in node_supply.items()} original_demand = {i: v for i, v in node_demand.items()} closest_supply = {} closest_supply_amount = {} assignments = {} #map demands to supplies while len(node_demand) > 0: total_demand = 0 total_supply = 0 max_supply = 0 for i in node_demand: total_demand += node_demand[i] for i in node_supply: total_supply += node_supply[i] if node_supply[i] > max_supply: max_supply = node_supply[i] # Supply slack used if there is too much demand and not enough supply. Represents infeasibility # Demand slack used if there is more supply than demand. This does not constitue infeasibility, but availability in the supply nodes #Add total_demand + total_supply incase all nodes disconnected. #This means supply_slack is feeding all the supply nodes and demand_slack is feeding all the demand nodes if total_supply > total_demand: G.add_node('demand_slack', demand=-1 * (total_demand + total_supply) + total_demand - total_supply) G.add_node('supply_slack', demand=total_demand + total_supply) else: G.add_node('demand_slack', demand=-1 * (total_demand + total_supply)) G.add_node('supply_slack', demand=(total_demand + total_supply) - total_supply + total_demand) G.add_edge('demand_slack', 'supply_slack', weight=-1 * max_supply, capacity=total_demand + total_supply) #might this cause numerical issues? #Costs of all real edges are negative so only assigned if no other options for i in node_supply: G.add_edge('demand_slack', i, weight=10, capacity=node_supply[i]) for j in node_demand: G.add_edge(j, 'supply_slack', weight=10, capacity=node_demand[j]) # Network simplex algorithm used to do the LP relaxation. Should be fast in practice flow_cost, flow_dict = nx.network_simplex(G) demands_to_remove = [] supplies_to_remove = [] remove_supplies = True # Find closest fractional node assignment in case node is unassigned. Only used if overload_supplies flag is set if overload_supplies: for i in node_demand: for j in flow_dict[i]: if j != "supply_slack": if i not in closest_supply_amount or flow_dict[i][ j] > closest_supply_amount[i]: closest_supply[i] = j closest_supply_amount[i] = flow_dict[i][j] # Remove demand node if it's unassigned (i.e. connected to slack supply # Remove demand node and edges if it's fully allocated to a supply node # Remove edge if LP relaxation assigns it to 0 (not included in optimal for i in node_demand: for j in flow_dict[i]: if j == 'supply_slack' and flow_dict[i][j] > 0: remove_supplies = False assignments[i] = 'unassigned' G.remove_node(i) demands_to_remove.append(i) break if flow_dict[i][j] == node_demand[i]: remove_supplies = False assignments[i] = j node_supply[j] = node_supply[j] - node_demand[i] G.node[j]['demand'] = G.node[j]['demand'] - node_demand[i] G.remove_node(i) demands_to_remove.append(i) break if j != 'supply_slack' and flow_dict[i][ j] == 0: #ignore empty edges to slack node remove_supplies = False G.remove_edge(i, j) # Only remove supplies if no edges have been removed already # Remove supply node if it has a degree of one (i.e. it won't be used since it wasn't fully assigned in the LP) # Remove supply node if it has a degree of two and inputs from connected nodes are overloaded if remove_supplies: # Since it's a digraph we need to specify nodes coming into j for the degree 2 case reverse_neighbors = {} for i in node_demand: for j in G.neighbors(i): if j in reverse_neighbors: reverse_neighbors[j].append(i) else: reverse_neighbors[j] = [i] for j in node_supply: if G.degree( j ) <= 2: # Degree needs to be <=1 but we've got a slack node connected to all supplies G.remove_node(j) supplies_to_remove.append(j) if not risky: break elif G.degree( j ) == 3: # Degree needs to be <=2 but we've got a slack node connected to all supplies total_xin = 0 for i in reverse_neighbors[j]: if node_demand[i] != 0: #should always be the case total_xin += flow_dict[i][j] / float( node_demand[i]) if total_xin >= 1: G.remove_node(j) supplies_to_remove.apend(j) if not risky: break # Update supply and demand nodes and prepare for rerun. for i in demands_to_remove: node_demand.pop(i) for i in supplies_to_remove: node_supply.pop(i) G.remove_node('supply_slack') G.remove_node('demand_slack') allocation_amounts = {} for i in original_supply.keys(): allocation_amounts[i] = 0 print("Assigneed Demands:") for i in original_demand.keys(): if assignments[i] == 'unassigned': pass else: allocation_amounts[assignments[i]] += original_demand[i] print(i + "-> " + assignments[i]) print() print("Non-empty supplies:") for i in original_supply.keys(): if original_supply[i] != 0 and allocation_amounts[i] != 0: print(i + " at " + str(allocation_amounts[i]) + " (" + str( round(100 * allocation_amounts[i] / float(original_supply[i]), 3)) + "%)") print() print("Unassigned demands:") overloaded_allocation_amounts = {} for i in original_demand.keys(): # closest_supply will only be non-empty if overload_supplies is True if assignments[i] == 'unassigned' and i in closest_supply: print(i + " not assigned - closest supply is " + closest_supply[i]) if closest_supply[i] not in overloaded_allocation_amounts: if overload_threshold is None or allocation_amounts[ closest_supply[i]] + original_demand[ i] < overload_threshold * original_supply[ closest_supply[i]]: overloaded_allocation_amounts[ closest_supply[i]] = allocation_amounts[ closest_supply[i]] + original_demand[i] assignments[i] = closest_supply[i] else: if overload_threshold is None or overloaded_allocation_amounts[ closest_supply[i]] + original_demand[ i] < overload_threshold * original_supply[ closest_supply[i]]: overloaded_allocation_amounts[ closest_supply[i]] = overloaded_allocation_amounts[ closest_supply[i]] + original_demand[i] assignments[i] = closest_supply[i] # This is used if overload_supplies is False since closest_supply will be empty if assignments[i] == 'unassigned' and i not in closest_supply: print(i + " not assigned") if overload_supplies: print() print( "Supply loading if unassigned demands attached to best candidate within overload threshold {}:" .format(overload_threshold)) for i in overloaded_allocation_amounts: print(i + " at " + str(overloaded_allocation_amounts[i]) + " (" + str( round( 100 * overloaded_allocation_amounts[i] / float(original_supply[i]), 3)) + "%)") return assignments
G.add_node(1, demand=-2) G.add_node(2, demand=-5) # Adiciona nos de demanda G.add_node(3, demand=1) G.add_node(4, demand=3) G.add_node(5, demand=3) # Adiciona os arcos G.add_edge(1, 3, weight=3) G.add_edge(2, 3, weight=7) # ################################### G.add_edge(1, 4, weight=4) G.add_edge(2, 4, weight=2) # ################################### G.add_edge(1, 5, weight=1) G.add_edge(2, 5, weight=5) flowCost, flowDict = nx.network_simplex(G) print flowCost # print flowDict k,w = 0,0 mat = np.zeros([2,3]) cost = np.zeros([2,3]) total = 0 for i in flowDict: #print "i:%d\n"%i w = 0 for j in flowDict[i]: # print flowDict[i][j], mat[k,w] = flowDict[i][j] cost[k,w] = G[i][j]["weight"] w += 1 total += flowDict[i][j]*G[i][j]["weight"]
def distribute(G, requiredBikes, requiredDocks): url_status = 'https://api.bsmsa.eu/ext/api/bsm/gbfs/v2/en/station_status' bikes = pd.DataFrame.from_records(pd.read_json(url_status)['data'] ['stations'], index='station_id') G_Di = nx.DiGraph() G_Di.add_node('TOP') # The green node demand = 0 for st in bikes.itertuples(): idx = st.Index if idx not in index_graph_stations(G): continue stridx = str(idx) # The blue (s), black (g) and red (t) nodes of the graph s_idx, g_idx, t_idx = 's'+stridx, 'g'+stridx, 't'+stridx G_Di.add_node(g_idx) G_Di.add_node(s_idx) G_Di.add_node(t_idx) b, d = st.num_bikes_available, st.num_docks_available req_bikes = max(0, requiredBikes - b) req_docks = max(0, requiredDocks - d) G_Di.add_edge('TOP', s_idx) G_Di.add_edge(t_idx, 'TOP') G_Di.add_edge(s_idx, g_idx) G_Di.add_edge(g_idx, t_idx) if req_bikes > 0: demand += req_bikes G_Di.nodes[t_idx]['demand'] = req_bikes G_Di.edges[s_idx, g_idx]['capacity'] = 0 elif req_docks > 0: demand -= req_docks G_Di.nodes[s_idx]['demand'] = -req_docks G_Di.edges[g_idx, t_idx]['capacity'] = 0 G_Di.nodes['TOP']['demand'] = -demand # Selects the established edges in our graph # and introduces them onto the directed. for edge in G.edges(): node1 = edge[0] node2 = edge[1] id1 = node1.Index id2 = node2.Index dist = G[node1][node2]['weight']*10 G_Di.add_edge('g'+str(id1), 'g'+str(id2), cost=int(1000*dist), weight=dist) G_Di.add_edge('g'+str(id2), 'g'+str(id1), cost=int(1000*dist), weight=dist) err = False try: flowCost, flowDict = nx.network_simplex(G_Di, weight='cost') except nx.NetworkXUnfeasible: err = True return err, 0, 0 # Error = No solution could be found for the parameters given" # The format error has been eliminated, because the graph provided to the # function is directed. if not err: total_cost = 0 initial = True for src in flowDict: if src[0] != 'g': continue idx_src = int(src[1:]) for dst, b in flowDict[src].items(): if dst[0] == 'g' and b > 0: idx_dst = int(dst[1:]) total_cost += G_Di.edges[src, dst]['weight'] # The cost is the distance traveled * num of bikes. cost = (G_Di.edges[src, dst]['weight'] * b, idx_src, idx_dst) if initial: initial = False Biggest_move = cost elif cost[0] > Biggest_move[0]: Biggest_move = cost if total_cost == 0: return err, total_cost, 0 return err, total_cost, Biggest_move
def optimseFlows(self, logger, NLL_F, NLL_D, maxIter): self.initialiseFlows() dF = 0. F = 0. (dF, F) = self.evalDF(NLL_F, NLL_D) rho = 1.0e2 i = 0 ssedges = set(self.sEdges) init_pflow = 0.1 * max(self.X.items(), key=itemgetter(1))[1] logger.info("Performing %d iterations of graph normalisation: ", maxIter) logger.info("Iter, dF, F") ChangeF = 1.0 F = -1. while i < maxIter and abs(ChangeF) > 1.0e-3: self.setWeightsD(NLL_D) path = nx.bellman_ford_path(self.diGraph, 'source+', 'sink+', weight='dweight') weight = self.evalPathWeight(path, 'dweight') epath = [(u, v) for u, v in zip(path, path[1:])] spath = set(epath) & ssedges if i > 10 and i % 5 == 0: (fMax, rMax) = self.setResidualGraph() if fMax > 1.0e-6 and rMax > 1.0e-6: ds = {'sink+': -MAX_REV_FLOW, 'source+': MAX_REV_FLOW} nx.set_node_attributes(self.rGraph, ds, 'demand') (mf, pf) = nx.network_simplex(self.rGraph, demand='demand', capacity='capacity', weight='rweight') fCost = (mf * rMax) / (MAX_INT_FLOW * MAX_REV_FLOW) else: fCost = 1.0e6 else: fCost = 1.0e6 if weight < fCost and weight < 0.: pflow = init_pflow DeltaF = self.deltaF(spath, pflow, NLL_F) while DeltaF > pflow * weight * BETA: pflow *= TAU DeltaF = self.deltaF(spath, pflow, NLL_F) if pflow > 0.: self.addFlowPath(path, pflow) else: if fCost < 0.: epath = [] for k, v in pf.items(): for k2, v2 in v.items(): if int(v2) > 0: epath.append((k2, k)) pflow = fMax * (MAX_REV_FLOW / MAX_INT_FLOW) spath = set(epath) & ssedges DeltaF = self.deltaF(spath, -pflow, NLL_F) while DeltaF > pflow * fCost * BETA: pflow *= TAU DeltaF = self.deltaF(spath, -pflow, NLL_F) #print(str(pflow) + ',' + str(DeltaF)) if pflow > 0.: self.addEdgePath(epath, -pflow) lastF = F (dF, F) = self.evalDF(NLL_F, NLL_D) ChangeF = F - lastF if i % 10 == 0: logger.info("%d, %f, %f", i, dF, F) i += 1
parser = argparse.ArgumentParser( description="Script which shows minimum flow in given graph") parser.add_argument("nodes_file", help="File which contain nodes and their demands") parser.add_argument( "edges_file", help="File which contain edges with their weights and capacities") args = parser.parse_args() #we need directed graph G = nx.DiGraph() #load nodes[0] and their demands[1] with open(args.nodes_file) as nodes: for data in nodes: node_demand = data.split(" ") G.add_node(node_demand[0], demand=int(node_demand[1])) #load edges with their data with open(args.edges_file) as edges: for data in edges: edge_data = data.split(" ") G.add_edge(edge_data[0], edge_data[1], capacity=int(edge_data[2]), weight=int(edge_data[3])) flow_cost, flow_dict = nx.network_simplex(G) print "Flow cost : " + str(flow_cost) for verticle, neighbours in flow_dict.iteritems(): for neighbour, weight in neighbours.iteritems(): print "From: %s to: %s weight: %s" % (verticle, neighbour, weight)
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(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_equal(flowCost, 150) assert_equal(nx.min_cost_flow_cost(G), 150) assert_equal(H, soln) assert_equal(nx.min_cost_flow(G), soln) assert_equal(nx.cost_of_flow(G, H), 150) flowCost, H = nx.capacity_scaling(G) assert_equal(flowCost, 150) assert_equal(H, soln) assert_equal(nx.cost_of_flow(G, H), 150)
def flow(G, rb, rd): url_status = 'https://api.bsmsa.eu/ext/api/bsm/gbfs/v2/en/station_status' bikes = DataFrame.from_records(pd.read_json(url_status) ['data']['stations'], index='station_id') DG = nx.DiGraph() DG.add_node('TOP') # The green node demand = 0 for station in bikes.itertuples(): idx = station.Index if idx not in Nodes_of_graf(G): continue stridx = str(idx) # The blue (s), black (g) and red (t) nodes of the graph s_idx, g_idx, t_idx = 's'+stridx, 'g'+stridx, 't'+stridx DG.add_node(g_idx) DG.add_node(s_idx) DG.add_node(t_idx) b, d = station.num_bikes_available, station.num_docks_available req_bikes = max(0, int(rb) - b) req_docks = max(0, int(rd) - d) DG.add_edge('TOP', s_idx) DG.add_edge(t_idx, 'TOP') DG.add_edge(s_idx, g_idx) DG.add_edge(g_idx, t_idx) if req_bikes > 0: demand += req_bikes DG.nodes[t_idx]['demand'] = req_bikes DG.edges[s_idx, g_idx]['offer'] = 0 elif req_docks > 0: demand -= req_docks DG.nodes[s_idx]['demand'] = -req_docks DG.edges[g_idx, t_idx]['offer'] = 0 DG.nodes['TOP']['demand'] = -demand for edge in G.edges(): first = edge[0] second = edge[1] ID1 = first[0] ID2 = second[0] dist = G[first][second]['weight']*10 DG.add_edge('g'+str(ID1), 'g'+str(ID2), cost=int(1000*dist), weight=dist) DG.add_edge('g'+str(ID2), 'g'+str(ID1), cost=int(1000*dist), weight=dist) # This variable will indicate if a solution can be found err = True try: Fc, Fd = nx.network_simplex(DG, weight='cost') except nx.NetworkXUnfeasible: err = False return err, 0, 0 if err: total = 0 first = True for sd in Fd: if sd[0] != 'g': continue sd_ID = int(sd[1:]) for dst, a in Fd[sd].items(): if dst[0] == 'g' and a > 0: dt_ID = int(dst[1:]) total += DG.edges[sd, dst]['weight'] w_aresta = (DG.edges[sd, dst]['weight'] * a, sd_ID, dt_ID) if first: first = False maxim = w_aresta elif w_aresta[0] > maxim[0]: maxim = w_aresta if total == 0: return err, total, 0 return err, str(int(total)), str(int(maxim[0]))