# Ticket #14434: trac_14434.patch

File trac_14434.patch, 7.5 KB (added by ncohen, 7 years ago)
• ## sage/graphs/digraph.py

# HG changeset patch
# User Nathann Cohen <nathann.cohen@gmail.com>
# Date 1365590279 -7200
# Node ID 548ba75f6331c3f70d29f95d8ba95fb3b05d2a09
# Parent  28801f75075decdbdf1395376977cdfcdfc59641
implements GenericGraph.feedback_vertex_set for undirected graphs

diff --git a/sage/graphs/digraph.py b/sage/graphs/digraph.py
 a :delim: | :meth:~DiGraph.feedback_edge_set | Computes the minimum feedback edge (arc) set of a digraph :meth:~DiGraph.feedback_vertex_set | Computes the minimum feedback vertex set of a digraph. Methods -------
• ## sage/graphs/generic_graph.py

diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
 a :meth:~GenericGraph.steiner_tree | Returns a tree of minimum weight connecting the given set of vertices. :meth:~GenericGraph.edge_disjoint_spanning_trees | Returns the desired number of edge-disjoint spanning trees/arborescences. :meth:~GenericGraph.feedback_vertex_set | Computes the minimum feedback vertex set of a (di)graph. :meth:~GenericGraph.multiway_cut | Returns a minimum edge multiway cut :meth:~GenericGraph.max_cut | Returns a maximum edge cut of the graph. :meth:~GenericGraph.longest_path | Returns a longest path of self. def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constraint_generation = True): r""" Computes the minimum feedback vertex set of a digraph. The minimum feedback vertex set of a digraph is a set of vertices that intersect all the circuits of the digraph. Equivalently, a minimum feedback vertex set of a DiGraph is a set S of vertices such that the digraph G-S is acyclic. For more information, see the Wikipedia article on feedback vertex sets _. Computes the minimum feedback vertex set of a (di)graph. The minimum feedback vertex set of a (di)graph is a set of vertices that intersect all of its cycles.  Equivalently, a minimum feedback vertex set of a (di)graph is a set S of vertices such that the digraph G-S is acyclic. For more information, see the Wikipedia article on feedback vertex sets _. INPUT: generation when solving the Mixed Integer Linear Program (default: True). ALGORITHM: This problem is solved using Linear Programming, which certainly is not the best way and will have to be replaced by a better algorithm.  The program to be solved is the following: ALGORITHMS: (Constraints generation) When the parameter constraint_generation is enabled (default) the following MILP formulation is used to solve the problem:: .. MATH:: \mbox{Minimize : }&\sum_{v\in G} b_{v}\\ \mbox{Such that : }&\\ &\forall C\text{ circuits }\subseteq G, \sum_{v\in C}b_{v}\geq 1\\ As the number of circuits contained in a graph is exponential, this LP is solved through constraint generation. This means that the solver is sequentially asked to solved the problem, knowing only a portion of the circuits contained in G, each time adding to the list of its constraints the circuit which its last answer had left intact. (Another formulation based on an ordering of the vertices) When the graph is directed, a second (and very slow) formulation is available, which should only be used to check the result of the first implementation in case of doubt. .. MATH:: The number of vertices removed is then minimized, which is the objective. (Constraint Generation) If the parameter constraint_generation is enabled, a more efficient formulation is used : .. MATH:: \mbox{Minimize : }&\sum_{v\in G} b_{v}\\ \mbox{Such that : }&\\ &\forall C\text{ circuits }\subseteq G, \sum_{v\in C}b_{v}\geq 1\\ As the number of circuits contained in a graph is exponential, this LP is solved through constraint generation. This means that the solver is sequentially asked to solved the problem, knowing only a portion of the circuits contained in G, each time adding to the list of its constraints the circuit which its last answer had left intact. EXAMPLES: The necessary example:: sage: g = graphs.PetersenGraph() sage: g.feedback_vertex_set() [1, 3, 5] In a digraph built from a graph, any edge is replaced by arcs going in the two opposite directions, thus creating a cycle of length two. Hence, to remove all the cycles from the graph, each edge must see one ...            constraint_generation = False) sage: x == y True Bad algorithm:: sage: g = graphs.PetersenGraph() sage: g.feedback_vertex_set(constraint_generation = False) Traceback (most recent call last): ... ValueError: The only implementation available for undirected graphs is with constraint_generation set to True. """ # It would be a pity to start a LP if the digraph is already acyclic if self.is_directed_acyclic(): if not constraint_generation and not self.is_directed(): raise ValueError("The only implementation available for "+ "undirected graphs is with constraint_generation " "set to True.") # It would be a pity to start a LP if the graph is already acyclic if ((not self.is_directed() and self.is_forest()) or (    self.is_directed() and self.is_directed_acyclic())): if value_only: return 0 return [] # For as long as we do not break because the digraph is # acyclic.... while (1): while True: # Building the graph without the edges removed by the LP h = self.subgraph(vertices = [v for v in self if p.get_values(b[v]) < .5]) # Is the digraph acyclic ? isok, certificate = h.is_directed_acyclic(certificate = True) # Is the graph acyclic ? if self.is_directed(): isok, certificate = h.is_directed_acyclic(certificate = True) else: isok, certificate = h.is_forest(certificate = True) # If so, we are done ! if isok: else: # listing the edges contained in the MFAS # listing the edges contained in the MFVS return [v for v in self if p.get_values(b[v]) > .5] else: ###################################### &\forall x\in G, b_x\mbox{ is a binary variable} INPUT: - x -- Source vertex - y -- Sink vertex