Ticket #14434: trac_14434.patch

File trac_14434.patch, 7.5 KB (added by ncohen, 6 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 b  
    8585    :delim: |
    8686
    8787    :meth:`~DiGraph.feedback_edge_set` | Computes the minimum feedback edge (arc) set of a digraph
    88     :meth:`~DiGraph.feedback_vertex_set` | Computes the minimum feedback vertex set of a digraph.
    89 
    9088
    9189Methods
    9290-------
  • sage/graphs/generic_graph.py

    diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
    a b  
    280280
    281281    :meth:`~GenericGraph.steiner_tree` | Returns a tree of minimum weight connecting the given set of vertices.
    282282    :meth:`~GenericGraph.edge_disjoint_spanning_trees` | Returns the desired number of edge-disjoint spanning trees/arborescences.
     283    :meth:`~GenericGraph.feedback_vertex_set` | Computes the minimum feedback vertex set of a (di)graph.
    283284    :meth:`~GenericGraph.multiway_cut` | Returns a minimum edge multiway cut
    284285    :meth:`~GenericGraph.max_cut` | Returns a maximum edge cut of the graph.
    285286    :meth:`~GenericGraph.longest_path` | Returns a longest path of ``self``.
     
    60456046
    60466047    def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constraint_generation = True):
    60476048        r"""
    6048         Computes the minimum feedback vertex set of a digraph.
    6049 
    6050         The minimum feedback vertex set of a digraph is a set of vertices
    6051         that intersect all the circuits of the digraph.
    6052         Equivalently, a minimum feedback vertex set of a DiGraph is a set
    6053         `S` of vertices such that the digraph `G-S` is acyclic. For more
    6054         information, see the
    6055         `Wikipedia article on feedback vertex sets
    6056         <http://en.wikipedia.org/wiki/Feedback_vertex_set>`_.
     6049        Computes the minimum feedback vertex set of a (di)graph.
     6050
     6051        The minimum feedback vertex set of a (di)graph is a set of vertices that
     6052        intersect all of its cycles.  Equivalently, a minimum feedback vertex
     6053        set of a (di)graph is a set `S` of vertices such that the digraph `G-S`
     6054        is acyclic. For more information, see the `Wikipedia article on feedback
     6055        vertex sets <http://en.wikipedia.org/wiki/Feedback_vertex_set>`_.
    60576056
    60586057        INPUT:
    60596058
     
    60806079          generation when solving the Mixed Integer Linear Program (default:
    60816080          ``True``).
    60826081
    6083         ALGORITHM:
    6084 
    6085         This problem is solved using Linear Programming, which certainly is not
    6086         the best way and will have to be replaced by a better algorithm.  The
    6087         program to be solved is the following:
     6082        ALGORITHMS:
     6083
     6084        (Constraints generation)
     6085
     6086        When the parameter ``constraint_generation`` is enabled (default) the
     6087        following MILP formulation is used to solve the problem::
     6088
     6089        .. MATH::
     6090
     6091            \mbox{Minimize : }&\sum_{v\in G} b_{v}\\
     6092            \mbox{Such that : }&\\
     6093            &\forall C\text{ circuits }\subseteq G, \sum_{v\in C}b_{v}\geq 1\\
     6094
     6095        As the number of circuits contained in a graph is exponential, this LP
     6096        is solved through constraint generation. This means that the solver is
     6097        sequentially asked to solved the problem, knowing only a portion of the
     6098        circuits contained in `G`, each time adding to the list of its
     6099        constraints the circuit which its last answer had left intact.
     6100
     6101        (Another formulation based on an ordering of the vertices)
     6102
     6103        When the graph is directed, a second (and very slow) formulation is
     6104        available, which should only be used to check the result of the first
     6105        implementation in case of doubt.
    60886106
    60896107        .. MATH::
    60906108
     
    61046122        The number of vertices removed is then minimized, which is the
    61056123        objective.
    61066124
    6107         (Constraint Generation)
    6108 
    6109         If the parameter ``constraint_generation`` is enabled, a more efficient
    6110         formulation is used :
    6111 
    6112         .. MATH::
    6113 
    6114             \mbox{Minimize : }&\sum_{v\in G} b_{v}\\
    6115             \mbox{Such that : }&\\
    6116             &\forall C\text{ circuits }\subseteq G, \sum_{v\in C}b_{v}\geq 1\\
    6117 
    6118         As the number of circuits contained in a graph is exponential, this LP
    6119         is solved through constraint generation. This means that the solver is
    6120         sequentially asked to solved the problem, knowing only a portion of the
    6121         circuits contained in `G`, each time adding to the list of its
    6122         constraints the circuit which its last answer had left intact.
    6123 
    61246125        EXAMPLES:
    61256126
     6127        The necessary example::
     6128
     6129            sage: g = graphs.PetersenGraph()
     6130            sage: g.feedback_vertex_set()
     6131            [1, 3, 5]
     6132
    61266133        In a digraph built from a graph, any edge is replaced by arcs going in
    61276134        the two opposite directions, thus creating a cycle of length two.
    61286135        Hence, to remove all the cycles from the graph, each edge must see one
     
    61566163            ...            constraint_generation = False)
    61576164            sage: x == y
    61586165            True
     6166
     6167         Bad algorithm::
     6168
     6169            sage: g = graphs.PetersenGraph()
     6170            sage: g.feedback_vertex_set(constraint_generation = False)
     6171            Traceback (most recent call last):
     6172            ...
     6173            ValueError: The only implementation available for undirected graphs is with constraint_generation set to True.
    61596174         """
    6160 
    6161         # It would be a pity to start a LP if the digraph is already acyclic
    6162         if self.is_directed_acyclic():
     6175        if not constraint_generation and not self.is_directed():
     6176            raise ValueError("The only implementation available for "+
     6177                             "undirected graphs is with constraint_generation "
     6178                             "set to True.")
     6179
     6180        # It would be a pity to start a LP if the graph is already acyclic
     6181        if ((not self.is_directed() and self.is_forest()) or
     6182            (    self.is_directed() and self.is_directed_acyclic())):
    61636183            if value_only:
    61646184                return 0
    61656185            return []
     
    61856205
    61866206            # For as long as we do not break because the digraph is
    61876207            # acyclic....
    6188             while (1):
     6208            while True:
    61896209
    61906210                # Building the graph without the edges removed by the LP
    61916211                h = self.subgraph(vertices =
    61926212                                  [v for v in self if p.get_values(b[v]) < .5])
    61936213
    6194                 # Is the digraph acyclic ?
    6195                 isok, certificate = h.is_directed_acyclic(certificate = True)
     6214                # Is the graph acyclic ?
     6215                if self.is_directed():
     6216                    isok, certificate = h.is_directed_acyclic(certificate = True)
     6217                else:
     6218                    isok, certificate = h.is_forest(certificate = True)
    61966219
    61976220                # If so, we are done !
    61986221                if isok:
     
    62136236
    62146237            else:
    62156238
    6216                 # listing the edges contained in the MFAS
     6239                # listing the edges contained in the MFVS
    62176240                return [v for v in self if p.get_values(b[v]) > .5]
    62186241
    6219 
    62206242        else:
    62216243
    62226244        ######################################
     
    62636285            &\forall x\in G, b_x\mbox{ is a binary variable}
    62646286
    62656287        INPUT:
    6266    
     6288
    62676289        - ``x`` -- Source vertex
    62686290
    62696291        - ``y`` -- Sink vertex