Ticket #6962: trac_6962.patch

File trac_6962.patch, 9.0 KB (added by ncohen, 11 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1253385913 -7200
    # Node ID b2af0a8f0e5b97688407e37af24ed355592c8221
    # Parent  021c67fcbec41f970d52b920b30ab91a28dd5cd8
    Adds the functions :
    * DiGraph.feedback_edge_set
    * DiGraph.feedback_vertex_set
    
    diff -r 021c67fcbec4 -r b2af0a8f0e5b sage/graphs/graph.py
    a b  
    1247112471        """
    1247212472        return sorted(self.out_degree_iterator(), reverse=True)
    1247312473
     12474
     12475    def feedback_edge_set(self,value_only=False):
     12476        r"""
     12477        Computes the minimum feedback edge set of a digraph
     12478        ( also called feedback arc set ).
     12479
     12480        The minimum feedback edge set of a digraph is a set of edges
     12481        that intersect all the circuits of the digraph.
     12482        Equivalently, a minimum feedback arc set of a DiGraph is a set
     12483        `S` of arcs such that the digraph `G-S` is acyclic.
     12484
     12485        For more informations, see
     12486        ( http://en.wikipedia.org/wiki/Feedback_arc_set )
     12487
     12488        INPUT :
     12489
     12490        - ``value_only`` (boolean) --
     12491            - When set to ``True``, only the minimum
     12492              cardinal of a minimum edge set is
     12493              returned.
     12494
     12495            - When set to ``False``, the ``Set`` of edges
     12496              of a minimal edge set is returned.
     12497
     12498        This problem is solved using Linear Programming, which certainly
     12499        is not the best way and will have to be updated. The program solved
     12500        is the following :
     12501
     12502        .. MATH:
     12503            \mbox{Minimize : }&\sum_{(u,v)\in G} b_{(u,v)}\\
     12504            \mbox{Such that : }&\\
     12505            &\forall v\in G, \sum_{i\in [0,\dots,n-1]}x_{v,i}=1\\
     12506            &\forall i\in [0,\dots,n-1], \sum_{v\in G}x_{v,i}=1\\
     12507            &\forall v\in G,\sum_{i\in [0,\dots,n-1]} ix_{v,i}=d_v\\
     12508            &\forall (u,v)\in G, d_u-d_v+nb_{(u,v)}\geq 0\\
     12509                       
     12510        An explanation :
     12511
     12512        An acyclic digraph can be seen as a poset, and every poset has
     12513        a linear extension. This means that in any acyclic digraph
     12514        the vertices can be ordered with a total order `<` in such a way
     12515        that if `(u,v)\in G`, then `u<v`.
     12516
     12517        Thus, this linear program is built in order to assign to each vertex
     12518        `v` an unique number `d_v\in [0,\dots,n-1]` such that if there exists
     12519        an edge `(u,v)\in G` such that `d_v<d_u`, then the edge `(u,v)` is
     12520        removed (`\Rightarrow x_{(u,v)}=1`).
     12521
     12522        The number of edges removed is then minimized, which is
     12523        the objective.
     12524
     12525        EXAMPLE :
     12526
     12527        If the digraph is created from a graph, and hence is symmetric
     12528        ( if `uv` is an edge, then `vu` is an edge too ), then
     12529        obviously the cardinality of its feedback arc set is the number
     12530        of edges in the first graph ::
     12531
     12532            sage: cycle=graphs.CycleGraph(5)
     12533            sage: dcycle=DiGraph(cycle)
     12534            sage: cycle.size()
     12535            5
     12536            sage: dcycle.feedback_edge_set(value_only=True)    # optional - requires GLPK or CBC
     12537            5.0
     12538       
     12539        And in this situation, for any edge `uv` of the first graph, `uv` of `vu`
     12540        is in the returned feedback arc set::
     12541
     12542           sage: g = graphs.RandomGNP(5,.3)
     12543           sage: dg = DiGraph(g)
     12544           sage: feedback = dg.feedback_edge_set()
     12545           sage: (u,v,l) = g.edge_iterator().next()
     12546           sage: (u,v) in feedback or (v,u) in feedback
     12547           True
     12548        """
     12549       
     12550        from sage.numerical.mip import MixedIntegerLinearProgram
     12551       
     12552        p=MixedIntegerLinearProgram(maximization=False)
     12553       
     12554        b=p.new_variable()
     12555        x=p.new_variable(dim=2)
     12556        d=p.new_variable()
     12557        n=self.order()
     12558        N=range(n)
     12559
     12560        # First and second constraints
     12561        [p.add_constraint(sum([x[v][i] for i in N]),min=1,max=1) for v in self]
     12562        [p.add_constraint(sum([x[v][i] for v in self]),min=1,max=1) for i in N]
     12563       
     12564        # Definition of d_v
     12565        [p.add_constraint(sum([i*x[v][i] for i in N])-d[v],max=0,min=0) for v in self]
     12566
     12567        # The removed vertices cover all the back arcs ( third condition )
     12568        [p.add_constraint(d[u]-d[v]+n*(b[(u,v)]),min=0) for (u,v) in self.edges(labels=None)]
     12569
     12570        p.set_binary(b)
     12571        p.set_binary(x)
     12572
     12573        p.set_objective(sum([b[(u,v)] for (u,v) in self.edges(labels=None)]))
     12574
     12575        if value_only:
     12576            return p.solve(objective_only=True)
     12577        else:
     12578            p.solve()
     12579
     12580            b_sol=p.get_values(b)
     12581
     12582            from sage.sets.set import Set
     12583            return Set([(u,v) for (u,v) in self.edges(labels=None) if b_sol[(u,v)]==1])
     12584
     12585    def feedback_vertex_set(self,value_only=False):
     12586        r"""
     12587        Computes the minimum feedback vertex set of a digraph.
     12588
     12589        The minimum feedback vertex set of a digraph is a set of vertices
     12590        that intersect all the circuits of the digraph.
     12591        Equivalently, a minimum feedback vertex set of a DiGraph is a set
     12592        `S` of vertices such that the digraph `G-S` is acyclic.
     12593
     12594        For more informations, see
     12595        ( http://en.wikipedia.org/wiki/Feedback_vertex_set )
     12596
     12597        INPUT :
     12598
     12599        - ``value_only`` (boolean) --
     12600            - When set to ``True``, only the minimum
     12601              cardinal of a minimum vertex set is
     12602              returned.
     12603
     12604            - When set to ``False``, the ``Set`` of vertices
     12605              of a minimal feedback vertex set is returned.
     12606
     12607        This problem is solved using Linear Programming, which certainly
     12608        is not the best way and will have to be replaced by a better algorithm.
     12609        The program solved is the following :
     12610
     12611        .. MATH:
     12612            \mbox{Minimize : }&\sum_{v\in G} b_v\\
     12613            \mbox{Such that : }&\\
     12614            &\forall v\in G, \sum_{i\in [0,\dots,n-1]}x_{v,i}=1\\
     12615            &\forall i\in [0,\dots,n-1], \sum_{v\in G}x_{v,i}=1\\
     12616            &\forall v\in G,\sum_{i\in [0,\dots,n-1]} ix_{v,i}=d_v\\
     12617            &\forall (u,v)\in G, d_u-d_v+nb_u+nb_v\geq 0\\
     12618                       
     12619        A brief explanation :
     12620
     12621        An acyclic digraph can be seen as a poset, and every poset has
     12622        a linear extension. This means that in any acyclic digraph
     12623        the vertices can be ordered with a total order `<` in such a way
     12624        that if `(u,v)\in G`, then `u<v`.
     12625        Thus, this linear program is built in order to assign to each vertex
     12626        `v` an unique number `d_v\in [0,\dots,n-1]` such that if there exists
     12627        an edge `(u,v)\in G` such that `d_v<d_u`, then either `u` is removed
     12628        (`\Rightarrow b_u=1`) or `v` is removed (`\Rightarrow b_v=1`).
     12629        The number of vertices removed is then minimized, which is
     12630        the objective.
     12631
     12632        EXAMPLE:
     12633
     12634        In a digraph built from a graph, any edge is replaced by arcs going
     12635        in the two opposite directions, thus creating a cycle of length two.
     12636        Hence, to remove all the cycles from the graph, each edge must see
     12637        one of its neighbors removed : a feedback vertex set is in this
     12638        situation a vertex cover ::
     12639
     12640            sage: cycle=graphs.CycleGraph(5)
     12641            sage: dcycle=DiGraph(cycle)
     12642            sage: cycle.vertex_cover(value_only=True)         # optional - requires GLPK or CBC
     12643            3
     12644            sage: feedback = dcycle.feedback_vertex_set() # optional - requires GLPK or CBC
     12645            sage: feedback.cardinality()
     12646            3
     12647            sage: (u,v,l) = cycle.edge_iterator().next()
     12648            sage: u in feedback or v in feedback
     12649           
     12650        For a circuit, the minimum feedback arc set is clearly `1` ::
     12651
     12652            sage: circuit = digraphs.Circuit(5)
     12653            sage: circuit.feedback_vertex_set(value_only=True) == 1
     12654            True
     12655        """
     12656       
     12657        from sage.numerical.mip import MixedIntegerLinearProgram
     12658       
     12659        p=MixedIntegerLinearProgram(maximization=False)
     12660       
     12661        b=p.new_variable()
     12662        x=p.new_variable(dim=2)
     12663        d=p.new_variable()
     12664        n=self.order()
     12665        N=range(n)
     12666
     12667        # First and second constraints
     12668        [p.add_constraint(sum([x[v][i] for i in N]),min=1,max=1) for v in self]
     12669        [p.add_constraint(sum([x[v][i] for v in self]),min=1,max=1) for i in N]
     12670       
     12671        # Definition of d_v
     12672        [p.add_constraint(sum([i*x[v][i] for i in N])-d[v],max=0,min=0) for v in self]
     12673
     12674        # The removed vertices cover all the back arcs ( third condition )
     12675        [p.add_constraint(d[u]-d[v]+n*(b[u]+b[v]),min=0) for (u,v) in self.edges(labels=None)]
     12676
     12677        p.set_binary(b)
     12678        p.set_binary(x)
     12679
     12680        p.set_objective(sum([b[v] for v in self]))
     12681
     12682        if value_only:
     12683            return p.solve(objective_only=True)
     12684        else:
     12685            p.solve()
     12686            b_sol=p.get_values(b)
     12687
     12688            from sage.sets.set import Set
     12689            return Set([v for v in self if b_sol[v]==1])
     12690
     12691
    1247412692    ### Construction
    1247512693
    1247612694    def reverse(self):