Ticket #8404: trac_8404.patch

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

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1267382744 -3600
    # Node ID ffcf15176a09ea5e4fd49f067921ad8bb85d6647
    # Parent  ad225fbca74921d05b49b616c18820365bf389af
    trac 8404 : Minors...
    
    diff -r ad225fbca749 -r ffcf15176a09 sage/graphs/graph.py
    a b  
    18971897
    18981898        return repr
    18991899
     1900    def minor(self, H, **kwds):
     1901        r"""
     1902        Returns the vertices of a minor isomorphic to `H` in the current graph.
     1903
     1904        We say that a graph `G` has a `H`-minor (or that it has
     1905        a graph isomorphic to `H` as a minor), if for all `h\in H`,
     1906        there exist disjoint sets `S_h \subseteq V(G)` such that
     1907        once the vertices of each `S_h` have been merged to create
     1908        a new graph `G'`, this new graph contains `H` as a subgraph.
     1909
     1910        For more information of minor theory, see
     1911        http://en.wikipedia.org/wiki/Minor_(graph_theory)
     1912
     1913        INPUT:
     1914
     1915        - ``H`` -- The minor to find for in the current graph
     1916
     1917        - ``**kwds`` -- arguments to be passed down to the ``solve``
     1918          function of ``MixedIntegerLinearProgram``. See the documentation
     1919          of ``MixedIntegerLinearProgram.solve`` for more informations.
     1920
     1921        OUTPUT:
     1922
     1923        A dictionary associating to each vertex of `H` the set of vertices
     1924        in the current graph representing it.
     1925
     1926        ALGORITHM:
     1927
     1928        Mixed Integer Linear Programming
     1929
     1930        COMPLEXITY:
     1931
     1932        Theoretically, when `H` is fixed, testing for the existence of
     1933        a `H`-minor is polynomial. The known algorithms are highly
     1934        exponential in `H`, though.
     1935
     1936        NOTE:
     1937       
     1938        This function can be expected to be *very* slow, especially
     1939        where the minor does not exist.
     1940
     1941        EXAMPLE:
     1942
     1943        Trying to find a minor isomorphic to `K_4` in
     1944        the `4\times 4` grid ::
     1945       
     1946            sage: g = graphs.GridGraph([4,4])
     1947            sage: h = graphs.CompleteGraph(4)
     1948            sage: L = g.minor(h)                                                 # optional - requires GLPK, CPLEX or CBC
     1949            sage: gg = g.subgraph(flatten(L.values(), max_level = 1))            # optional - requires GLPK, CPLEX or CBC
     1950            sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1]     # optional - requires GLPK, CPLEX or CBC
     1951            sage: gg.is_isomorphic(h)                                            # optional - requires GLPK, CPLEX or CBC
     1952            True
     1953
     1954        We can also try to prove this way that the Petersen graph
     1955        is not planar, as it has a `K_5` minor ::
     1956
     1957            sage: g = graphs.PetersenGraph()
     1958            sage: K5_minor = g.minor(graphs.CompleteGraph(5))                    # optional long - requires GLPK, CPLEX or CBC
     1959
     1960        And even a `K_{3,3}` minor ::
     1961
     1962            sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3))        # optional long - requires GLPK, CPLEX or CBC
     1963           
     1964        (It is much faster to use the linear-time test of
     1965        planarity in this situation, though)
     1966
     1967        As there is no cycle in a tree, looking for a `K_3` minor is useless.
     1968        This function will raise an exception in this case::
     1969
     1970            sage: g = graphs.RandomGNP(20,.5)
     1971            sage: g = g.subgraph(edges = g.min_spanning_tree())
     1972            sage: g.is_tree()
     1973            True
     1974            sage: L = g.minor(graphs.CompleteGraph(3))                           # optional - requires GLPK, CPLEX or CBC
     1975            Traceback (most recent call last):
     1976            ...
     1977            ValueError: This graph has no minor isomorphic to H !
     1978        """
     1979
     1980        from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException
     1981        p = MixedIntegerLinearProgram()
     1982       
     1983        # sorts an edge
     1984        S = lambda (x,y) : (x,y) if x<y else (y,x)
     1985
     1986        # rs = Representative set of a vertex
     1987        # for h in H, v in G is such that rs[h][v] == 1 if and only if v
     1988        # is a representant of h in self
     1989        rs = p.new_variable(dim=2)
     1990
     1991        for v in self:
     1992            p.add_constraint(sum([rs[h][v] for h in H]), max = 1)
     1993
     1994        # We ensure that the set of representatives of a
     1995        # vertex h contains a tree, and thus is connected
     1996
     1997        # edges represents the edges of the tree
     1998        edges = p.new_variable(dim = 2)
     1999
     2000        # there can be a edge for h between two vertices
     2001        # only if those vertices represent h
     2002        for u,v in self.edges(labels=None):
     2003            for h in H:
     2004                p.add_constraint(edges[h][S((u,v))] - rs[h][u], max = 0 )
     2005                p.add_constraint(edges[h][S((u,v))] - rs[h][v], max = 0 )
     2006
     2007        # The number of edges of the tree in h is exactly the cardinal
     2008        # of its representative set minus 1
     2009               
     2010        for h in H:
     2011            p.add_constraint(sum([edges[h][S(e)] for e in self.edges(labels=None)])-sum([rs[h][v] for v in self]), min=-1, max=-1)
     2012
     2013        # a tree  has no cycle
     2014        epsilon = 1/(5*Integer(self.order()))
     2015        r_edges = p.new_variable(dim=2)
     2016
     2017        for h in H:
     2018            for u,v in self.edges(labels=None):
     2019                p.add_constraint(r_edges[h][(u,v)] + r_edges[h][(v,u)] - edges[h][S((u,v))], min = 0)
     2020                                                                   
     2021            for v in self:
     2022                p.add_constraint(sum([r_edges[h][(u,v)] for u in self.neighbors(v)]), max = 1-epsilon)
     2023
     2024        # Once the representative sets are described, we must ensure
     2025        # there are arcs corresponding to those of H between them
     2026        h_edges = p.new_variable(dim=2)
     2027
     2028        for h1, h2 in H.edges(labels=None):
     2029
     2030            for v1, v2 in self.edges(labels=None):
     2031
     2032                p.add_constraint(h_edges[(h1,h2)][S((v1,v2))] - rs[h2][v2], max = 0)
     2033                p.add_constraint(h_edges[(h1,h2)][S((v1,v2))] - rs[h1][v1], max = 0)
     2034
     2035                p.add_constraint(h_edges[(h2,h1)][S((v1,v2))] - rs[h1][v2], max = 0)
     2036                p.add_constraint(h_edges[(h2,h1)][S((v1,v2))] - rs[h2][v1], max = 0)
     2037
     2038            p.add_constraint(sum([h_edges[(h1,h2)][S(e)] + h_edges[(h2,h1)][S(e)] for e in self.edges(labels=None) ]), min = 1)
     2039
     2040        p.set_binary(rs)
     2041        p.set_binary(edges)
     2042
     2043        p.set_objective(None)
     2044
     2045        try:
     2046            p.solve(**kwds)
     2047        except MIPSolverException:
     2048            raise ValueError("This graph has no minor isomorphic to H !")
     2049
     2050        rs = p.get_values(rs)
     2051
     2052        from sage.sets.set import Set
     2053        rs_dict = {}
     2054        for h in H:
     2055            rs_dict[h] = [v for v in self if rs[h][v]==1]
     2056
     2057        return rs_dict
     2058           
     2059
    19002060    ### Centrality
    19012061
    19022062    def centrality_betweenness(self, normalized=True):