# Ticket #8403: trac_8403.patch

File trac_8403.patch, 6.2 KB (added by ncohen, 11 years ago)
• ## sage/graphs/generic_graph.py

```# HG changeset patch
# User Nathann Cohen <nathann.cohen@gmail.com>
# Date 1267379885 -3600
# Node ID 1a774059334288a72aaf5e897fb146eb56e41016
# Parent  556bb66e4c6dbb92a4ee37c1750d82a5c6298eeb
trac 8403 : Graph.steiner_tree

diff -r 556bb66e4c6d -r 1a7740593342 sage/graphs/generic_graph.py```
 a v = pv return B, C def steiner_tree(self,vertices, weighted = False): r""" Returns a tree of minimum weight connecting the given set of vertices. Definition : Computing a minimum spanning tree in a graph can be done in `n \log(n)` time (and in linear time if all weights are equal). On the other hand, if one is given a large (possibly weighted) graph and a subset of its vertices, it is NP-Hard to find a tree of minimum weight connecting the given set of vertices, which is then called a Steiner Tree. `Wikipedia article on Steiner Trees `_. INPUT: - ``vertices`` -- the vertices to be connected by the Steiner Tree. - ``weighted`` (boolean) -- Whether to consider the graph as weighted, and use each edge's label as a weight, considering ``None`` as a weight of `1`. If ``weighted=False`` (default) all edges are considered to have a weight of `1`. .. NOTE:: * This problem being defined on undirected graphs, the orientation is not considered if the current graph is actually a digraph. * The graph is assumed not to have multiple edges. ALGORITHM: Solved through Linear Programming. COMPLEXITY: NP-Hard. Note that this algorithm first checks whether the given set of vertices induces a connected graph, returning one of its spanning trees if ``weighted`` is set to ``False``, and thus answering very quickly in some cases EXAMPLES: The Steiner Tree of the first 5 vertices in a random graph is, of course, always a tree :: sage: g = graphs.RandomGNP(30,.5) sage: st = g.steiner_tree(g.vertices()[:5])              # optional - requires GLPK, CBC or CPLEX sage: st.is_tree()                                       # optional - requires GLPK, CBC or CPLEX True And all the 5 vertices are contained in this tree :: sage: all([v in st for v in g.vertices()[:5] ])          # optional - requires GLPK, CBC or CPLEX True An exception is raised when the problem is impossible, i.e. if the given vertices are not all included in the same connected component :: sage: g = 2 * graphs.PetersenGraph() sage: st = g.steiner_tree([5,15]) Traceback (most recent call last): ... ValueError: The given vertices do not all belong to the same connected component. This problem has no solution ! """ if self.is_directed(): g = Graph(self) else: g = self if g.has_multiple_edges(): raise ValueError("The graph is expected not to have multiple edges.") # Can the problem be solved ? Are all the vertices in the same # connected component ? cc = g.connected_component_containing_vertex(vertices[0]) if not all([v in cc for v in vertices]): raise ValueError("The given vertices do not all belong to the same connected component. This problem has no solution !") # Can it be solved using the min spanning tree algorithm ? if not weighted: gg = g.subgraph(vertices) if gg.is_connected(): st = g.subgraph(edges = gg.min_spanning_tree()) st.delete_vertices([v for v in g if st.degree(v) == 0]) return st # Then, LP formulation from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization = False) # Reorder an edge R = lambda (x,y) : (x,y) if x