# HG changeset patch
# User Nathann Cohen
# 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/sage/graphs/digraph.py
+++ b/sage/graphs/digraph.py
@@ 85,8 +85,6 @@
: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

diff git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
 a/sage/graphs/generic_graph.py
+++ b/sage/graphs/generic_graph.py
@@ 280,6 +280,7 @@
: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 edgedisjoint 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``.
@@ 6045,15 +6046,13 @@
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 `GS` 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 `GS`
+ is acyclic. For more information, see the `Wikipedia article on feedback
+ vertex sets `_.
INPUT:
@@ 6080,11 +6079,30 @@
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::
@@ 6104,25 +6122,14 @@
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
@@ 6156,10 +6163,23 @@
... 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 []
@@ 6185,14 +6205,17 @@
# 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:
@@ 6213,10 +6236,9 @@
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:
######################################
@@ 6263,7 +6285,7 @@
&\forall x\in G, b_x\mbox{ is a binary variable}
INPUT:

+
 ``x``  Source vertex
 ``y``  Sink vertex