# Ticket #14498: trac_14998-more-edits-dg.patch

File trac_14998-more-edits-dg.patch, 84.5 KB (added by darij, 6 years ago)

new review patch

• ## sage/combinat/abstract_tree.py

# HG changeset patch
# User darij grinberg <darijgrinberg@gmail.com>
# Date 1384130170 28800
# Node ID d1916f255d1147726cbfea1082543d454c6708f3
# Parent  10f4f08eea2cf27bf045363c7bf6a4fd00b13377
trac #14498: Darij's review patch, to be applied ATOP of trac_14498-algorithms_trees-rebased.patch and trac_14498-tree-imps-dg-rebased.patch

diff --git a/sage/combinat/abstract_tree.py b/sage/combinat/abstract_tree.py
 a incoherent with the data structure. from sage.structure.list_clone import ClonableArray from sage.rings.integer import Integer from sage.misc.misc_c import prod ############################################################################### # # use to load tikz in the preamble (one for *view* and one for *notebook*) from sage.misc.latex import latex latex.add_package_to_preamble_if_available("tikz") latex.add_to_mathjax_avoid_list("tikz") ############################################################################### # Unfortunately Cython forbids multiple inheritance. Therefore, we do not # inherits from SageObject to be able to inherits from Element or a subclass # inherit from SageObject to be able to inherit from Element or a subclass # of it later. class AbstractTree(object): """ Abstract Tree Abstract Tree. There is no data structure defined here, as this class is meant to be extended, not instantiated. class AbstractTree(object):  method should return the same value for trees that are considered equal (see the "canonical labellings" section in the documentation of the :class:AbstractTree  module). :class:AbstractTree  class). * For a tree T the call T.parent().labelled_trees() should return a parent for labelled trees of the same kind: for example, class AbstractTree(object): The depth-first pre-order traversal iterator. This method iters each node following the depth-first pre-order traversal algorithm (recursive implementation). traversal algorithm (recursive implementation). The algorithm is:: yield the root (in the case of binary trees, if it is not a node); then explore each subtree (by the algorithm) from the leftmost one to the rightmost one. EXAMPLES: For example, on the following binary tree b:: class AbstractTree(object): |        / \      | |       4   6     | the depth-first pre-order traversal algorithm explores b in the following order of nodes: 3,1,2,7,5,4,6,8. The algorithm is:: manipulate the root, then explore each subtree (by the algorithm). (only the nodes shown), the depth-first pre-order traversal algorithm explores b in the following order of nodes: 3,1,2,7,5,4,6,8. Another example:: class AbstractTree(object): |  / /        | | 4 5         | The algorithm explores this tree in the following order: 1,2,3,4,5,6,7,8,9,10. The algorithm explores this labelled tree in the following order: 1,2,3,4,5,6,7,8,9,10. TESTS:: class AbstractTree(object): [       4   6     ] sage: [n.label() for n in b.pre_order_traversal_iter()] [3, 1, 2, 7, 5, 4, 6, 8] sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling() sage: ascii_art([t]) [     __1____   ] class AbstractTree(object): [ 4 5           ] sage: [n.label() for n in t.pre_order_traversal_iter()] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] sage: [n for n in BinaryTree(None).pre_order_traversal_iter()] [] The following test checks that things don't go wrong if some among the descendants of the tree are equal or even identical:: sage: u = BinaryTree(None) sage: v = BinaryTree([u, u]) sage: w = BinaryTree([v, v]) sage: t = BinaryTree([w, w]) sage: t.node_number() 7 sage: l = [1 for i in t.pre_order_traversal_iter()] sage: len(l) 7 """ if self.is_empty(): return class AbstractTree(object): def iterative_pre_order_traversal(self, action=None): r""" The depth-first pre-order traversal algorithm (iterative implementation). Run the depth-first pre-order traversal algorithm (iterative implementation) and subject every node encountered to some procedure action. The algorithm is:: manipulate the root with function action (in the case of a binary tree, only if the root is not a leaf); then explore each subtree (by the algorithm) from the leftmost one to the rightmost one. INPUT: - action -- (optional) a function which takes a node in input and does something during the exploration - action -- (optional) a function which takes a node as input, and does something during the exploration OUTPUT: None. (This is *not* an iterator.) .. SEEALSO:: class AbstractTree(object): sage: b.iterative_pre_order_traversal(lambda node: l.append(node.label())) sage: l [3, 1, 2, 7, 5, 4, 6, 8] sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling() sage: t 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]] class AbstractTree(object): sage: l [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] sage: l = [] sage: BinaryTree().canonical_labelling().\ ....:     pre_order_traversal(lambda node: l.append(node.label())) sage: l class AbstractTree(object): ....:     iterative_pre_order_traversal(lambda node: l.append(node.label())) sage: l [1] The following test checks that things don't go wrong if some among the descendants of the tree are equal or even identical:: sage: u = BinaryTree(None) sage: v = BinaryTree([u, u]) sage: w = BinaryTree([v, v]) sage: t = BinaryTree([w, w]) sage: t.node_number() 7 sage: l = [] sage: t.iterative_pre_order_traversal(lambda node: l.append(1)) sage: len(l) 7 """ if self.is_empty(): return class AbstractTree(object): def pre_order_traversal(self, action=None): r""" The depth-first pre-order traversal algorithm (recursive implementation). Run the depth-first pre-order traversal algorithm (recursive implementation) and subject every node encountered to some procedure action. The algorithm is:: manipulate the root with function action (in the case of a binary tree, only if the root is not a leaf); then explore each subtree (by the algorithm) from the leftmost one to the rightmost one. INPUT: - action -- (optional) a function which takes a node in input and does something during the exploration - action -- (optional) a function which takes a node as input, and does something during the exploration For example on the following binary tree b:: OUTPUT: None. (This is *not* an iterator.) EXAMPLES: For example, on the following binary tree b:: |   ___3____      | |  /        \     | class AbstractTree(object): |        / \      | |       4   6     | the depth-first pre-order traversal algorithm explores b in the following order of nodes 3,1,2,7,5,4,6,8. The algorithm is:: manipulate the root with function action, then explore each subtrees (by the algorithm) the depth-first pre-order traversal algorithm explores b in the following order of nodes: 3,1,2,7,5,4,6,8. Another example:: class AbstractTree(object): sage: b.iterative_pre_order_traversal(lambda node: li.append(node.label())) sage: l == li True sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling() sage: t 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]] class AbstractTree(object): sage: t.iterative_pre_order_traversal(lambda node: li.append(node.label())) sage: l == li True sage: l = [] sage: BinaryTree().canonical_labelling().\ ....:     pre_order_traversal(lambda node: l.append(node.label())) class AbstractTree(object): ....:     pre_order_traversal(lambda node: l.append(node.label())) sage: l [1] The following test checks that things don't go wrong if some among the descendants of the tree are equal or even identical:: sage: u = BinaryTree(None) sage: v = BinaryTree([u, u]) sage: w = BinaryTree([v, v]) sage: t = BinaryTree([w, w]) sage: t.node_number() 7 sage: l = [] sage: t.pre_order_traversal(lambda node: l.append(1)) sage: len(l) 7 """ if action is None: action = lambda x: None class AbstractTree(object): The depth-first post-order traversal iterator. This method iters each node following the depth-first post-order traversal algorithm (recursive implementation). traversal algorithm (recursive implementation). The algorithm is:: explore each subtree (by the algorithm) from the leftmost one to the rightmost one; then yield the root (in the case of binary trees, only if it is not a node). EXAMPLES: For example on the following binary tree b:: class AbstractTree(object): |        / \      | |       4   6     | the depth-first post-order traversal algorithm explores b in the following order of nodes 2,1,4,6,5,8,7,3. (only the nodes are shown), the depth-first post-order traversal algorithm explores b in the following order of nodes: 2,1,4,6,5,8,7,3. The algorithm is:: explore each subtrees (by the algorithm) then manipulate the root with function action Another example:: For another example, consider the labelled tree:: |     __1____ | |    /  /   / | class AbstractTree(object): [       4   6     ] sage: [node.label() for node in b.post_order_traversal_iter()] [2, 1, 4, 6, 5, 8, 7, 3] sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling() sage: ascii_art([t]) [     __1____   ] class AbstractTree(object): [ 4 5           ] sage: [node.label() for node in t.post_order_traversal_iter()] [4, 5, 3, 2, 7, 6, 9, 10, 8, 1] sage: [node.label() for node in BinaryTree().canonical_labelling().\ ....:     post_order_traversal_iter()] [] sage: [node.label() for node in OrderedTree([]).\ ....:     canonical_labelling().post_order_traversal_iter()] [1] The following test checks that things don't go wrong if some among the descendants of the tree are equal or even identical:: sage: u = BinaryTree(None) sage: v = BinaryTree([u, u]) sage: w = BinaryTree([v, v]) sage: t = BinaryTree([w, w]) sage: t.node_number() 7 sage: l = [1 for i in t.post_order_traversal_iter()] sage: len(l) 7 """ if self.is_empty(): return class AbstractTree(object): def post_order_traversal(self, action=None): r""" The depth-first post-order traversal algorithm (recursive implementation). Run the depth-first post-order traversal algorithm (recursive implementation) and subject every node encountered to some procedure action. The algorithm is:: explore each subtree (by the algorithm) from the leftmost one to the rightmost one; then manipulate the root with function action (in the case of a binary tree, only if the root is not a leaf). INPUT: - action -- (optional) a function which takes a node in input and does something during the exploration - action -- (optional) a function which takes a node as input, and does something during the exploration OUTPUT: None. (This is *not* an iterator.) .. SEEALSO:: class AbstractTree(object): sage: b.post_order_traversal(lambda node: l.append(node.label())) sage: l [2, 1, 4, 6, 5, 8, 7, 3] sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).\ ....:     canonical_labelling(); t 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]] class AbstractTree(object): sage: t.post_order_traversal(lambda node: l.append(node.label())) sage: l [4, 5, 3, 2, 7, 6, 9, 10, 8, 1] sage: l = [] sage: BinaryTree().canonical_labelling().\ ....:     post_order_traversal(lambda node: l.append(node.label())) class AbstractTree(object): ....:     post_order_traversal(lambda node: l.append(node.label())) sage: l [1] The following test checks that things don't go wrong if some among the descendants of the tree are equal or even identical:: sage: u = BinaryTree(None) sage: v = BinaryTree([u, u]) sage: w = BinaryTree([v, v]) sage: t = BinaryTree([w, w]) sage: t.node_number() 7 sage: l = [] sage: t.post_order_traversal(lambda node: l.append(1)) sage: len(l) 7 """ if action is None: action = lambda x: None class AbstractTree(object): def iterative_post_order_traversal(self, action=None): r""" The depth-first post-order traversal algorithm (iterative implementation). Run the depth-first post-order traversal algorithm (iterative implementation) and subject every node encountered to some procedure action. The algorithm is:: explore each subtree (by the algorithm) from the leftmost one to the rightmost one; then manipulate the root with function action (in the case of a binary tree, only if the root is not a leaf). INPUT: - action -- (optional) a function which takes a node in input and does something during the exploration - action -- (optional) a function which takes a node as input, and does something during the exploration OUTPUT: None. (This is *not* an iterator.) .. SEEALSO:: class AbstractTree(object): 3[1[., 2[., .]], 7[5[4[., .], 6[., .]], 8[., .]]] sage: b.iterative_post_order_traversal(lambda node: l.append(node.label())) sage: l [8, 6, 4, 5, 7, 2, 1, 3] [2, 1, 4, 6, 5, 8, 7, 3] sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling() sage: t 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]] sage: l = [] sage: t.iterative_post_order_traversal(lambda node: l.append(node.label())) sage: l [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] [4, 5, 3, 2, 7, 6, 9, 10, 8, 1] sage: l = [] sage: BinaryTree().canonical_labelling().\ ....:     iterative_post_order_traversal( class AbstractTree(object): ....:         lambda node: l.append(node.label())) sage: l [1] The following test checks that things don't go wrong if some among the descendants of the tree are equal or even identical:: sage: u = BinaryTree(None) sage: v = BinaryTree([u, u]) sage: w = BinaryTree([v, v]) sage: t = BinaryTree([w, w]) sage: t.node_number() 7 sage: l = [] sage: t.iterative_post_order_traversal(lambda node: l.append(1)) sage: len(l) 7 """ if self.is_empty(): return if action is None: action = lambda x: None stack = [self] mark = [] while len(stack) > 0: node = stack[-1] if node in mark: if node != None: # A "None" on the stack means that the node right before # it on the stack has already been "exploded" into # subtrees, and should not be exploded again, but instead # should be manipulated and removed from the stack. stack.append(None) for i in range(len(node)): subtree = node[-i - 1] if not subtree.is_empty(): stack.append(subtree) else: stack.pop() node = stack.pop() action(node) else: mark.append(node) stack.extend(filter(lambda n: not n.is_empty(), node)) def breadth_first_order_traversal(self, action=None): r""" The breadth-first order traversal algorithm. Run the breadth-first post-order traversal algorithm and subject every node encountered to some procedure action. The algorithm is:: queue <- [ root ]; while the queue is not empty: node <- pop( queue ); manipulate the node; prepend to the queue the list of all subtrees of the node (from the rightmost to the leftmost). INPUT: - action -- (optional) a function which takes a node in input and does omething during the exploration - action -- (optional) a function which takes a node as input, and does something during the exploration OUTPUT: None. (This is *not* an iterator.) EXAMPLES: For example, on the following binary tree b:: class AbstractTree(object): |        / \      | |       4   6     | the breadth-first order traversal algorithm explores b in the the breadth-first order traversal algorithm explores b in the following order of nodes: 3,1,7,2,5,8,4,6. The algorithm is:: queue <- ( root ) while the queue is not empty: node <- pop( queue ) manipulate the node append in the queue all subtrees of the node TESTS:: sage: b = BinaryTree([[None,[]],[[[],[]],[]]]).canonical_labelling() class AbstractTree(object): sage: b.breadth_first_order_traversal(lambda node: l.append(node.label())) sage: l [3, 1, 7, 2, 5, 8, 4, 6] sage: t = OrderedTree([[[[],[]]],[[]],[[],[]]]).canonical_labelling() sage: t 1[2[3[4[], 5[]]], 6[7[]], 8[9[], 10[]]] class AbstractTree(object): sage: t.breadth_first_order_traversal(lambda node: l.append(node.label())) sage: l [1, 2, 6, 8, 3, 7, 9, 10, 4, 5] sage: l = [] sage: BinaryTree().canonical_labelling().\ ....:     breadth_first_order_traversal( class AbstractTree(object): def subtrees(self): """ Return a generator for all subtrees of self. Return a generator for all nonempty subtrees of self. The number of subtrees of a tree is its number of elements. The number of nonempty subtrees of a tree is its number of nodes. (The word "nonempty" makes a difference only in the case of binary trees. For ordered trees, for example, all trees are nonempty.) EXAMPLES:: class AbstractTree(object): sage: list(OrderedTree([[],[[]]]).subtrees()) [[[], [[]]], [], [[]], []] sage: list(OrderedTree([[],[[]]]).canonical_labelling().subtrees()) [1[2[], 3[4[]]], 2[], 3[4[]], 4[]] sage: list(BinaryTree([[],[[],[]]]).subtrees()) [[[., .], [[., .], [., .]]], [., .], [[., .], [., .]], [., .], [., .]] sage: v = BinaryTree([[],[]]) sage: list(v.canonical_labelling().subtrees()) [2[1[., .], 3[., .]], 1[., .], 3[., .]] TESTS:: sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]]) class AbstractTree(object): OUTPUT: This method returns a list of sequences of integers. Each of these sequences represents a path from the root node to another one : (1, 3, 2, 5, 3) represents the node obtained by chosing the 1st children of the root node (in the ordering returned by iter), then the 3rd of its children, then the 2nd of this element, etc. sequences represents a path from the root node to some node. For instance, (1, 3, 2, 5, 0, 3) represents the node obtained by choosing the 1st child of the root node (in the ordering returned by iter), then the 3rd child of its child, then the 2nd child of the latter, etc. (where the labelling of the children is zero-based). The root element is represented by the empty tuple (). class AbstractTree(object): def node_number(self): """ The number of nodes of self The number of nodes of self. EXAMPLES:: class AbstractTree(object): sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).node_number() 13 EXAMPLE:: EXAMPLES:: sage: BinaryTree(None).node_number() 0 class AbstractTree(object): def depth(self): """ The depth of self The depth of self. EXAMPLES:: class AbstractTree(object): def canonical_labelling(self,shift=1): """ Returns a labelled version of self Returns a labelled version of self. The actual canonical labelling is currently unspecified. However, it is guaranteed to have labels in 1...n where n is the number of class AbstractTree(object): def tree_factorial(self): """ Return the tree-factorial of self Return the tree-factorial of self. Definition: class AbstractTree(object): def _latex_(self): r""" Nice output which can be easily modified Generate \LaTeX output which can be easily modified. TESTS:: class AbstractTree(object): (a) edge (b) edge (e); \end{tikzpicture}} """ ############################################################################### # # use to load tikz in the preamble (one for *view* and one for *notebook*) from sage.misc.latex import latex latex.add_package_to_preamble_if_available("tikz") latex.add_to_mathjax_avoid_list("tikz") ############################################################################### # latex environnement : TikZ begin_env = "\\begin{tikzpicture}[auto]\n" end_env = "\\end{tikzpicture}" class AbstractTree(object): class AbstractClonableTree(AbstractTree): """ Abstract Clonable Tree Abstract Clonable Tree. An abstract class for trees with clone protocol (see :mod:~sage.structure.list_clone). It is expected that classes extending this one may also inherit from classes like :class:ClonableArray or :class:~sage.structure.list_clone.ClonableList depending wether one :class:~sage.structure.list_clone.ClonableList depending whether one wants to build trees where adding a child is allowed. .. NOTE:: Due to the limitation of Cython inheritance, one cannot inherit here from :class:~sage.structure.list_clone.ClonableElement, because it would prevent us to inherit later from it would prevent us from later inheriting from from :class:~sage.structure.list_clone.ClonableArray or :class:~sage.structure.list_clone.ClonableList. .. rubric:: How should this class be extended ? A class extending :class:AbstractTree  should the following assumptions: A class extending :class:AbstractClonableTree  should satisfy the following assumptions: * An instantiable class extending :class:AbstractTree  should also extend the :class:ClonableElement  class or one of its subclass generally at least :class:ClonableArray * An instantiable class extending :class:AbstractClonableTree  should also extend the :class:ClonableElement  class or one of its subclasses generally, at least :class:ClonableArray . * To respect the Clone protocol, the :meth:AbstractClonableTree.check method should be overridden by the new class. See also the assumptions in :class:AbstractTree. """ def check(self): """ Check that self is a correct tree Check that self is a correct tree. This method does nothing. It is implemented here because many extensions of :class:AbstractTree  also extend extensions of :class:AbstractClonableTree  also extend :class:sage.structure.list_clone.ClonableElement, which requires it. It should be overriden in subclass in order to check that the invariant of the kind of tree holds (eg: two children for binary trees). It should be overridden in subclasses in order to check that the characterizing property of the respective kind of tree holds (eg: two children for binary trees). EXAMPLES:: class AbstractClonableTree(AbstractTree) sage: x = OrderedTree([[],[[]]]) sage: with x.clone() as x: ...    x[0] = OrderedTree([[]]) ....:     x[0] = OrderedTree([[]]) sage: x [[[]], [[]]] class AbstractClonableTree(AbstractTree) sage: y = OrderedTree(x) sage: with x.clone() as x: ...    x[0,0] = OrderedTree([[]]) ....:     x[0,0] = OrderedTree([[]]) sage: x [[[[]]], [[]]] sage: y [[[]], [[]]] sage: with y.clone() as y: ...    y[(0,)] = OrderedTree([]) ....:     y[(0,)] = OrderedTree([]) sage: y [[], [[]]] class AbstractClonableTree(AbstractTree) sage: bt = BinaryTree([[],[[],[]]]); bt [[., .], [[., .], [., .]]] sage: with bt.clone() as bt1: ...    bt1[0,0] = BinaryTree([[[], []], None]) ....:     bt1[0,0] = BinaryTree([[[], []], None]) sage: bt1 [[[[[., .], [., .]], .], .], [[., .], [., .]]] class AbstractClonableTree(AbstractTree) sage: x = OrderedTree([]) sage: with x.clone() as x: ...    x[0] = OrderedTree([[]]) ....:     x[0] = OrderedTree([[]]) Traceback (most recent call last): ... ....: IndexError: list assignment index out of range sage: x = OrderedTree([]); x = OrderedTree([x,x]);x = OrderedTree([x,x]); x = OrderedTree([x,x]) sage: x = OrderedTree([]); x = OrderedTree([x,x]); x = OrderedTree([x,x]); x = OrderedTree([x,x]) sage: with x.clone() as x: ...    x[0,0] = OrderedTree() ....:     x[0,0] = OrderedTree() sage: x [[[], [[], []]], [[[], []], [[], []]]] """ class AbstractClonableTree(AbstractTree) sage: x = OrderedTree([[[], []],[[]]]) sage: with x.clone() as x: ...    x[0,1] = OrderedTree([[[]]]) # indirect doctest ....:     x[0,1] = OrderedTree([[[]]]) # indirect doctest sage: x [[[], [[[]]]], [[]]] """ class AbstractClonableTree(AbstractTree) class AbstractLabelledTree(AbstractTree): """ Abstract Labelled Tree Abstract Labelled Tree. Typically a class for labelled tree is contructed by inheriting from a class for unlabelled trees and :class:AbstractLabelledTree Typically a class for labelled trees is contructed by inheriting from a class for unlabelled trees and :class:AbstractLabelledTree. .. rubric:: How should this class be extended ? class AbstractLabelledTree(AbstractTree) following assumptions: * For a labelled tree T the call T.parent().unlabelled_trees() should return a parent for labelled trees of the same kind: for example, should return a parent for unlabelled trees of the same kind: for example, - if T is a binary labelled tree, T.parent() is LabelledBinaryTrees() and T.parent().unlabelled_trees() is class AbstractLabelledTree(AbstractTree) OrderedTrees() * In the same vein, the class of T should contain an attribute _Unlabelled which should be the class for the corresponding _UnLabelled which should be the class for the corresponding unlabelled trees. See also the assumptions in :class:AbstractTree. .. SEEALSO:: :class:AbstractTree """ def __init__(self, parent, children, label = None, check = True): class AbstractLabelledClonableTree(Abstr ... ValueError: object is immutable; please change a copy instead. sage: with t.clone() as t: ...    t.set_root_label(3) ....:     t.set_root_label(3) sage: t.label() 3 sage: t class AbstractLabelledClonableTree(Abstr ... ValueError: object is immutable; please change a copy instead. sage: with bt.clone() as bt: ...    bt.set_root_label(3) ....:     bt.set_root_label(3) sage: bt.label() 3 sage: bt class AbstractLabelledClonableTree(Abstr TESTS:: sage: with t.clone() as t: ...    t[0] = LabelledOrderedTree(t[0], label = 4) ....:     t[0] = LabelledOrderedTree(t[0], label = 4) sage: t 3[4[], None[None[], None[]]] sage: with t.clone() as t: ...    t[1,0] = LabelledOrderedTree(t[1,0], label = 42) ....:     t[1,0] = LabelledOrderedTree(t[1,0], label = 42) sage: t 3[4[], None[42[], None[]]] """ """ self._require_mutable() self._label = label class AbstractLabelledClonableTree(Abstr ... ValueError: object is immutable; please change a copy instead. sage: with t.clone() as t: ...    t.set_label((0,), 4) ....:     t.set_label((0,), 4) sage: t None[4[], None[None[], None[]]] sage: with t.clone() as t: ...    t.set_label((1,0), label = 42) ....:     t.set_label((1,0), label = 42) sage: t None[4[], None[42[], None[]]]
• ## sage/combinat/binary_tree.py

diff --git a/sage/combinat/binary_tree.py b/sage/combinat/binary_tree.py
 a # -*- coding: utf-8 -*- """ Binary Trees Binary Trees. This module deals with binary trees as mathematical (in particular immutable) objects. AUTHORS: REFERENCES: .. [LodayRonco] Jean-Louis Loday and María O. Ronco. .. [LodayRonco] Jean-Louis Loday and Maria O. Ronco. *Hopf algebra of the planar binary trees*, Advances in Mathematics, volume 139, issue 2, 10 November 1998, pp. 293-309. REFERENCES: *The algebra of binary search trees*, :arxiv:math/0401089v2. .. [CP12] Gregory Chatel, Vivane Pons. .. [CP12] Gregory Chatel, Viviane Pons. *Counting smaller trees in the Tamari order*, :arxiv:1212.0751v1. """ class BinaryTree(AbstractClonableTree, C Binary trees contain nodes and leaves, where each node has two children while each leaf has no children. The number of leaves always equals the number of nodes plus 1. of a binary tree always equals the number of nodes plus 1. INPUT: class BinaryTree(AbstractClonableTree, C leaf or a pair of binary trees. Syntactic sugar allows leaving out all but the outermost calls of the BinaryTree() constructor, so that, e. g., BinaryTree([BinaryTree(None),BinaryTree(None)]) can be simplified to BinaryTree([None,None]). It is also allowed to be shortened to BinaryTree([None,None]). It is also allowed to abbreviate [None, None] by []. - check -- (default to True) whether check for binary should be - check -- (default: True) whether check for binary should be performed or not. EXAMPLES:: class BinaryTree(AbstractClonableTree, C [[., .], .] sage: BinaryTree("[[], .]") [[., .], .] sage: BinaryTree([None, BinaryTree([None, None])]) [., [., .]] sage: BinaryTree([[], None, []]) Traceback (most recent call last): class BinaryTree(AbstractClonableTree, C sage: t1 = BinaryTree([[None, [[],[[], None]]],[[],[]]]) sage: t2 = BinaryTree([[[],[]],[]]) sage: with t1.clone() as t1c: ...       t1c[1,1,1] = t2 ....:     t1c[1,1,1] = t2 sage: t1 == t1c False """ class BinaryTree(AbstractClonableTree, C if with_leaves:   # We want leaves and nodes. # Special treatment for the case when self has only 1 vertex. # Special treatment for the case when self is empty. # In this case, rec(self, 0) would give a false result. if not self: return DiGraph([[0], lambda i,j: False]) class BinaryTree(AbstractClonableTree, C return res def canonical_labelling(self,shift=1): """ r""" Return a labelled version of self. The canonical labelling of a binary tree is a certain labelling of the The canonical labelling of a binary tree is a certain labelling of the nodes (not the leaves) of the tree. The actual canonical labelling is currently unspecified. However, it is guaranteed to have labels in 1...n where n is the number of class BinaryTree(AbstractClonableTree, C .. WARNING:: Left and right children might get interchanged in the actual picture. the actual picture. Moreover, for a labelled binary tree, the labels shown in the picture are not (in general) the ones given by the labelling! Use :meth:_latex_, view, :meth:_ascii_art_ or pretty_print for more faithful representations of the data of the tree. TESTS:: class BinaryTree(AbstractClonableTree, C The depth-first infix-order traversal iterator for the binary tree self. This method iters each vertex (node and leaf alike) following the depth-first infix order traversal algorithm. This method iters each vertex (node and leaf alike) of the given binary tree following the depth-first infix order traversal algorithm. The *depth-first infix order traversal algorithm* iterates through a binary tree as follows:: class BinaryTree(AbstractClonableTree, C [    1     4       3   5    ] [         / \               ] [        3   5,  ,      ,   ] sage: list(BinaryTree(None).in_order_traversal_iter()) [.] """ if self.is_empty(): yield self class BinaryTree(AbstractClonableTree, C sage: def n_action(_): ....:    global nb_node ....:    nb_node += 1 sage: BinaryTree().in_order_traversal(n_action, l_action) sage: nb_leaf, nb_node (1, 0) sage: nb_leaf, nb_node = 0, 0 sage: b = BinaryTree([[],[[],[]]]); b [[., .], [[., .], [., .]]] class BinaryTree(AbstractClonableTree, C sage: b.in_order_traversal(lambda node: l.append( node.label() )) sage: l [1, 2, 3, 4, 5] sage: leaf = 'a' sage: l = [] sage: def l_action(_): class BinaryTree(AbstractClonableTree, C r""" The list of all trees greater or equal to self in the Tamari order. This is the transitive ideal of its successors. This is the order filter of the Tamari order generated self. The Tamari order on binary trees of size n is the partial order on the set of all binary trees of size n generated by the class BinaryTree(AbstractClonableTree, C is a quotient of the weak order on the n-th symmetric group. See [CP12]_. EXAMPLES:: For example, the tree:: |     __o__   | class BinaryTree(AbstractClonableTree, C def tamari_pred(self): r""" Compute the list of predecessors of self in the Tamari poset. This list is computed by all left rotate possible on This list is computed by performing all left rotates possible on its nodes. EXAMPLES:: For this tree:: |     __o__   | class BinaryTree(AbstractClonableTree, C r""" The list of all trees smaller or equal to self in the Tamari order. This is the transitive ideal of its predecessors. This is the order ideal of the Tamari order generated self. The Tamari order on binary trees of size n is the partial order on the set of all binary trees of size n generated by the following requirement:  If a binary tree T' is obtained by right rotation (see :meth:right_rotate) from a binary tree T, then T < T'. This not only is a well-defined partial order, but actually is a lattice structure on the set of binary trees of size n, and is a quotient of the weak order on the n-th symmetric group. See [CP12]_. EXAMPLES:: The tree:: class BinaryTree(AbstractClonableTree, C def tamari_succ(self): r""" Compute the list of successors of self in the Tamari poset. There is the list of all trees obtained by a right rotate of This is the list of all trees obtained by a right rotate of one of its nodes. EXAMPLES:: The list of successors of:: |     __o__   | class BinaryTree(AbstractClonableTree, C h_{q} (T_1) h_{q} (T_2), where T is any nonempty binary tree, and T_1 and T_2 are the two children trees of the root of T, and where the two child trees of the root of T, and where \binom{a}{b}_q denotes a q-binomial coefficient. A variation of the q-hook length fraction is the following class BinaryTree(AbstractClonableTree, C tree self. Right rotation on binary trees is defined as follows: Let T be a nonempty binary tree such that the left child of the root of T is a node. Let C be the right Let T be a binary tree such that the left child of the root of T is a node. Let C be the right child of the root of T, and let A and B be the left and right children of the left child of the root of T. (Keep in mind that nodes of trees are identified with the subtrees consisting of their descendants.) Then, the right rotation of T is the nonempty binary tree in which the left child of the root is A, whereas Then, the right rotation of T is the binary tree in which the left child of the root is A, whereas the right child of the root is a node whose left and right children are B and C. In pictures:: class BinaryTree(AbstractClonableTree, C tree self. Left rotation on binary trees is defined as follows: Let T be a nonempty binary tree such that the right child of the root of T is a node. Let A be the left Let T be a binary tree such that the right child of the root of T is a node. Let A be the left child of the root of T, and let B and C be the left and right children of the right child of the root of T. (Keep in mind that nodes of trees are identified with the subtrees consisting of their descendants.) Then, the left rotation of T is the nonempty binary tree in which the right child of the root is C, whereas Then, the left rotation of T is the binary tree in which the right child of the root is C, whereas the left child of the root is a node whose left and right children are A and B. In pictures:: class BinaryTree(AbstractClonableTree, C If T and T' are two binary trees, then T over T' (written T / T') is defined as the tree obtained by grafting T' on the rightmost node of T. See section 4.5 of [HNT05]_. T' on the rightmost leaf of T. More precisely, T / T' is defined by identifying the root of the T' with the rightmost leaf of T. See section 4.5 of [HNT05]_. If T is empty, then T / T' = T'. .. TODO:: Fix this doc and figure out which of the different (inconsistent?) notations to follow. I don't see the "over" operation defined in [LodayRonco]_, although [HNT05]_ pretends that it is defined there. In [HNT05]_ the definition is somewhat vague about the order of the operads. Loday and Ronco seem to define I don't see the "over" operation defined in [LodayRonco]_, although [HNT05]_ pretends that it is defined there. Loday and Ronco seem to define "over" on page 2 of "Order structure on the algebra of permutations and of planar binary trees", but with a different choice of left/right. This is defined by:: Same for "under". EXAMPLES: Showing only the nodes of a binary tree, here is an example for the over operation: |   o       __o__       _o_         | |  / \  /  /     \  =  /   \        | class BinaryTree(AbstractClonableTree, C |                          \     /  | |                           o   o   | EXAMPLES:: A Sage example:: sage: b1 = BinaryTree([[],[[],[]]]) sage: b2 = BinaryTree([[None, []],[]]) class BinaryTree(AbstractClonableTree, C [     o       o ] [      \     /  ] [       o   o   ] The same in the labelled case: sage: b1 = b1.canonical_labelling() sage: b2 = b2.canonical_labelling() sage: ascii_art([b1.over(b2)]) [   _2_         ] [  /   \        ] [ 1     3       ] [        \      ] [       __3__   ] [      /     \  ] [     1       5 ] [      \     /  ] [       2   4   ] """ B = self.parent()._element_constructor_ if self.is_empty(): return bt lab = None if hasattr(self, "label"): lab = self.label() return B([self[0], self[1].over(bt)], lab) else: return B([self[0], self[1].over(bt)], lab) return B([self[0], self[1].over(bt)]) __div__ = over class BinaryTree(AbstractClonableTree, C The under (\backslash) operation defined by Loday-Ronco [LodayRonco]_. If T and T' are two binary trees, then T under T' (written T \ T') is defined as the tree obtained by grafting T on the leftmost leaf of T'. More precisely, T \ T' is defined by identifying the root of T with the leftmost leaf of T'. See section 4.5 of [HNT05]_. If T' is empty, then T \ T' = T. EXAMPLES:: Showing only the nodes of a binary tree, here is an example for the under operation: sage: b1 = BinaryTree([[],[]]) sage: b2 = BinaryTree([None,[]]) sage: ascii_art((b1, b2, b1 \ b2)) class BinaryTree(AbstractClonableTree, C [     o         ] [      \        ] [       o       ] The same in the labelled case: sage: b1 = b1.canonical_labelling() sage: b2 = b2.canonical_labelling() sage: ascii_art([b1.under(b2)]) [        2_     ] [       /  \    ] [      1    3   ] [     /      \  ] [   _2_       4 ] [  /   \        ] [ 1     5       ] [      /        ] [     3         ] [      \        ] [       4       ] """ B = self.parent()._element_constructor_ if bt.is_empty(): class BinaryTree(AbstractClonableTree, C lab = None if hasattr(bt, "label"): lab = bt.label() return B([self.under(bt[0]), bt[1]], lab) else: return B([self.under(bt[0]), bt[1]], lab) return B([self.under(bt[0]), bt[1]]) _backslash_ = under class BinaryTree(AbstractClonableTree, C \sigma whose binary search tree (a notion defined in [HNT05]_, Definition 7) is T after forgetting the labels. This is an equivalence class of the sylvester congruence (the congruence on words which sets two words uacvbw and ucavbw congruent words which holds two words uacvbw and ucavbw congruent whenever a, b, c are letters satisfying a \leq b < c, and extends by transitivity) on the symmetric group. class BinaryTree(AbstractClonableTree, C (only the nodes are drawn here). The binary search tree of a word is constructed by an RSK-like algorithm, in which the word is read from right to left. If a left-to-right reading is to be employed instead, the insertion algorithm which proceeds as follows: Start with an empty labelled binary tree, and read the word from left to right. Each time a letter is read from the word, insert this letter in the existing tree using binary search tree insertion (:meth:~sage.combinat.binary_tree.LabelledBinaryTree.binary_search_insert). If a left-to-right reading is to be employed instead, the left_to_right optional keyword variable should be set to True. class BinaryTree(AbstractClonableTree, C if self.is_empty(): yield [] return import itertools from itertools import product from sage.combinat.words.word import Word as W from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 \ as shuffle class BinaryTree(AbstractClonableTree, C builder = lambda i, p: list(p) + [i] shift = self[0].node_number() + 1 for l, r in itertools.product( self[0].sylvester_class(), self[1].sylvester_class()): for l, r in product(self[0].sylvester_class(), self[1].sylvester_class()): for p in shuffle(W(l), W([shift + ri for ri in r])): yield builder(shift, p) class BinaryTree(AbstractClonableTree, C r""" Return True if self is complete, else return False. A complete binary tree is a perfect binary tree except possibly in the last level. In a nutshell, a complete binary tree is a perfect binary tree except possibly in the last level, with all nodes in the last level "flush to the left". In more detail: A complete binary tree (also called binary heap) is a binary tree in which every level, except possibly the last one (the deepest), is completely filled. At depth n all nodes must be as far left as completely filled. At depth n, all nodes must be as far left as possible. For example:: class BinaryTrees(UniqueRepresentation, sage: BinaryTrees(2) Binary trees of size 2 .. NOTE:: this in a factory class whose constructor returns instances of .. NOTE:: this is a factory class whose constructor returns instances of subclasses. .. NOTE:: the fact that OrderedTrees is a class instead of a simple callable .. NOTE:: the fact that BinaryTrees is a class instead of a simple callable is an implementation detail. It could be changed in the future and one should not rely on it. """ class BinaryTrees(UniqueRepresentation, TEST:: sage: (BinaryTrees().leaf() is ...    sage.combinat.binary_tree.BinaryTrees_all().leaf()) ....:  sage.combinat.binary_tree.BinaryTrees_all().leaf()) True """ return self(None) class BinaryTrees_all(DisjointUnionEnume def unlabelled_trees(self): """ Return the set of unlabelled trees associated to self Return the set of unlabelled trees associated to self. EXAMPLES:: class BinaryTrees_all(DisjointUnionEnume def labelled_trees(self): """ Return the set of labelled trees associated to self Return the set of labelled trees associated to self. EXAMPLES:: class BinaryTrees_all(DisjointUnionEnume Element = BinaryTree from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from combinat import catalan_number ################################################################# # Enumerated set of binary trees of a given size ################################################################# class BinaryTrees_size(BinaryTrees): sage: BinaryTrees(5).cardinality() 42 """ from combinat import catalan_number return catalan_number(self._size) def __iter__(self): class BinaryTrees_size(BinaryTrees): @lazy_attribute def _parent_for(self): """ The parent of the element generated by self The parent of the elements generated by self. TESTS:: class LabelledBinaryTree(AbstractLabelle Labelled binary trees. A labelled binary tree is a binary tree (see :class:BinaryTree for the meaning of this) with a label assigned to each node. (The labels need not be integers, nor are they required to be distinct. None can be used as a label.) the meaning of this) with a label assigned to each node and leaf. The labels need not be integers, nor are they required to be distinct. None can be used as a label. INPUT: - children -- None (default) or a list, tuple or iterable of length 2 of labelled binary trees or convertible objects. This corresponds to the standard recursive definition of a labelled binary tree as given by a pair of: - either a leaf or a pair of labelled binary trees, - and a label. (The label is specified in the keyword variable label; see below.) Syntactic sugar allows leaving out all but the outermost calls of the LabelledBinaryTree() constructor, so that, e. g., LabelledBinaryTree([LabelledBinaryTree(None),LabelledBinaryTree(None)]) can be shortened to LabelledBinaryTree([None,None]). However, using this shorthand, it is impossible to label any vertex of the tree other than the root (because there is no way to pass a label variable without calling LabelledBinaryTree explicitly). It is also allowed to abbreviate [None, None] by [] if one does not want to label the leaves. - label -- (default: None) the label to be put on the root of this tree. - check -- (default: True) whether checkes should be performed or not. .. TODO:: Explain how to init these. Maybe allow LabelledBinaryTree() syntax for LabelledBinaryTree(None) (in analogy to BinaryTree class). EXAMPLE:: It is currently not possible to use LabelledBinaryTree() as a shorthand for LabelledBinaryTree(None) (in analogy to similar syntax in the BinaryTree class). EXAMPLES:: sage: LabelledBinaryTree(None) . sage: LabelledBinaryTree(None, label="ae") 'ae' sage: LabelledBinaryTree([]) None[., .] sage: LabelledBinaryTree([], label=3) 3[., .] sage: LabelledBinaryTree([None, None]) None[., .] sage: LabelledBinaryTree([None, None], label=5) 5[., .] sage: LabelledBinaryTree([None, []]) None[., None[., .]] sage: LabelledBinaryTree([None, []], label=4) 4[., None[., .]] sage: LabelledBinaryTree([[], None]) None[None[., .], .] sage: LabelledBinaryTree("[[], .]", label=False) False[None[., .], .] sage: LabelledBinaryTree([None, LabelledBinaryTree([None, None], label=4)], label=3) 3[., 4[., .]] sage: LabelledBinaryTree([None, BinaryTree([None, None])], label=3) 3[., None[., .]] sage: LabelledBinaryTree([[], None, []]) Traceback (most recent call last): ... ValueError: this is not a binary tree sage: LBT = LabelledBinaryTree sage: t1 = LBT([[LBT([], label=2), None], None], label=4); t1 4[None[2[., .], .], .] TESTS:: sage: t1 = LabelledBinaryTree([[None, [[],[[], None]]],[[],[]]]) sage: t2 = LabelledBinaryTree([[[],[]],[]]) sage: with t1.clone() as t1c: ....:     t1c[1,1,1] = t2 sage: t1 == t1c False """ __metaclass__ = ClasscallMetaclass class LabelledBinaryTree(AbstractLabelle def __classcall_private__(cls, *args, **opts): """ Ensure that trees created by the sets and directly are the same and that they are instances of :class:LabelledTree that they are instances of :class:LabelledTree. TESTS:: class LabelledBinaryTree(AbstractLabelle Labelled binary trees sage: LabelledBinaryTree([], label = 3).parent() Labelled binary trees """ """ return LabelledBinaryTrees() def _repr_(self): class LabelledBinaryTree(AbstractLabelle INPUT: - letter -- any object comparable with the label of self - letter -- any object comparable with the labels of self OUTPUT: class LabelledBinaryTree(AbstractLabelle inserted into it according to the binary search insertion algorithm. .. NOTE:: self is supposed to be a binary search tree. No check is performed. .. NOTE:: self is supposed to be a binary search tree. This is not being checked! A right strict binary search tree is defined to be a labelled binary tree such that for each node n with label x, every descendant of the left child of n has a label \leq x, and every descendant of the right child of n has a label > x. (Here, only nodes count as descendants, and every node counts as its own descendant too.) .. TODO:: Explain the algorithm. counts as its own descendant too.) Leaves are assumed to have no labels. Given a right strict binary search tree t and a letter i, the result of inserting i into t (denoted Ins(i, t) in the following) is defined recursively as follows: - If t is empty, then Ins(i, t) is the tree with one node only, and this node is labelled with i. - Otherwise, let j be the label of the root of t. If i > j, then Ins(i, t) is obtained by replacing the right child of t by Ins(i, r) in t, where r denotes the right child of t. If i \leq j, then Ins(i, t) is obtained by replacing the left child of t by Ins(i, l) in t, where l denotes the left child of t. See, for example, [HNT05]_ for properties of this algorithm. .. WARNING:: If t is nonempty, then inserting i into t does not change the root label of t. Hence, as opposed to algorithms like Robinson-Schensted-Knuth, binary search tree insertion involves no bumping. EXAMPLES:: The example from Fig. 2 of [HNT05]_:: sage: LBT = LabelledBinaryTree sage: x = LBT(None) sage: x . sage: x = x.binary_search_insert("b"); x b[., .] sage: x = x.binary_search_insert("d"); x b[., d[., .]] sage: x = x.binary_search_insert("e"); x b[., d[., e[., .]]] sage: x = x.binary_search_insert("a"); x b[a[., .], d[., e[., .]]] sage: x = x.binary_search_insert("b"); x b[a[., b[., .]], d[., e[., .]]] sage: x = x.binary_search_insert("d"); x b[a[., b[., .]], d[d[., .], e[., .]]] sage: x = x.binary_search_insert("a"); x b[a[a[., .], b[., .]], d[d[., .], e[., .]]] sage: x = x.binary_search_insert("c"); x b[a[a[., .], b[., .]], d[d[c[., .], .], e[., .]]] Other examples:: sage: LBT = LabelledBinaryTree sage: LBT(None).binary_search_insert(3) 3[., .] class LabelledBinaryTree(AbstractLabelle fils = self[1].binary_search_insert(letter) return LT([self[0], fils], label=self.label()) def semistandard_insert(self, letter): """ Return the result of inserting a letter letter into the semistandard tree self using the bumping algorithm. INPUT: - letter -- any object comparable with the labels of self OUTPUT: The semistandard tree self with letter inserted into it according to the bumping algorithm. .. NOTE:: self is supposed to be a semistandard tree. This is not being checked! A semistandard tree is defined to be a labelled binary tree such that for each node n with label x, every descendant of the left child of n has a label > x, and every descendant of the right child of n has a label \geq x. (Here, only nodes count as descendants, and every node counts as its own descendant too.) Leaves are assumed to have no labels. Given a semistandard tree t and a letter i, the result of inserting i into t (denoted Ins(i, t) in the following) is defined recursively as follows: - If t is empty, then Ins(i, t) is the tree with one node only, and this node is labelled with i. - Otherwise, let j be the label of the root of t. If i \geq j, then Ins(i, t) is obtained by replacing the right child of t by Ins(i, r) in t, where r denotes the right child of t. If i < j, then Ins(i, t) is obtained by replacing the label at the root of t by i, and replacing the left child of t by Ins(j, l) in t, where l denotes the left child of t. This algorithm is similar to the Robinson-Schensted-Knuth algorithm for semistandard Young tableaux. AUTHORS: - Darij Grinberg (10 Nov 2013). EXAMPLES:: sage: LBT = LabelledBinaryTree sage: x = LBT(None) sage: x . sage: x = x.semistandard_insert("b"); x b[., .] sage: x = x.semistandard_insert("d"); x b[., d[., .]] sage: x = x.semistandard_insert("e"); x b[., d[., e[., .]]] sage: x = x.semistandard_insert("a"); x a[b[., .], d[., e[., .]]] sage: x = x.semistandard_insert("b"); x a[b[., .], b[d[., .], e[., .]]] sage: x = x.semistandard_insert("d"); x a[b[., .], b[d[., .], d[e[., .], .]]] sage: x = x.semistandard_insert("a"); x a[b[., .], a[b[d[., .], .], d[e[., .], .]]] sage: x = x.semistandard_insert("c"); x a[b[., .], a[b[d[., .], .], c[d[e[., .], .], .]]] Other examples:: sage: LBT = LabelledBinaryTree sage: LBT(None).semistandard_insert(3) 3[., .] sage: LBT([], label = 1).semistandard_insert(3) 1[., 3[., .]] sage: LBT([], label = 3).semistandard_insert(1) 1[3[., .], .] sage: res = LBT(None) sage: for i in [3,1,5,2,4,6]: ....:     res = res.semistandard_insert(i) sage: res 1[3[., .], 2[5[., .], 4[., 6[., .]]]] """ LT = self.parent()._element_constructor_ if not self: return LT([], label = letter) else: root_label = self.label() if letter < root_label: fils = self[0].semistandard_insert(root_label) return LT([fils, self[1]], label=letter) else: fils = self[1].semistandard_insert(letter) return LT([self[0], fils], label=root_label) def right_rotate(self): r""" Return the result of right rotation applied to the labelled binary tree self. Right rotation on labelled binary trees is defined as follows: Let T be a nonempty labelled binary tree such that the left child of the root of T is a node. Let follows: Let T be a labelled binary tree such that the left child of the root of T is a node. Let C be the right child of the root of T, and let A and B be the left and right children of the left child of the root of T. (Keep in mind that nodes of trees are class LabelledBinaryTree(AbstractLabelle descendants.) Furthermore, let y be the label at the root of T, and x be the label at the left child of the root of T. Then, the right rotation of T is the nonempty labelled binary tree in which the root is labelled x, the left child of the root is A, whereas the right child of the root is a node labelled y whose left and right children are B and C. In pictures:: Then, the right rotation of T is the labelled binary tree in which the root is labelled x, the left child of the root is A, whereas the right child of the root is a node labelled y whose left and right children are B and C. In pictures:: |     y                      x     | |    / \                    / \    | class LabelledBinaryTree(AbstractLabelle x[A[., .], y[B[., .], C[., .]]] """ B = self.parent()._element_constructor_ return B([ self[0][0], B([self[0][1], self[1]], self.label()) ], self[0].label()) s0 = self[0] return B([s0[0], B([s0[1], self[1]], self.label())], s0.label()) def left_rotate(self): r""" class LabelledBinaryTree(AbstractLabelle binary tree self. Left rotation on labelled binary trees is defined as follows: Let T be a nonempty labelled binary tree such that the right child of the root of T is a node. Let follows: Let T be a labelled binary tree such that the right child of the root of T is a node. Let A be the left child of the root of T, and let B and C be the left and right children of the right child of the root of T. (Keep in mind that nodes of trees are class LabelledBinaryTree(AbstractLabelle descendants.) Furthermore, let x be the label at the root of T, and y be the label at the right child of the root of T. Then, the left rotation of T is the nonempty labelled binary tree in which the root is labelled y, the right child of the root is C, whereas the left child of the root is a node labelled x whose left and right children are A and B. In pictures:: Then, the left rotation of T is the labelled binary tree in which the root is labelled y, the right child of the root is C, whereas the left child of the root is a node labelled x whose left and right children are A and B. In pictures:: |     y                    x     | |    / \                  / \    | class LabelledBinaryTree(AbstractLabelle True """ B = self.parent()._element_constructor_ return B([ B([self[0], self[1][0]], self.label()), self[1][1] ], self[1].label()) s1 = self[1] return B([B([self[0], s1[0]], self.label()), s1[1]], s1.label()) def heap_insert(self, l): r""" Return the result of inserting a letter l into the binary heap (tree) self. Roughly, a binary heap will be a labelled complete binary tree such that for each node the label is greater or equal to the label of each of its children. A binary heap is a labelled complete binary tree such that for each node, the label at the node is greater or equal to the label of each of its child nodes. (More precisely, this is called a max-heap.) For example:: class LabelledBinaryTree(AbstractLabelle is a binary heap. See :wikipedia:Binary_heap#Insert for a description of how to insert a letter into a binary heap. The result is another binary heap. INPUT: - letter -- any object comparable with the label of self - letter -- any object comparable with the labels of self .. NOTE:: class LabelledBinaryTree(AbstractLabelle # we insert in L return B([L.heap_insert(label_insert), R], label_root) # else ==> dL == dR # if R is perfect we have to insert on the most left leaf # if R is perfect we have to insert on the leftmost leaf if R.is_perfect(): # ## TODO:: can be optimized... return B([L.heap_insert(label_insert), R], label_root) class LabelledBinaryTree(AbstractLabelle class LabelledBinaryTrees(LabelledOrderedTrees): """ This is a parent stub to serve as a factory class for trees with various labels constraints labels constraints. """ def _repr_(self): """ class LabelledBinaryTrees(LabelledOrdere def _an_element_(self): """ Return a labelled binary tree Return a labelled binary tree. EXAMPLE:: class LabelledBinaryTrees(LabelledOrdere def unlabelled_trees(self): """ Return the set of unlabelled trees associated to self Return the set of unlabelled trees associated to self. EXAMPLES:: class LabelledBinaryTrees(LabelledOrdere def labelled_trees(self): """ Return the set of labelled trees associated to self Return the set of labelled trees associated to self. EXAMPLES:: class LabelledBinaryTrees(LabelledOrdere #     sage: BTsp_to_bintrees(BT.isotypes(range(5))[0]) #     [., [., [., [., [., .]]]]] #     sage: def spls(size): #     ...    return map(BTsp_to_bintrees, BT.isotypes(range(size)).list()) #     ....:     return map(BTsp_to_bintrees, BT.isotypes(range(size)).list()) #     sage: spls(3) #     [[., [., [., .]]], [., [[., .], .]], [[., .], [., .]], [[., [., .]], .], [[[., .], .], .]] #     sage: all(spls(i) == BinaryTrees(i).list() for i in range(5))
• ## sage/combinat/ordered_tree.py

diff --git a/sage/combinat/ordered_tree.py b/sage/combinat/ordered_tree.py
 a class OrderedTree(AbstractClonableTree, @lazy_class_attribute def _auto_parent(cls): """ The automatic parent of the element of this class The automatic parent of the elements of this class. When calling the constructor of an element of this class, one needs a parent. This class attribute specifies which parent is used. class OrderedTrees(UniqueRepresentation, TEST:: sage: (OrderedTrees().leaf() is ...    sage.combinat.ordered_tree.OrderedTrees_all().leaf()) ....:     sage.combinat.ordered_tree.OrderedTrees_all().leaf()) True """ return self([]) class OrderedTrees_all(DisjointUnionEnum from sage.misc.lazy_attribute import lazy_attribute from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from combinat import catalan_number from sage.combinat.composition import Compositions from sage.combinat.cartesian_product import CartesianProduct ################################################################# class OrderedTrees_size(OrderedTrees): """ The cardinality of self This is a Catalan number This is a Catalan number. TESTS:: class OrderedTrees_size(OrderedTrees): if self._size == 0: return Integer(0) else: from combinat import catalan_number return catalan_number(self._size-1) def __iter__(self): class OrderedTrees_size(OrderedTrees): class LabelledOrderedTree(AbstractLabelledClonableTree, OrderedTree): """ Labelled ordered trees Labelled ordered trees. A labelled ordered tree is an ordered tree with a label attached at each node. class LabelledOrderedTree(AbstractLabell @lazy_class_attribute def _auto_parent(cls): """ The automatic parent of the element of this class The automatic parent of the elements of this class. When calling the constructor of an element of this class, one needs a parent. This class attribute specifies which parent is used. class LabelledOrderedTree(AbstractLabell Labelled ordered trees sage: LabelledOrderedTree([], label = 3).parent() Labelled ordered trees """ """ return LabelledOrderedTrees() _UnLabelled = OrderedTree from sage.rings.infinity import Infinity class LabelledOrderedTrees(UniqueRepresentation, Parent): """ This is a parent stub to serve as a factory class for trees with various labels constraints label constraints. EXAMPLES:: class LabelledOrderedTrees(UniqueReprese def cardinality(self): """ Return the cardinality of self Return the cardinality of self. EXAMPLE::
• ## sage/combinat/tools.py

diff --git a/sage/combinat/tools.py b/sage/combinat/tools.py
 a Tools #***************************************************************************** def transitive_ideal(f, x): """ Given an initial value x and a successor function f, return a list containing x and all of its successors. The successor function should return a list of all the successors of f. Note that if x has an infinite number of successors, transitive_ideal won't return. r""" Return a list of all elements reachable from x in the abstract reduction system whose reduction relation is given by the function f. In more elementary terms: If S is a set, and f is a function sending every element of S to a list of elements of S, then we can define a digraph on the vertex set S by drawing an edge from s to t for every s \in S and every t \in f(s). If x \in S, then an element y \in S is said to be reachable from x if there is a path x \to y in this graph. Given f and x, this method computes the list of all elements of S reachable from x. Note that if there are infinitely many such elements, then this method will never halt. EXAMPLES:: sage: f = lambda x: [x-1] if x > 0 else [] sage: sage.combinat.tools.transitive_ideal(f, 10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
• ## sage/combinat/words/shuffle_product.py

diff --git a/sage/combinat/words/shuffle_product.py b/sage/combinat/words/shuffle_product.py
 a from sage.combinat.composition import Co class ShuffleProduct_w1w2(CombinatorialClass): def __init__(self, w1, w2): """ r""" The shuffle product of the two words w1 and w2. If u and v are two words, then the *shuffle product* of u and v is a certain multiset of words defined as follows: Let a and b be the lengths of u and v, respectively. For every a-element subset I of \{1, 2, \cdots, a+b\}, let w(I) be the length-a+b word such that: - for every 1 \leq k \leq a, the i_k-th letter of w(I) is the k-th letter of u, where i_k is the k-th smallest element of I; - for every 1 \leq l \leq b, the j_l-th letter of w(I) is the l-th letter of v, where j_l is the l-th smallest element of \{1, 2, \cdots, a+b\} \setminus I. The shuffle product of u and v is then the multiset of all w(I) with I ranging over the a-element subsets of \{1, 2, \cdots, a+b\}. EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 sage: W = Words([1,2,3,4]) sage: s = ShuffleProduct_w1w2(W([1,2]),W([3,4])) sage: sorted(list(s)) [word: 1234, word: 1324, word: 1342, word: 3124, word: 3142, word: 3412] sage: s == loads(dumps(s)) True sage: s = ShuffleProduct_w1w2(W([1,4,3]),W([2])) sage: sorted(list(s)) [word: 1243, word: 1423, word: 1432, word: 2143] sage: s = ShuffleProduct_w1w2(W([1,4,3]),W([])) sage: sorted(list(s)) [word: 143] """ self._w1 = w1 self._w2 = w2 class ShuffleProduct_w1w2(CombinatorialC return len(wx) == 0 def cardinality(self): """ Returns the number of words in the shuffle product of w1 and w2. r""" Return the number of words in the shuffle product of w1 and w2. It is given by binomial(len(w1)+len(w2), len(w1)). It is given by \binom{l_1+l_2}{l_1}, where l_1 is the length of w1 and where l_2 is the length of w2. EXAMPLES:: class ShuffleProduct_shifted(ShuffleProd class ShuffleProduct_overlapping_r(CombinatorialClass): def __init__(self, w1, w2, r): """ The overlapping shuffle product of the two words w1 and w2 with precisely r overlaps. See :class:ShuffleProduct_overlapping for a definition. EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r sage: w, u = map(Words("abcdef"), ["ab", "cd"]) sage: w, u = map(Words(range(20)), [[2, 9], [9, 1]]) sage: S = ShuffleProduct_overlapping_r(w,u,1) sage: S == loads(dumps(S)) True class ShuffleProduct_overlapping_r(Combi EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r sage: w, u = map(Words("abcdef"), ["ab", "cd"]) sage: w, u = map(Words(range(20)), [[2, 9], [9, 1]]) sage: ShuffleProduct_overlapping_r(w,u,1).__repr__() 'Overlapping shuffle product of word: ab and word: cd with 1 overlaps' 'Overlapping shuffle product of word: 29 and word: 91 with 1 overlaps' """ return "Overlapping shuffle product of %s and %s with %s overlaps"%(repr(self._w1), repr(self._w2), self.r) class ShuffleProduct_overlapping_r(Combi class ShuffleProduct_overlapping(CombinatorialClass): def __init__(self, w1, w2): """ r""" The overlapping shuffle product of the two words w1 and w2. If u and v are two words whose letters belong to an additive monoid or to another kind of alphabet on which addition is well-defined, then the *overlapping shuffle product* of u and v is a certain multiset of words defined as follows: Let a and b be the lengths of u and v, respectively. Let A be the set \{(0, 1), (0, 2), \cdots, (0, a)\}, and let B be the set \{(1, 1), (1, 2), \cdots, (1, b)\}. Notice that the sets A and B are disjoint. Let p be the map from A \cup B to the set of all letters which sends every (0, i) to the i-th letter of u, and every (1, j) to the j-th letter of v. For every nonnegative integer c and every surjective map f : A \cup B \to \{ 1, 2, \cdots, c \} for which both restrictions f \mid_A and f \mid_B are injective, let w(f) be the length-c word such that for every 1 \leq k \leq c, the k-th letter of w(f) equals \sum_{j \in f^{-1}(k)} p(j) (this sum always has either one or two addends). The overlapping shuffle product of u and v is then the multiset of all w(f) with c ranging over all nonnegative integers and f ranging over the surjective maps f : A \cup B \to \{ 1, 2, \cdots, c \} for which both restrictions f \mid_A and f \mid_B are injective. If one restricts c to a particular fixed nonnegative integer, then the multiset is instead called the *overlapping shuffle product with precisely a + b - c overlaps*. This is nonempty only if \max \{a, b\} \leq c \leq a + b. If c = a + b, then the overlapping shuffle product with precisely a + b - c overlaps is plainly the shuffle product (:class:ShuffleProduct_w1w2). EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping sage: w, u = map(Words("abcdef"), ["ab", "cd"]) sage: w, u = map(Words(range(20)), [[2, 9], [9, 1]]) sage: S = ShuffleProduct_overlapping(w,u) sage: sorted([list(i) for i in list(S)]) [[2, 9, 1, 9], [2, 9, 9, 1], [2, 9, 9, 1], [2, 9, 10], [2, 18, 1], [9, 1, 2, 9], [9, 2, 1, 9], [9, 2, 9, 1], [9, 2, 10], [9, 3, 9], [11, 1, 9], [11, 9, 1], [11, 10]] sage: S == loads(dumps(S)) True """ class ShuffleProduct_overlapping(Combina EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping sage: w, u = map(Words("abcdef"), ["ab", "cd"]) sage: w, u = map(Words(range(20)), [[2, 9], [9, 1]]) sage: ShuffleProduct_overlapping(w,u).__repr__() 'Overlapping shuffle product of word: ab and word: cd' 'Overlapping shuffle product of word: 29 and word: 91' """ return "Overlapping shuffle product of %s and %s"%(repr(self._w1), repr(self._w2))