# Ticket #7592: trac_7592.patch

File trac_7592.patch, 7.3 KB (added by ncohen, 11 years ago)
• ## sage/graphs/graph.py

# HG changeset patch
# User Nathann Cohen <nathann.cohen@gmail.com>
# Date 1260305403 -3600
# Node ID 5792c7088b6f77b89369818f40a471527b1747ff
# Parent  bae8353680492b942e0fe7b58db854055f94e6a0
Graph.flow method

diff -r bae835368049 -r 5792c7088b6f sage/graphs/graph.py
 a -  Anders Jonsson (2009-10-10): Counting of spanning trees and out-trees added. -  Nathann Cohen (2009-09) : Cliquer, Connectivity, Flows and everything that uses Linear Programming and class numerical.MIP Graph Format ------------ v = pv return B, C def flow(self,x,y,value_only=True,integer=False, use_edge_labels=True,vertex_bound=False): r""" Returns a maximum flow in the graph from x to y ( cf. http://en.wikipedia.org/wiki/Max_flow_problem ) represented by an optimal valuation of the edges. As an optimization problem, is can be expressed this way : .. MATH:: \mbox{Maximize : }&\sum_{e\in G.edges()} w_e b_e\\ \mbox{Such that : }&\forall v \in G, \sum_{(u,v)\in G.edges()} b_{(u,v)}\leq 1\\ &\forall x\in G, b_x\mbox{ is a binary variable} INPUT: - x -- Source vertex - y -- Sink vertex - value_only (boolean) - When set to True, only the value of a maximal flow is returned. - When set to False, is returned a pair whose first element is the value of the maximum flow, and whose second value is a flow graph ( a copy of the current graph, such that each edge has the flow using it as a label, the edges without flow being omitted ). - integer (boolean) - When set to True, computes an optimal solution under the constraint that the flow going through an edge has to be an integer - use_edge_labels (boolean) - When set to True, computes a maximun flow where each edge has a capacity defined by its label. ( if an edge has no label, 1 is assumed ) - When set to False, each edge has capacity 1 - vertex_bound (boolean) - When set to True, sets the maximum flow leaving a vertex different from x to 1 ( useful for vertex connectivity parameters ) This parameter is set to False by default. EXAMPLES: Two basic applications of the flow method for the PappusGraph and the ButterflyGraph with parameter 2 :: sage: g=graphs.PappusGraph() sage: g.flow(1,2) # optional - requires Glpk or COIN-OR/CBC 3.0 :: sage: b=digraphs.ButterflyGraph(2) sage: b.flow(('00',1),('00',2)) # optional - requires Glpk or COIN-OR/CBC 1.0 The flow method can be used to compute a matching in a bipartite graph by linking a source s to all the vertices of the first set and linking a sink t to all the vertices of the second set, then computing a maximum s-t flow :: sage: g = graphs.CompleteBipartiteGraph(4,4) sage: g.add_edges([('s',i) for i in range(4)]) sage: g.add_edges([(4+i,'t') for i in range(4)]) sage: [cardinal, flow_graph] = g.flow('s','t',integer=True,value_only=False) # optional - requries GLPK or CBC sage: flow_graph.delete_vertices(['s','t'])                                  # optional - requries GLPK or CBC sage: flow_graph.edges(labels=None)                                          # optional - requries GLPK or CBC [(0, 5), (1, 4), (2, 7), (3, 6)] """ from sage.numerical.mip import MixedIntegerLinearProgram g=self p=MixedIntegerLinearProgram(maximization=True) flow=p.new_variable(dim=2) if use_edge_labels: capacity=lambda x: x if x!=None else 1 else: capacity=lambda x: 1 # maximizes z, which is the flow leaving from x if g.is_directed(): # This function return the balance of flow at X flow_sum=lambda X: sum([flow[X][v] for (u,v) in g.outgoing_edges([X],labels=None)])-sum([flow[u][X] for (u,v) in g.incoming_edges([X],labels=None)]) # Maximizes the flow leaving x p.set_objective(flow_sum(x)) # Elsewhere, the flow is equal to 0- [p.add_constraint(flow_sum(v),min=0,max=0) for v in g if v!=x and v!=y] # Capacity constraints [p.add_constraint(flow[u][v],max=capacity(w)) for (u,v,w) in g.edges()] if vertex_bound: [p.add_constraint(sum([flow[uu][vv] for (uu,vv) in g.outgoing_edges([v],labels=None)]),max=1) for v in g.vertices() if v!=x and v!=y] else: # This function return the balance of flow at X flow_sum=lambda X:sum([flow[X][v]-flow[v][X] for v in g[X]]) # Maximizes the flow leaving x p.set_objective(flow_sum(x)) # Elsewhere, the flow is equal to 0 [p.add_constraint(flow_sum(v),min=0,max=0) for v in g if v!=x and v!=y] # Capacity constraints [p.add_constraint(flow[u][v]+flow[v][u],max=capacity(w)) for (u,v,w) in g.edges()] if vertex_bound: [p.add_constraint([flow[X][v] for X in g[v]],max=1) for v in g if v!=x and v!=y] if integer: p.set_integer(flow) if value_only: return p.solve(objective_only=True) obj=p.solve() flow=p.get_values(flow) flow_graph = g.copy() if g.is_directed(): for (u,v) in g.edges(labels=None): # We do not want to see both edges (u,v) and (v,u) # with a positive flow if g.has_edge(v,u): m=min(flow[u][v],flow[v][u]) flow[u][v]-=m flow[v][u]-=m for (u,v) in g.edge_iterator(labels=None): if flow[u][v]>0: flow_graph.set_edge_label(u,v,flow[u][v]) else: flow_graph.delete_edge(u,v) else: for (u,v) in g.edges(labels=None): m=min(flow[u][v],flow[v][u]) flow[u][v]-=m flow[v][u]-=m # We do not want to see both edges (u,v) and (v,u) # with a positive flow for (u,v) in g.edges(labels=None): if flow[u][v]>0: flow_graph.set_edge_label(u,v,flow[u][v]) elif flow[v][u]>0: flow_graph.set_edge_label(v,u,flow[v][u]) else: flow_graph.delete_edge(v,u) return [obj,flow_graph] ### Vertex handlers def add_vertex(self, name=None):