Ticket #12385: trac_12385-all-simple-paths.patch

File trac_12385-all-simple-paths.patch, 10.4 KB (added by kini, 10 years ago)

apply to $SAGE_ROOT/devel/sage

  • sage/graphs/digraph.py

    # HG changeset patch
    # Date 1327896886 -28800
    # User Keshav Kini <keshav.kini@gmail.com>
    # Parent 75b29dbaa700aa3a5dd4e5619d4742a50404f8a3
    all_simple_paths semantics
    
    diff --git a/sage/graphs/digraph.py b/sage/graphs/digraph.py
    a b  
    16941694        INPUT:
    16951695
    16961696        -  ``vertex`` - the starting vertex of the paths.
    1697         -  ``ending_vertices`` - iterable (default: None) on
    1698            the allowed ending vertices of the paths. If None,
    1699            then all vertices are allowed.
    1700         -  ``simple`` - boolean (default: False). If set to True,
    1701            then only simple paths are considered. A path is simple
    1702            if no vertex occurs twice in it except possibly the first
    1703            and last ones.
    1704         -  ``max_length`` - non negative integer (default: None).
    1705            The maximum length of the enumerated paths. If set to None,
    1706            then all lengths are allowed.
    1707         -  ``trivial`` - boolean (default: False). If set to True,
    1708            then the empty paths are also enumerated.
     1697        -  ``ending_vertices`` - iterable (default: None) on the allowed
     1698           ending vertices of the paths. If None, then all vertices are
     1699           allowed.
     1700        -  ``simple`` - boolean (default: False). If set to True, then
     1701           only simple paths are considered. A path is simple if no
     1702           vertex occurs twice in it except possibly the first and last
     1703           ones.
     1704        -  ``max_length`` - non negative integer (default: None). The
     1705           maximum length of the enumerated paths. If set to None, then
     1706           all lengths are allowed.
     1707        -  ``trivial`` - boolean (default: False). If set to True, then
     1708           the empty paths are also enumerated.
    17091709                             
    17101710        OUTPUT:
    17111711
     
    17321732            ['b', 'c', 'd', 'c', 'd']
    17331733            ['b', 'c', 'd', 'c', 'd', 'c']
    17341734
    1735         One may wish to enumerate simple paths, i.e. paths such that no vertex
    1736         occurs twice in it except possibly the first and last one. The result
    1737         is always finite but may be long to be computed::
     1735        One may wish to enumerate simple paths, i.e. paths such that no
     1736        vertex occurs twice in it except possibly the first and last
     1737        one. The result is always finite but may be long to be
     1738        computed::
    17381739
    17391740            sage: pi = g._all_paths_iterator('a', simple=True)
    17401741            sage: list(pi)
    1741             [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'c']]
     1742            [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
    17421743            sage: pi = g._all_paths_iterator('d', simple=True)
    17431744            sage: list(pi)
    17441745            [['d', 'c'], ['d', 'c', 'd']]
     
    17701771
    17711772            sage: pi = g._all_paths_iterator('a', max_length=3, trivial=True)
    17721773            sage: list(pi)
    1773             [['a'], ['a', 'a'], ['a', 'b'], ['a', 'a', 'a'], ['a', 'a', 'b'], ['a', 'b', 'c'], ['a', 'a', 'a', 'a'], ['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'], ['a', 'b', 'c', 'd']]
     1774            [['a'], ['a', 'a'], ['a', 'b'], ['a', 'a', 'a'], ['a', 'a', 'b'],
     1775             ['a', 'b', 'c'], ['a', 'a', 'a', 'a'], ['a', 'a', 'a', 'b'],
     1776             ['a', 'a', 'b', 'c'], ['a', 'b', 'c', 'd']]
    17741777        """
    17751778        if ending_vertices is None:
    17761779            ending_vertices = self
    1777         # First enumerate the empty path
    1778         if trivial:
    1779             yield [vertex]
    1780         queue = [[vertex]]
    17811780        if max_length is None:
    17821781            from sage.rings.infinity import Infinity
    17831782            max_length = Infinity
     1783        if max_length < 1:
     1784            return
     1785
     1786        # Start with the empty path; we will try all extensions of it
     1787        queue = [[vertex]]
    17841788        while queue:
    1785             path = queue.pop(0)
    1786             if len(path) > 1 and path[-1] in ending_vertices:
    1787                 yield path
    1788             # Makes sure that the current path is not too long
    1789             # and checks that the path is simple
    1790             if len(path) <= max_length and (not simple or path.count(path[-1]) == 1):
     1789            path = queue.pop(0)     # get a path
     1790            cycle = False
     1791            if simple and path.count(path[-1]) > 1:
     1792                # We found a path which has formed a cycle, and simple=True, so
     1793                # we don't want to extend this path, and we don't want to yield
     1794                # it unless it IS a cycle (beginning = end). See trac #12385.
     1795                if path[0] == path[-1]:
     1796                    cycle = True
     1797                else:
     1798                    continue
     1799            if path[-1] in ending_vertices and (trivial or len(path) > 1):
     1800                yield path      # yield good path
     1801
     1802            if cycle:
     1803                # We only yielded this path because it was a cycle; it should
     1804                # not be extended.
     1805                continue
     1806
     1807            # Build next generation of paths, one arc longer
     1808            if len(path) <= max_length:
    17911809                for neighbor in self.neighbor_out_iterator(path[-1]):
    17921810                    queue.append(path + [neighbor])
    17931811
     
    18581876
    18591877            sage: pi = g.all_paths_iterator(simple=True)
    18601878            sage: list(pi)
    1861             [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd'], ['b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c']]
     1879            [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'],
     1880             ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'],
     1881             ['d', 'c', 'd'], ['a', 'b', 'c', 'd']]
    18621882
    18631883        Or simply bound the length of the enumerated paths::
    18641884
    18651885            sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b', 'c'], max_length=6)
    18661886            sage: list(pi)
    1867             [['a', 'b'], ['a', 'a', 'b'], ['a', 'b', 'c'], ['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'], ['a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'b', 'c'], ['a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'a', 'b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c', 'd', 'c']]
     1887            [['a', 'b'], ['a', 'a', 'b'], ['a', 'b', 'c'],
     1888             ['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'],
     1889             ['a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'b', 'c'],
     1890             ['a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'b'],
     1891             ['a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'b', 'c', 'd', 'c'],
     1892             ['a', 'a', 'a', 'a', 'a', 'a', 'b'],
     1893             ['a', 'a', 'a', 'a', 'a', 'b', 'c'],
     1894             ['a', 'a', 'a', 'b', 'c', 'd', 'c'],
     1895             ['a', 'b', 'c', 'd', 'c', 'd', 'c']]
    18681896
    18691897        By default, empty paths are not enumerated, but it may be
    18701898        parametrized::
    18711899
    18721900            sage: pi = g.all_paths_iterator(simple=True, trivial=True)
    18731901            sage: list(pi)
    1874             [['a'], ['b'], ['c'], ['d'], ['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd'], ['b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c']]
     1902            [['a'], ['b'], ['c'], ['d'], ['a', 'a'], ['a', 'b'], ['b', 'c'],
     1903             ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'],
     1904             ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']]
    18751905            sage: pi = g.all_paths_iterator(simple=True, trivial=False)
    18761906            sage: list(pi)
    1877             [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd'], ['b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c']]
     1907            [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'],
     1908             ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'],
     1909             ['d', 'c', 'd'], ['a', 'b', 'c', 'd']]
    18781910        """
    18791911        if starting_vertices is None:
    18801912            starting_vertices = self
     
    19401972
    19411973            sage: g = DiGraph({'a' : ['a', 'b'], 'b' : ['c'], 'c' : ['d'], 'd' : ['c']}, loops=True)
    19421974            sage: g.all_simple_paths()
    1943             [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd'], ['b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c']]
     1975            [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'],
     1976             ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'],
     1977             ['d', 'c', 'd'], ['a', 'b', 'c', 'd']]
    19441978
    19451979        One may compute all paths having specific starting and/or
    19461980        ending vertices::
    19471981
    19481982            sage: g.all_simple_paths(starting_vertices=['a'])
    1949             [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'c']]
     1983            [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
    19501984            sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['c'])
    1951             [['a', 'b', 'c'], ['a', 'b', 'c', 'd', 'c']]
     1985            [['a', 'b', 'c']]
    19521986            sage: g.all_simple_paths(starting_vertices=['a'], ending_vertices=['b', 'c'])
    1953             [['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd', 'c']]
     1987            [['a', 'b'], ['a', 'b', 'c']]
    19541988
    19551989        It is also possible to bound the length of the paths::
    19561990
    19571991            sage: g.all_simple_paths(max_length=2)
    1958             [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd']]
     1992            [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'],
     1993             ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'],
     1994             ['d', 'c', 'd']]
    19591995
    19601996        By default, empty paths are not enumerated, but this can
    19611997        be parametrized::
    19621998
    19631999            sage: g.all_simple_paths(starting_vertices=['a'], trivial=True)
    1964             [['a'], ['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'c']]
     2000            [['a'], ['a', 'a'], ['a', 'b'], ['a', 'b', 'c'],
     2001             ['a', 'b', 'c', 'd']]
    19652002            sage: g.all_simple_paths(starting_vertices=['a'], trivial=False)
    1966             [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'c']]
     2003            [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']]
    19672004        """
    19682005        return list(self.all_paths_iterator(starting_vertices=starting_vertices, ending_vertices=ending_vertices, simple=True, max_length=max_length, trivial=trivial))
    19692006