Ticket #8288: trac_8288-reviewer.patch

File trac_8288-reviewer.patch, 16.2 KB (added by mvngu, 11 years ago)
  • sage/combinat/backtrack.py

    # HG changeset patch
    # User Minh Van Nguyen <nguyenminh2@gmail.com>
    # Date 1271645265 25200
    # Node ID 5fdfa5c79f8fefa4860b28751af6e1f6bc48642f
    # Parent  54bf196dd08eb8b87dad86a1a2ad17975507a388
    #8288: Depth/Breadth improvement for SearchForest: reviewer patch
    
    diff --git a/sage/combinat/backtrack.py b/sage/combinat/backtrack.py
    a b  
    55elements can be enumerated by exploring a search space with a (lazy)
    66tree or graph structure.
    77
    8 - :class:`~sage.combinat.backtrack.SearchForest`: Depth and Breath first
     8- :class:`~sage.combinat.backtrack.SearchForest`: Depth and breadth first
    99  search through a tree described by a ``children`` function.
    1010- :class:`~sage.combinat.backtrack.GenericBacktracker`: Depth first search
    1111  through a tree described by a ``children`` function, with branch pruning,
     
    101101                stack.append( self._rec(obj, state) )
    102102
    103103
    104 def search_forest_iterator(roots, children, method="depth"):
     104def search_forest_iterator(roots, children, algorithm="depth"):
    105105    r"""
    106106    Returns an iterator on the nodes of the forest having the given
    107107    roots, and where ``children(x)`` returns the children of the node ``x``
     
    112112
    113113    - ``roots``: a list (or iterable)
    114114    - ``children``: a function returning a list (or iterable)
    115     - ``method``: ``"depth"`` or ``"breadth"``
     115    - ``algorithm``: the search strategy (default: ``"depth"``). If
     116      ``algorithm="depth"``, use depth-first search. If
     117      ``algorithm="breadth"``, use breadth-first search.
    116118
    117119    EXAMPLES:
    118120
     
    128130        sage: list(search_forest_iterator([[]], lambda l: [l + [i] for i in range(4) if i not in l] if len(l) < 2 else []))
    129131        [[], [0], [0, 1], [0, 2], [0, 3], [1], [1, 0], [1, 2], [1, 3], [2], [2, 0], [2, 1], [2, 3], [3], [3, 0], [3, 1], [3, 2]]
    130132
    131     We show how to set the enumeration method::
     133    We show how to set the enumeration algorithm::
    132134
    133135        sage: from sage.combinat.backtrack import search_forest_iterator
    134         sage: list(search_forest_iterator([[]], lambda l: [l+[0], l+[1]] if len(l) < 3 else [], method="breadth"))
     136        sage: list(search_forest_iterator([[]], lambda l: [l+[0], l+[1]] if len(l) < 3 else [], algorithm="breadth"))
    135137        [[], [0], [1], [0, 0], [0, 1], [1, 0], [1, 1], [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
    136138    """
    137     #Set the position according the method depth/breadth   
    138     if method == "depth":
     139    # Set the element removal position according to depth-first or
     140    # breadth-first search.
     141    if algorithm == "depth":
    139142        position = -1
     143    elif algorithm == "breadth":
     144        position = 0
    140145    else:
    141         position = 0
     146        raise ValueError("Unsupported search algorithm (= %s)" % algorithm)
    142147
    143148    #Invariant: stack[i] contains an iterator for the siblings of the i-th node of the current branch
    144149    stack = [iter(roots)]
     
    159164# We define a pickable function for the TestSuite of SearchForest
    160165def pick_children(x):
    161166    r"""
    162     pick_children is example of pickable function of children.
    163     A SearchForest instance is pickable if and only if it is
     167    The function ``pick_children`` is an example of a pickable function of
     168    children. A ``SearchForest`` instance is pickable if and only if it is
    164169    defined with pickable functions.
    165170
    166171    EXAMPLES::
     
    176181        sage: for i in range(20):
    177182        ...       assert pick_children(i) == unpickable_children(i)
    178183    """
    179     return [x+1]
     184    return [x + 1]
    180185
    181186
    182187from sage.combinat.combinat import CombinatorialClass
     
    315320        r"""
    316321        Returns an iterable over the children of the element ``x``.
    317322
     323        INPUT:
     324
     325        - ``x``: an element.
     326
    318327        EXAMPLES::
    319328
    320329            sage: I = SearchForest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)])
     
    333342
    334343    def father(self, x):
    335344        r"""
    336         Returns the father of the element ``x`` if a fonction ``father``
     345        Returns the father of the element ``x`` if a function ``father``
    337346        was given in argument. If not raise an ``AssertionError``.
    338347
     348        INPUT:
     349
     350        - ``x``: an element.
     351
    339352        EXAMPLES::
    340353
    341354            sage: father = lambda t: (t[0]-1,0) if t[1] == 0 else (t[0],t[1]-1)
     
    351364            sage: I.father(_)
    352365            (0, 0)
    353366        """
    354         assert self._father != None, "No 'father' function given"
     367        assert self._father is not None, "No 'father' function given"
    355368        return self._father(x)
    356369
    357370    def next_brother(self, x, father=None):
    358371        r"""
    359 
    360         Returns the next brother of the element ``x`` if it exist, returns
     372        Returns the next brother of the element ``x`` if it exist. Returns
    361373        ``None`` otherwise.
    362374
     375        INPUT:
     376
     377        - ``x``: an element.
     378        - ``father``: (default: ``None``) a father function.
     379
    363380        If a function ``_next_brother`` was given at the creation of ``self``,
    364         the methods ``next_brother`` simply returns its results, otherwise it
     381        the method ``next_brother`` simply returns its results. Otherwise it
    365382        returns the next children of the father of ``x``.
    366383
    367384        EXAMPLES::
     
    383400            (2, 1)
    384401            sage: I.next_brother((2,1))
    385402        """
    386         # If the function next_brother was given in argument of ``self.__init__``,
    387         # we use it firstly.
    388         if self._next_brother != None:
     403        # If the function next_brother was given in argument of
     404        # self.__init__, we use it firstly.
     405        if self._next_brother is not None:
    389406            return self._next_brother(x)
    390407        else:
    391408            # If we have no next_brother method, we search for the father and
    392409            # mainly the father given in argument, otherwise the father method.
    393             if father == None:
     410            if father is None:
    394411                father = self.father(x)
    395412            children = self.children(father)
    396413            brother = children.next()
     
    424441
    425442    def depth_first_search_iterator(self):
    426443        r"""
    427         Returns an iterator on the elements of ``self`` exploring the tree by depth.
     444        Returns an iterator on the elements of ``self`` exploring the tree
     445        by depth-first search.
    428446
    429447        EXAMPLES::
    430448
    431             sage: f = SearchForest([[]],
    432             ...                    lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
     449            sage: f = SearchForest(
     450            ...   [[]],
     451            ...   lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
    433452            sage: list(f.depth_first_search_iterator())
    434             [[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1], [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]] 
     453            [[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1], [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]]
    435454        """
    436         return search_forest_iterator(self._roots, self._children, method="depth")
     455        return search_forest_iterator(self._roots,
     456                                      self._children,
     457                                      algorithm="depth")
    437458
    438459    def breadth_first_search_iterator(self):
    439460        r"""
    440461        Returns an iterator on the elements of ``self`` exploring the
    441         tree by breadth first search.
     462        tree by breadth-first search.
    442463
    443464        EXAMPLES::
    444465
    445             sage: f = SearchForest([[]],
    446             ...                    lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
     466            sage: f = SearchForest(
     467            ...   [[]],
     468            ...   lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
    447469            sage: list(f.breadth_first_search_iterator())
    448470            [[], [0], [1], [0, 0], [0, 1], [1, 0], [1, 1], [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
    449471        """
    450         return search_forest_iterator(self._roots, self._children, method="breadth")
     472        return search_forest_iterator(self._roots,
     473                                      self._children,
     474                                      algorithm="breadth")
    451475
    452476    def next_generation_iterator(self, fathers):
    453477        r"""
    454         From an iterator ``it`` over some elements of ``self``, return an iterator
    455         over all children of elements generated by ``it`.
     478        Iterate over the children of ``fathers``.
     479
     480        - ``fathers``: an iterable of father objects.
    456481
    457482        EXAMPLES::
    458483
    459             sage: I = SearchForest([(0,0)],
    460             ...           lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0
    461             ...                     else [(l[0], l[1]+1)])
     484            sage: I = SearchForest(
     485            ...   [(0,0)],
     486            ...   lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)])
    462487            sage: list(I.next_generation_iterator(I.roots()))
    463488            [(1, 0), (0, 1)]
    464             sage: I = SearchForest([[]],
    465             ...                    lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
     489            sage: I = SearchForest(
     490            ...   [[]],
     491            ...   lambda l: [l+[0], l+[1]] if len(l) < 3 else [])
    466492            sage: list(I.next_generation_iterator(I.roots()))
    467493            [[0], [1]]
    468494        """
     
    472498
    473499    def _next_element_by_father(self, x):
    474500        r"""
    475         Returns the next element of ``self`` by breadth enumeration using
     501        Returns the next element of ``self`` by breadth-first enumeration using
    476502        ``father`` and ``next_brother`` method.
    477503
     504        - ``x``: an element.
     505
    478506        EXAMPLES::
    479507
    480508            sage: def children(t):
     
    528556        roots = list(self.roots())
    529557        for i in range(len(roots)):
    530558            if x == roots[i]:
    531                 if i < len(roots)-1:
    532                     return roots[i+1]
     559                if i < len(roots) - 1:
     560                    return roots[i + 1]
    533561                else:
    534562                    return self.children(roots[0]).next()
    535563        brother = self.next_brother(x)
    536         if brother != None:
     564        if brother is not None:
    537565            return brother
    538566        else:
    539567            next_father = self._next_element_by_father(self.father(x))
     
    553581        Returns an iterator starting with the element ``start`` and stopping
    554582        just before the element ``end``.
    555583
     584        INPUT:
     585
     586        - ``start``: an element from which to begin the iteration.
     587        - ``end``: an element up to which we stop the iteration. If our
     588          iteration stops at ``end``, then the last element in our iteration
     589          is the element just before ``end``. Thus the range ``start`` to
     590          ``end`` includes ``start``, but excludes ``end``.
     591
    556592        EXAMPLES::
    557593
    558594            sage: father = lambda t: (t[0]-1,0) if t[1] == 0 else (t[0],t[1]-1)
     
    571607        r"""
    572608        Returns the first element of given ``depth``.
    573609
     610        INPUT:
     611
     612        - ``depth``: nonnegative integer.
     613
    574614        EXAMPLES::
    575615
    576616            sage: father = lambda l : l[:-1]
     
    592632            except StopIteration:
    593633                return None
    594634        else:
    595             if father_with_depth == None:
     635            if father_with_depth is None:
    596636                try:
    597                     next_father =  self.roots().next()
    598                     return self.first_element_of_depth(depth, father_with_depth=(next_father,0))
     637                    next_father = self.roots().next()
     638                    return self.first_element_of_depth(
     639                        depth,
     640                        father_with_depth=(next_father, 0))
    599641                except StopIteration:
    600642                    return None
    601643            else:
     
    603645                depth_father = father_with_depth[1]
    604646                try:
    605647                    next_father = self.children(father).next()
    606                     if depth == depth_father+1:
     648                    if depth == depth_father + 1:
    607649                        return next_father
    608650                    else:
    609                         return self.first_element_of_depth(depth, father_with_depth=(next_father,depth_father+1))
     651                        return self.first_element_of_depth(
     652                            depth,
     653                            father_with_depth=(next_father, depth_father + 1))
    610654                except StopIteration:
    611655                    next_father = self._next_element_by_father(father)
    612                     if next_father == None:
     656                    if next_father is None:
    613657                        return None
    614658                    else:
    615                         return self.first_element_of_depth(depth, father_with_depth=(next_father,depth_father))
     659                        return self.first_element_of_depth(
     660                            depth,
     661                            father_with_depth=(next_father, depth_father))
    616662       
    617     def element_of_depth_iterator(self, depth=0, method="full_generation"):
     663    def element_of_depth_iterator(self, depth=0, full_generation=True):
    618664        r"""
    619665        Returns an iterator on the elements of ``self`` of given depth.
    620666        An element of depth `n` can be obtained applying `n` times the
     
    622668
    623669        INPUT:
    624670
    625         - ``depth``: a non negative integer
    626         - ``method``: optional string.
     671        - ``depth``: a nonnegative integer (default: ``0``). The search
     672          depth.
    627673
    628 
    629         By default ``method`` is ``"full_generation"``. This means the
    630         algorithm start from the roots and generate all elements until the
    631         given depth is reached.
    632 
    633         If ``method`` is different of ``"full_generation"``, the algorithm
    634         makes use of ``father`` and ``next_brother`` methods. This reduces the
    635         number of calls to the ``children`` method.
     674        - ``full_generation``: boolean (default: ``True``). If
     675          ``full_generation=True``, the search starts from the root and
     676          generate all elements until the given depth is reached. If
     677          ``full_generation=False``, the search algorithm makes use of the
     678          ``father`` and ``next_brother`` methods. This reduces the number
     679          of calls to the ``children`` method.
    636680
    637681        EXAMPLES::
    638682
     
    652696            []
    653697            sage: father = lambda t: (t[0]-1,0) if t[1] == 0 else (t[0],t[1]-1)
    654698            sage: I = SearchForest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)], father=father)
    655             sage: list(I.element_of_depth_iterator(10, method="father"))
     699            sage: list(I.element_of_depth_iterator(10, full_generation=False))
    656700            [(10, 0), (9, 1), (8, 2), (7, 3), (6, 4), (5, 5), (4, 6), (3, 7), (2, 8), (1, 9), (0, 10)]
    657701            sage: father = lambda l : l[:-1]
    658702            sage: I = SearchForest([[3]], lambda l: (l+[i] for i in range(l[-1])), father = father)
    659             sage: list(I.element_of_depth_iterator(0, method="father"))
     703            sage: list(I.element_of_depth_iterator(0, full_generation=False))
    660704            [[3]]
    661             sage: list(I.element_of_depth_iterator(1, method="father"))
     705            sage: list(I.element_of_depth_iterator(1, full_generation=False))
    662706            [[3, 0], [3, 1], [3, 2]]
    663707            sage: for i in range(8):
    664             ...       assert list(I.element_of_depth_iterator(i)) == list(I.element_of_depth_iterator(i, method="father"))
     708            ...       assert list(I.element_of_depth_iterator(i)) == list(I.element_of_depth_iterator(i, full_generation=False))
    665709        """       
    666         if method == "full_generation":
     710        if full_generation:
    667711            iter = self.roots()
    668712            for i in range(depth):
    669713                iter = self.next_generation_iterator(iter)
     
    673717            # use father and next_brother method...
    674718            node = self.first_element_of_depth(depth)
    675719            # node is now the starting point for the enumeration
    676             if node == None:
     720            if node is None:
    677721                return [].__iter__()
    678722            else:
    679                 end_node = self.first_element_of_depth(depth+1, father_with_depth=(node,depth))
     723                end_node = self.first_element_of_depth(
     724                    depth + 1,
     725                    father_with_depth=(node, depth))
    680726                return self._iter_from_to(node, end_node)
    681727
    682728