# HG changeset patch
# User darij grinberg
# Date 1384130170 28800
# Node ID d1916f255d1147726cbfea1082543d454c6708f3
# Parent 10f4f08eea2cf27bf045363c7bf6a4fd00b13377
trac #14498: Darij's review patch, to be applied ATOP of trac_14498algorithms_treesrebased.patch and trac_14498treeimpsdgrebased.patch
diff git a/sage/combinat/abstract_tree.py b/sage/combinat/abstract_tree.py
 a/sage/combinat/abstract_tree.py
+++ b/sage/combinat/abstract_tree.py
@@ 66,20 +66,14 @@ 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.
@@ 97,7 +91,7 @@ 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,
@@ 118,7 +112,15 @@ class AbstractTree(object):
The depthfirst preorder traversal iterator.
This method iters each node following the depthfirst preorder
 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`::
@@ 130,13 +132,9 @@ class AbstractTree(object):
 / \ 
 4 6 
 the ``depthfirst preorder 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 depthfirst preorder traversal
+ algorithm explores `b` in the following order of nodes:
+ `3,1,2,7,5,4,6,8`.
Another example::
@@ 148,8 +146,8 @@ 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::
@@ 164,6 +162,7 @@ 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____ ]
@@ 175,6 +174,22 @@ 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
@@ 191,13 +206,23 @@ class AbstractTree(object):
def iterative_pre_order_traversal(self, action=None):
r"""
 The depthfirst preorder traversal algorithm (iterative
 implementation).
+ Run the depthfirst preorder 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::
@@ 213,6 +238,7 @@ 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[]]]
@@ 221,6 +247,7 @@ 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
@@ 229,6 +256,20 @@ 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
@@ 246,15 +287,27 @@ class AbstractTree(object):
def pre_order_traversal(self, action=None):
r"""
 The depthfirst preorder traversal algorithm (recursive
 implementation).
+ Run the depthfirst preorder 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____ 
 / \ 
@@ 264,13 +317,8 @@ class AbstractTree(object):
 / \ 
 4 6 
 the ``depthfirst preorder 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 depthfirst preorder traversal algorithm explores `b` in the
+ following order of nodes: `3,1,2,7,5,4,6,8`.
Another example::
@@ 303,6 +351,7 @@ 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[]]]
@@ 314,6 +363,7 @@ 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()))
@@ 323,6 +373,20 @@ 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
@@ 334,7 +398,15 @@ class AbstractTree(object):
The depthfirst postorder traversal iterator.
This method iters each node following the depthfirst postorder
 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`::
@@ 346,15 +418,11 @@ class AbstractTree(object):
 / \ 
 4 6 
 the ``depthfirst postorder traversal algorithm`` explores `b` in the
 following order of nodes `2,1,4,6,5,8,7,3`.
+ (only the nodes are shown), the depthfirst postorder 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____ 
 / / / 
@@ 380,6 +448,7 @@ 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____ ]
@@ 391,12 +460,26 @@ 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
@@ 413,13 +496,23 @@ class AbstractTree(object):
def post_order_traversal(self, action=None):
r"""
 The depthfirst postorder traversal algorithm (recursive
 implementation).
+ Run the depthfirst postorder 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::
@@ 435,6 +528,7 @@ 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[]]]
@@ 442,6 +536,7 @@ 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()))
@@ 451,6 +546,20 @@ 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
@@ 459,13 +568,23 @@ class AbstractTree(object):
def iterative_post_order_traversal(self, action=None):
r"""
 The depthfirst postorder traversal algorithm (iterative
 implementation).
+ Run the depthfirst postorder 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::
@@ 479,14 +598,16 @@ 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(
@@ 498,30 +619,66 @@ 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 breadthfirst order traversal algorithm.
+ Run the breadthfirst postorder 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`::
@@ 533,17 +690,9 @@ class AbstractTree(object):
 / \ 
 4 6 
 the ``breadthfirst order traversal algorithm`` explores `b` in the
+ the breadthfirst 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()
@@ 551,6 +700,7 @@ 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[]]]
@@ 558,6 +708,7 @@ 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(
@@ 585,9 +736,12 @@ 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::
@@ 596,9 +750,16 @@ 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([[], [[], [[], []], [[], []]], [[], []]])
@@ 619,10 +780,12 @@ 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
+ zerobased).
The root element is represented by the empty tuple ``()``.
@@ 655,7 +818,7 @@ class AbstractTree(object):
def node_number(self):
"""
 The number of nodes of ``self``
+ The number of nodes of ``self``.
EXAMPLES::
@@ 670,7 +833,7 @@ class AbstractTree(object):
sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).node_number()
13
 EXAMPLE::
+ EXAMPLES::
sage: BinaryTree(None).node_number()
0
@@ 688,7 +851,7 @@ class AbstractTree(object):
def depth(self):
"""
 The depth of ``self``
+ The depth of ``self``.
EXAMPLES::
@@ 826,7 +989,7 @@ 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
@@ 859,7 +1022,7 @@ class AbstractTree(object):
def tree_factorial(self):
"""
 Return the treefactorial of ``self``
+ Return the treefactorial of ``self``.
Definition:
@@ 888,7 +1051,7 @@ class AbstractTree(object):
def _latex_(self):
r"""
 Nice output which can be easily modified
+ Generate `\LaTeX` output which can be easily modified.
TESTS::
@@ 911,6 +1074,12 @@ 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}"
@@ 1249,48 +1418,49 @@ 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::
@@ 1332,7 +1502,7 @@ class AbstractClonableTree(AbstractTree)
sage: x = OrderedTree([[],[[]]])
sage: with x.clone() as x:
 ... x[0] = OrderedTree([[]])
+ ....: x[0] = OrderedTree([[]])
sage: x
[[[]], [[]]]
@@ 1340,13 +1510,13 @@ 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
[[], [[]]]
@@ 1355,7 +1525,7 @@ 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
[[[[[., .], [., .]], .], .], [[., .], [., .]]]
@@ 1363,14 +1533,14 @@ 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
[[[], [[], []]], [[[], []], [[], []]]]
"""
@@ 1387,7 +1557,7 @@ 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
[[[], [[[]]]], [[]]]
"""
@@ 1441,10 +1611,10 @@ 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 ?
@@ 1453,7 +1623,8 @@ 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
@@ 1464,9 +1635,11 @@ 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):
@@ 1736,7 +1909,7 @@ 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
@@ 1750,7 +1923,7 @@ 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
@@ 1759,14 +1932,14 @@ 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
@@ 1797,11 +1970,11 @@ 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[]]]
diff git a/sage/combinat/binary_tree.py b/sage/combinat/binary_tree.py
 a/sage/combinat/binary_tree.py
+++ b/sage/combinat/binary_tree.py
@@ 1,6 +1,6 @@
# * coding: utf8 *
"""
Binary Trees
+Binary Trees.
This module deals with binary trees as mathematical (in particular immutable)
objects.
@@ 16,7 +16,7 @@ AUTHORS:
REFERENCES:
.. [LodayRonco] JeanLouis Loday and MarĂa O. Ronco.
+.. [LodayRonco] JeanLouis Loday and Maria O. Ronco.
*Hopf algebra of the planar binary trees*,
Advances in Mathematics, volume 139, issue 2,
10 November 1998, pp. 293309.
@@ 26,7 +26,7 @@ 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`.
"""
@@ 57,7 +57,7 @@ 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:
@@ 67,10 +67,10 @@ 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::
@@ 89,6 +89,8 @@ class BinaryTree(AbstractClonableTree, C
[[., .], .]
sage: BinaryTree("[[], .]")
[[., .], .]
+ sage: BinaryTree([None, BinaryTree([None, None])])
+ [., [., .]]
sage: BinaryTree([[], None, []])
Traceback (most recent call last):
@@ 100,7 +102,7 @@ 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
"""
@@ 493,7 +495,7 @@ 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])
@@ 539,10 +541,10 @@ 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
@@ 575,7 +577,13 @@ 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::
@@ 1220,8 +1228,9 @@ class BinaryTree(AbstractClonableTree, C
The depthfirst infixorder traversal iterator for the binary
tree ``self``.
 This method iters each vertex (node and leaf alike) following the
 depthfirst infix order traversal algorithm.
+ This method iters each vertex (node and leaf alike) of the given
+ binary tree following the depthfirst infix order traversal
+ algorithm.
The *depthfirst infix order traversal algorithm* iterates
through a binary tree as follows::
@@ 1276,6 +1285,9 @@ class BinaryTree(AbstractClonableTree, C
[ 1 4 3 5 ]
[ / \ ]
[ 3 5, , , ]
+
+ sage: list(BinaryTree(None).in_order_traversal_iter())
+ [.]
"""
if self.is_empty():
yield self
@@ 1348,9 +1360,11 @@ 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
[[., .], [[., .], [., .]]]
@@ 1366,6 +1380,7 @@ 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(_):
@@ 1395,7 +1410,7 @@ 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
@@ 1407,6 +1422,8 @@ 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__ 
@@ 1463,9 +1480,12 @@ 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__ 
@@ 1510,7 +1530,19 @@ 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 welldefined 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::
@@ 1552,9 +1584,12 @@ 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__ 
@@ 1632,7 +1667,7 @@ 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
@@ 1792,14 +1827,14 @@ 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::
@@ 1879,14 +1914,14 @@ 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::
@@ 1952,21 +1987,27 @@ 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_ 
 / \ / / \ = / \ 
@@ 1978,7 +2019,7 @@ class BinaryTree(AbstractClonableTree, C
 \ / 
 o o 
 EXAMPLES::
+ A Sage example::
sage: b1 = BinaryTree([[],[[],[]]])
sage: b2 = BinaryTree([[None, []],[]])
@@ 2017,15 +2058,30 @@ 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
@@ 2035,8 +2091,19 @@ class BinaryTree(AbstractClonableTree, C
The ``under`` (`\backslash`) operation defined by LodayRonco
[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))
@@ 2074,6 +2141,23 @@ 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():
@@ 2081,8 +2165,9 @@ 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
@@ 2095,7 +2180,7 @@ 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.
@@ 2109,8 +2194,12 @@ class BinaryTree(AbstractClonableTree, C
(only the nodes are drawn here).
The binary search tree of a word is constructed by an RSKlike
 algorithm, in which the word is read from right to left. If a
 lefttoright 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 lefttoright reading is to be employed instead, the
``left_to_right`` optional keyword variable should be set to
``True``.
@@ 2153,7 +2242,7 @@ 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
@@ 2164,9 +2253,8 @@ 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)
@@ 2271,12 +2359,14 @@ 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::
@@ 2388,10 +2478,10 @@ 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.
"""
@@ 2432,7 +2522,7 @@ 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)
@@ 2502,7 +2592,7 @@ 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::
@@ 2513,7 +2603,7 @@ 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::
@@ 2539,7 +2629,6 @@ 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
#################################################################
@@ 2609,6 +2698,7 @@ class BinaryTrees_size(BinaryTrees):
sage: BinaryTrees(5).cardinality()
42
"""
+ from combinat import catalan_number
return catalan_number(self._size)
def __iter__(self):
@@ 2637,7 +2727,7 @@ 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::
@@ 2688,23 +2778,91 @@ 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
@@ 2712,7 +2870,7 @@ 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::
@@ 2740,7 +2898,7 @@ class LabelledBinaryTree(AbstractLabelle
Labelled binary trees
sage: LabelledBinaryTree([], label = 3).parent()
Labelled binary trees
 """
+ """
return LabelledBinaryTrees()
def _repr_(self):
@@ 2768,7 +2926,7 @@ class LabelledBinaryTree(AbstractLabelle
INPUT:
  ``letter``  any object comparable with the label of ``self``
+  ``letter``  any object comparable with the labels of ``self``
OUTPUT:
@@ 2776,22 +2934,67 @@ 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 RobinsonSchenstedKnuth, 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[., .]
@@ 2816,14 +3019,110 @@ 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 RobinsonSchenstedKnuth
+ 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
@@ 2831,11 +3130,11 @@ 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 
 / \ / \ 
@@ 2855,10 +3154,8 @@ 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"""
@@ 2866,8 +3163,8 @@ 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
@@ 2875,11 +3172,11 @@ 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 
 / \ / \ 
@@ 2899,19 +3196,18 @@ 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 maxheap.)
For example::
@@ 2923,9 +3219,13 @@ 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::
@@ 2979,7 +3279,7 @@ 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)
@@ 2992,7 +3292,7 @@ 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):
"""
@@ 3005,7 +3305,7 @@ class LabelledBinaryTrees(LabelledOrdere
def _an_element_(self):
"""
 Return a labelled binary tree
+ Return a labelled binary tree.
EXAMPLE::
@@ 3020,7 +3320,7 @@ 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::
@@ 3044,7 +3344,7 @@ 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::
@@ 3078,7 +3378,7 @@ 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))
diff git a/sage/combinat/ordered_tree.py b/sage/combinat/ordered_tree.py
 a/sage/combinat/ordered_tree.py
+++ b/sage/combinat/ordered_tree.py
@@ 200,7 +200,7 @@ 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.
@@ 574,7 +574,7 @@ 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([])
@@ 675,7 +675,6 @@ 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
#################################################################
@@ 741,7 +740,7 @@ class OrderedTrees_size(OrderedTrees):
"""
The cardinality of ``self``
 This is a Catalan number
+ This is a Catalan number.
TESTS::
@@ 755,6 +754,7 @@ class OrderedTrees_size(OrderedTrees):
if self._size == 0:
return Integer(0)
else:
+ from combinat import catalan_number
return catalan_number(self._size1)
def __iter__(self):
@@ 833,7 +833,7 @@ 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.
@@ 878,7 +878,7 @@ 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.
@@ 889,7 +889,7 @@ class LabelledOrderedTree(AbstractLabell
Labelled ordered trees
sage: LabelledOrderedTree([], label = 3).parent()
Labelled ordered trees
 """
+ """
return LabelledOrderedTrees()
_UnLabelled = OrderedTree
@@ 899,7 +899,7 @@ 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::
@@ 935,7 +935,7 @@ class LabelledOrderedTrees(UniqueReprese
def cardinality(self):
"""
 Return the cardinality of `self`
+ Return the cardinality of `self`.
EXAMPLE::
diff git a/sage/combinat/tools.py b/sage/combinat/tools.py
 a/sage/combinat/tools.py
+++ b/sage/combinat/tools.py
@@ 17,16 +17,26 @@ 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: [x1] if x > 0 else []
sage: sage.combinat.tools.transitive_ideal(f, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
diff git a/sage/combinat/words/shuffle_product.py b/sage/combinat/words/shuffle_product.py
 a/sage/combinat/words/shuffle_product.py
+++ b/sage/combinat/words/shuffle_product.py
@@ 25,14 +25,45 @@ 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
@@ 95,11 +126,12 @@ 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::
@@ 224,10 +256,15 @@ 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
@@ 246,9 +283,9 @@ 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)
@@ 321,12 +358,62 @@ 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 welldefined, 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
"""
@@ 338,9 +425,9 @@ 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))