Abstract Recursive Trees¶
The purpose of this class is to help implement trees with a specific structure
on the children of each node. For instance, one could want to define a tree in
which each node sees its children as linearly (see the Ordered Trees module) or cyclically ordered.
Tree structures
Conceptually, one can define a tree structure from any object that can contain others. Indeed, a list can contain lists which contain lists which contain lists, and thus define a tree … The same can be done with sets, or any kind of iterable objects.
While any iterable is sufficient to encode trees, it can prove useful to have
other methods available like isomorphism tests (see next section), conversions
to DiGraphs objects (see as_digraph()) or
computation of the number of automorphisms constrained by the structure on
children. Providing such methods is the whole purpose of the
AbstractTree class.
As a result, the AbstractTree class is not meant to be
instantiated, but extended. It is expected that classes extending this one may
also inherit from classes representing iterables, for instance
ClonableArray or ClonableList
Constrained Trees
The tree built from a specific container will reflect the properties of the
container. Indeed, if A is an iterable class whose elements are linearly
ordered, a class B extending both of AbstractTree and A will
be such that the children of a node will be linearly ordered. If A behaves
like a set (i.e. if there is no order on the elements it contains), then two
trees will be considered as equal if one can be obtained from the other
through permutations between the children of a same node (see next section).
Paths and ID
It is expected that each element of a set of children should be identified by its index in the container. This way, any node of the tree can be identified by a word describing a path from the root node.
Canonical labellings
Equality between instances of classes extending both AbstractTree
and A is entirely defined by the equality defined on the elements of
A. A canonical labelling of such a tree, however, should be such that
two trees a and b satisfying a == b have the same canonical
labellings. On the other hand, the canonical labellings of trees a and
b satisfying a != b are expected to be different.
For this reason, the values returned by the canonical_labelling method heavily
depend on the data structure used for a node’s children and should be
overridden by most of the classes extending AbstractTree if it is
incoherent with the data structure.
Authors
- Florent Hivert (2010-2011): initial revision 
- Frédéric Chapoton (2011): contributed some methods 
- class sage.combinat.abstract_tree.AbstractClonableTree[source]¶
- Bases: - AbstractTree- Abstract Clonable Tree. - An abstract class for trees with clone protocol (see - list_clone). It is expected that classes extending this one may also inherit from classes like- ClonableArrayor- ClonableListdepending 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 - ClonableElement, because it would prevent us from later inheriting from- ClonableArrayor- ClonableList.- How should this class be extended ? - A class extending - AbstractClonableTreeshould satisfy the following assumptions:- An instantiable class extending - AbstractClonableTreeshould also extend the- ClonableElementclass or one of its subclasses generally, at least- ClonableArray.
- To respect the Clone protocol, the - AbstractClonableTree.check()method should be overridden by the new class.
 - See also the assumptions in - AbstractTree.- check()[source]¶
- Check that - selfis a correct tree.- This method does nothing. It is implemented here because many extensions of - AbstractClonableTreealso extend- sage.structure.list_clone.ClonableElement, which requires it.- 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: - sage: OrderedTree([[],[[]]]).check() sage: BinaryTree([[],[[],[]]]).check() - >>> from sage.all import * >>> OrderedTree([[],[[]]]).check() >>> BinaryTree([[],[[],[]]]).check() 
 
- class sage.combinat.abstract_tree.AbstractLabelledClonableTree(parent, children, label=None, check=True)[source]¶
- Bases: - AbstractLabelledTree,- AbstractClonableTree- Abstract Labelled Clonable Tree. - This class takes care of modification for the label by the clone protocol. - Note - Due to the limitation of Cython inheritance, one cannot inherit here from - ClonableArray, because it would prevent us to inherit later from- ClonableList.- map_labels(f)[source]¶
- Apply the function \(f\) to the labels of - self.- This method returns a copy of - selfon which the function \(f\) has been applied on all labels (a label \(x\) is replaced by \(f(x)\)).- EXAMPLES: - sage: LT = LabelledOrderedTree sage: t = LT([LT([],label=1),LT([],label=7)],label=3); t 3[1[], 7[]] sage: t.map_labels(lambda z:z+1) 4[2[], 8[]] sage: LBT = LabelledBinaryTree sage: bt = LBT([LBT([],label=1),LBT([],label=4)],label=2); bt 2[1[., .], 4[., .]] sage: bt.map_labels(lambda z:z+1) 3[2[., .], 5[., .]] - >>> from sage.all import * >>> LT = LabelledOrderedTree >>> t = LT([LT([],label=Integer(1)),LT([],label=Integer(7))],label=Integer(3)); t 3[1[], 7[]] >>> t.map_labels(lambda z:z+Integer(1)) 4[2[], 8[]] >>> LBT = LabelledBinaryTree >>> bt = LBT([LBT([],label=Integer(1)),LBT([],label=Integer(4))],label=Integer(2)); bt 2[1[., .], 4[., .]] >>> bt.map_labels(lambda z:z+Integer(1)) 3[2[., .], 5[., .]] 
 - set_label(path, label)[source]¶
- Change the label of subtree indexed by - pathto- label.- INPUT: - path–- None(default) or a path (list or tuple of children index in the tree)
- label– any sage object
 - OUTPUT: nothing, - selfis modified in place- Note - selfmust be in a mutable state. See- sage.structure.list_clonefor more details about mutability.- EXAMPLES: - sage: t = LabelledOrderedTree([[],[[],[]]]) sage: t.set_label((0,), 4) Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. sage: with t.clone() as t: ....: 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) sage: t None[4[], None[42[], None[]]] - >>> from sage.all import * >>> t = LabelledOrderedTree([[],[[],[]]]) >>> t.set_label((Integer(0),), Integer(4)) Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. >>> with t.clone() as t: ... t.set_label((Integer(0),), Integer(4)) >>> t None[4[], None[None[], None[]]] >>> with t.clone() as t: ... t.set_label((Integer(1),Integer(0)), label = Integer(42)) >>> t None[4[], None[42[], None[]]] - Todo - Do we want to implement the following syntactic sugar: - with t.clone() as tt: tt.labels[1,2] = 3 ? 
 - set_root_label(label)[source]¶
- Set the label of the root of - self.- INPUT: - label– any Sage object
 - OUTPUT: none, - selfis modified in place- Note - selfmust be in a mutable state. See- sage.structure.list_clonefor more details about mutability.- EXAMPLES: - sage: t = LabelledOrderedTree([[],[[],[]]]) sage: t.set_root_label(3) Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. sage: with t.clone() as t: ....: t.set_root_label(3) sage: t.label() 3 sage: t 3[None[], None[None[], None[]]] - >>> from sage.all import * >>> t = LabelledOrderedTree([[],[[],[]]]) >>> t.set_root_label(Integer(3)) Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. >>> with t.clone() as t: ... t.set_root_label(Integer(3)) >>> t.label() 3 >>> t 3[None[], None[None[], None[]]] - This also works for binary trees: - sage: bt = LabelledBinaryTree([[],[]]) sage: bt.set_root_label(3) Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. sage: with bt.clone() as bt: ....: bt.set_root_label(3) sage: bt.label() 3 sage: bt 3[None[., .], None[., .]] - >>> from sage.all import * >>> bt = LabelledBinaryTree([[],[]]) >>> bt.set_root_label(Integer(3)) Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. >>> with bt.clone() as bt: ... bt.set_root_label(Integer(3)) >>> bt.label() 3 >>> bt 3[None[., .], None[., .]] 
 
- class sage.combinat.abstract_tree.AbstractLabelledTree(parent, children, label=None, check=True)[source]¶
- Bases: - AbstractTree- Abstract Labelled Tree. - Typically a class for labelled trees is constructed by inheriting from a class for unlabelled trees and - AbstractLabelledTree.- How should this class be extended ? - A class extending - AbstractLabelledTreeshould respect the following assumptions:- For a labelled tree - Tthe call- T.parent().unlabelled_trees()should return a parent for unlabelled trees of the same kind: for example,- if - Tis a binary labelled tree,- T.parent()is- LabelledBinaryTrees()and- T.parent().unlabelled_trees()is- BinaryTrees()
- if - Tis an ordered labelled tree,- T.parent()is- LabelledOrderedTrees()and- T.parent().unlabelled_trees()is- OrderedTrees()
 
- In the same vein, the class of - Tshould contain an attribute- _UnLabelledwhich should be the class for the corresponding unlabelled trees.
 - See also the assumptions in - AbstractTree.- See also - as_digraph()[source]¶
- Return a directed graph version of - self.- Warning - At this time, the output makes sense only if - selfis a labelled binary tree with no repeated labels and no- Nonelabels.- EXAMPLES: - sage: LT = LabelledOrderedTrees() sage: t1 = LT([LT([],label=6),LT([],label=1)],label=9) sage: t1.as_digraph() Digraph on 3 vertices sage: t = BinaryTree([[None, None],[[],None]]) sage: lt = t.canonical_labelling() sage: lt.as_digraph() Digraph on 4 vertices - >>> from sage.all import * >>> LT = LabelledOrderedTrees() >>> t1 = LT([LT([],label=Integer(6)),LT([],label=Integer(1))],label=Integer(9)) >>> t1.as_digraph() Digraph on 3 vertices >>> t = BinaryTree([[None, None],[[],None]]) >>> lt = t.canonical_labelling() >>> lt.as_digraph() Digraph on 4 vertices 
 - label(path=None)[source]¶
- Return the label of - self.- INPUT: - path–- None(default) or a path (list or tuple of children index in the tree)
 - OUTPUT: the label of the subtree indexed by - path- EXAMPLES: - sage: t = LabelledOrderedTree([[],[]], label = 3) sage: t.label() 3 sage: t[0].label() sage: t = LabelledOrderedTree([LabelledOrderedTree([], 5),[]], label = 3) sage: t.label() 3 sage: t[0].label() 5 sage: t[1].label() sage: t.label([0]) 5 - >>> from sage.all import * >>> t = LabelledOrderedTree([[],[]], label = Integer(3)) >>> t.label() 3 >>> t[Integer(0)].label() >>> t = LabelledOrderedTree([LabelledOrderedTree([], Integer(5)),[]], label = Integer(3)) >>> t.label() 3 >>> t[Integer(0)].label() 5 >>> t[Integer(1)].label() >>> t.label([Integer(0)]) 5 
 - labels()[source]¶
- Return the list of labels of - self.- EXAMPLES: - sage: LT = LabelledOrderedTree sage: t = LT([LT([],label='b'),LT([],label='c')],label='a') sage: t.labels() ['a', 'b', 'c'] sage: LBT = LabelledBinaryTree sage: LBT([LBT([],label=1),LBT([],label=4)],label=2).labels() [2, 1, 4] - >>> from sage.all import * >>> LT = LabelledOrderedTree >>> t = LT([LT([],label='b'),LT([],label='c')],label='a') >>> t.labels() ['a', 'b', 'c'] >>> LBT = LabelledBinaryTree >>> LBT([LBT([],label=Integer(1)),LBT([],label=Integer(4))],label=Integer(2)).labels() [2, 1, 4] 
 - leaf_labels()[source]¶
- Return the list of labels of the leaves of - self.- In case of a labelled binary tree, these “leaves” are not actually the leaves of the binary trees, but the nodes whose both children are leaves! - EXAMPLES: - sage: LT = LabelledOrderedTree sage: t = LT([LT([],label='b'),LT([],label='c')],label='a') sage: t.leaf_labels() ['b', 'c'] sage: LBT = LabelledBinaryTree sage: bt = LBT([LBT([],label='b'),LBT([],label='c')],label='a') sage: bt.leaf_labels() ['b', 'c'] sage: LBT([], label='1').leaf_labels() ['1'] sage: LBT(None).leaf_labels() [] - >>> from sage.all import * >>> LT = LabelledOrderedTree >>> t = LT([LT([],label='b'),LT([],label='c')],label='a') >>> t.leaf_labels() ['b', 'c'] >>> LBT = LabelledBinaryTree >>> bt = LBT([LBT([],label='b'),LBT([],label='c')],label='a') >>> bt.leaf_labels() ['b', 'c'] >>> LBT([], label='1').leaf_labels() ['1'] >>> LBT(None).leaf_labels() [] 
 - shape()[source]¶
- Return the unlabelled tree associated to - self.- EXAMPLES: - sage: t = LabelledOrderedTree([[],[[]]], label = 25).shape(); t [[], [[]]] sage: LabelledBinaryTree([[],[[],[]]], label = 25).shape() [[., .], [[., .], [., .]]] sage: LRT = LabelledRootedTree sage: tb = LRT([],label='b') sage: LRT([tb, tb], label='a').shape() [[], []] - >>> from sage.all import * >>> t = LabelledOrderedTree([[],[[]]], label = Integer(25)).shape(); t [[], [[]]] >>> LabelledBinaryTree([[],[[],[]]], label = Integer(25)).shape() [[., .], [[., .], [., .]]] >>> LRT = LabelledRootedTree >>> tb = LRT([],label='b') >>> LRT([tb, tb], label='a').shape() [[], []] 
 
- class sage.combinat.abstract_tree.AbstractTree[source]¶
- Bases: - object- Abstract Tree. - There is no data structure defined here, as this class is meant to be extended, not instantiated. - How should this class be extended? - A class extending - AbstractTreeshould respect several assumptions:- For a tree - T, the call- iter(T)should return an iterator on the children of the root- T.
- The - canonical_labellingmethod should return the same value for trees that are considered equal (see the “canonical labellings” section in the documentation of the- AbstractTreeclass).
- For a tree - Tthe call- T.parent().labelled_trees()should return a parent for labelled trees of the same kind: for example,- if - Tis a binary tree,- T.parent()is- BinaryTrees()and- T.parent().labelled_trees()is- LabelledBinaryTrees()
- if - Tis an ordered tree,- T.parent()is- OrderedTrees()and- T.parent().labelled_trees()is- LabelledOrderedTrees()
 
 - breadth_first_order_traversal(action=None)[source]¶
- 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 as input, and does something during the exploration
 - OUTPUT: - None. (This is not an iterator.)- EXAMPLES: - For example, on the following binary tree \(b\): - | ___3____ | | / \ | | 1 _7_ | | \ / \ | | 2 5 8 | | / \ | | 4 6 | - the breadth-first order traversal algorithm explores \(b\) in the following order of nodes: \(3,1,7,2,5,8,4,6\). 
 - canonical_labelling(shift=1)[source]¶
- Return 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 nodes of the tree. Moreover, two (unlabelled) trees compare as equal if and only if their canonical labelled trees compare as equal. - EXAMPLES: - sage: t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]]) sage: t.canonical_labelling() 1[2[], 3[4[], 5[6[], 7[]], 8[9[], 10[]]], 11[12[], 13[]]] sage: BinaryTree([]).canonical_labelling() 1[., .] sage: BinaryTree([[],[[],[]]]).canonical_labelling() 2[1[., .], 4[3[., .], 5[., .]]] - >>> from sage.all import * >>> t = OrderedTree([[], [[], [[], []], [[], []]], [[], []]]) >>> t.canonical_labelling() 1[2[], 3[4[], 5[6[], 7[]], 8[9[], 10[]]], 11[12[], 13[]]] >>> BinaryTree([]).canonical_labelling() 1[., .] >>> BinaryTree([[],[[],[]]]).canonical_labelling() 2[1[., .], 4[3[., .], 5[., .]]] 
 - contour_traversal(first_action=None, middle_action=None, final_action=None, leaf_action=None)[source]¶
- Run the counterclockwise countour traversal algorithm (iterative implementation) and subject every node encountered to some procedure - first_action,- middle_actionor- final_actioneach time it reaches it.- ALGORITHM: - if the root is a leaf, apply \(leaf_action\) 
- else
- apply \(first_action\) to the root 
- iteratively apply \(middle_action\) to the root and traverse each subtree from the leftmost one to the rightmost one 
- apply \(final_action\) to the root 
 
 
 - INPUT: - first_action– (optional) a function which takes a node as input, and does something the first time it is reached during exploration
- middle_action– (optional) a function which takes a node as input, and does something each time it explore one of its children
- final_action– (optional) a function which takes a node as input, and does something the last time it is reached during exploration
- leaf_action– (optional) a function which takes a leaf as input, and does something when it is reached during exploration.
 - OUTPUT: - None. (This is not an iterator.)
 - depth()[source]¶
- Return the depth of - self.- EXAMPLES: - sage: OrderedTree().depth() 1 sage: OrderedTree([]).depth() 1 sage: OrderedTree([[],[]]).depth() 2 sage: OrderedTree([[],[[]]]).depth() 3 sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).depth() 4 sage: BinaryTree().depth() 0 sage: BinaryTree([[],[[],[]]]).depth() 3 - >>> from sage.all import * >>> OrderedTree().depth() 1 >>> OrderedTree([]).depth() 1 >>> OrderedTree([[],[]]).depth() 2 >>> OrderedTree([[],[[]]]).depth() 3 >>> OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).depth() 4 >>> BinaryTree().depth() 0 >>> BinaryTree([[],[[],[]]]).depth() 3 
 - iterative_post_order_traversal(action=None)[source]¶
- 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 as input, and does something during the exploration
 - OUTPUT: - None. (This is not an iterator.)- See also 
 - iterative_pre_order_traversal(action=None)[source]¶
- 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 as input, and does something during the exploration
 - OUTPUT: - None. (This is not an iterator.)
 - node_number()[source]¶
- Return the number of nodes of - self.- EXAMPLES: - sage: OrderedTree().node_number() 1 sage: OrderedTree([]).node_number() 1 sage: OrderedTree([[],[]]).node_number() 3 sage: OrderedTree([[],[[]]]).node_number() 4 sage: OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).node_number() 13 - >>> from sage.all import * >>> OrderedTree().node_number() 1 >>> OrderedTree([]).node_number() 1 >>> OrderedTree([[],[]]).node_number() 3 >>> OrderedTree([[],[[]]]).node_number() 4 >>> OrderedTree([[], [[], [[], []], [[], []]], [[], []]]).node_number() 13 - EXAMPLES: - sage: BinaryTree(None).node_number() 0 sage: BinaryTree([]).node_number() 1 sage: BinaryTree([[], None]).node_number() 2 sage: BinaryTree([[None, [[], []]], None]).node_number() 5 - >>> from sage.all import * >>> BinaryTree(None).node_number() 0 >>> BinaryTree([]).node_number() 1 >>> BinaryTree([[], None]).node_number() 2 >>> BinaryTree([[None, [[], []]], None]).node_number() 5 
 - node_number_at_depth(depth)[source]¶
- Return the number of nodes at a given depth. - This counts all nodes that are at the given depth. - Here the root is considered to have depth 0. - INPUT: - depth– integer
 - EXAMPLES: - sage: T = OrderedTree([[[], [[]]], [[], [[[]]]], []]) sage: ascii_art(T) ___o____ / / / o_ o_ o / / / / o o o o | | o o | o sage: [T.node_number_at_depth(i) for i in range(6)] [1, 3, 4, 2, 1, 0] - >>> from sage.all import * >>> T = OrderedTree([[[], [[]]], [[], [[[]]]], []]) >>> ascii_art(T) ___o____ / / / o_ o_ o / / / / o o o o | | o o | o >>> [T.node_number_at_depth(i) for i in range(Integer(6))] [1, 3, 4, 2, 1, 0] 
 - node_number_to_the_right(path)[source]¶
- Return the number of nodes at the same depth and to the right of the node identified by - path.- This counts the nodes that are at the same depth as the given one, and strictly to its right. - EXAMPLES: - sage: T = OrderedTree([[[], [[]]], [[], [[[]]]], []]) sage: ascii_art(T) ___o____ / / / o_ o_ o / / / / o o o o | | o o | o sage: T.node_number_to_the_right(()) 0 sage: T.node_number_to_the_right((0,)) 2 sage: T.node_number_to_the_right((0,1)) 2 sage: T.node_number_to_the_right((0,1,0)) 1 sage: T = OrderedTree([]) sage: T.node_number_to_the_right(()) 0 - >>> from sage.all import * >>> T = OrderedTree([[[], [[]]], [[], [[[]]]], []]) >>> ascii_art(T) ___o____ / / / o_ o_ o / / / / o o o o | | o o | o >>> T.node_number_to_the_right(()) 0 >>> T.node_number_to_the_right((Integer(0),)) 2 >>> T.node_number_to_the_right((Integer(0),Integer(1))) 2 >>> T.node_number_to_the_right((Integer(0),Integer(1),Integer(0))) 1 >>> T = OrderedTree([]) >>> T.node_number_to_the_right(()) 0 
 - paths()[source]¶
- Return a generator for all paths to nodes of - self.- OUTPUT: - This method returns a list of sequences of integers. Each of these 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 - ().- See also - EXAMPLES: - sage: list(OrderedTree([]).paths()) [()] sage: list(OrderedTree([[],[[]]]).paths()) [(), (0,), (1,), (1, 0)] sage: list(BinaryTree([[],[[],[]]]).paths()) [(), (0,), (1,), (1, 0), (1, 1)] - >>> from sage.all import * >>> list(OrderedTree([]).paths()) [()] >>> list(OrderedTree([[],[[]]]).paths()) [(), (0,), (1,), (1, 0)] >>> list(BinaryTree([[],[[],[]]]).paths()) [(), (0,), (1,), (1, 0), (1, 1)] 
 - paths_at_depth(depth, path=[])[source]¶
- Return a generator for all paths at a fixed depth. - This iterates over all paths for nodes that are at the given depth. - Here the root is considered to have depth 0. - INPUT: - depth– integer
- path– (optional) list; given path used in the recursion
 - Warning - The - pathoption should not be used directly.- See also - EXAMPLES: - sage: T = OrderedTree([[[], [[], [[]]]], [], [[[],[]]], [], []]) sage: ascii_art(T) ______o_______ / / / / / _o__ o o o o / / | o o_ o_ / / / / o o o o | o sage: list(T.paths_at_depth(0)) [()] sage: list(T.paths_at_depth(2)) [(0, 0), (0, 1), (2, 0)] sage: list(T.paths_at_depth(4)) [(0, 1, 1, 0)] sage: list(T.paths_at_depth(5)) [] sage: T2 = OrderedTree([]) sage: list(T2.paths_at_depth(0)) [()] - >>> from sage.all import * >>> T = OrderedTree([[[], [[], [[]]]], [], [[[],[]]], [], []]) >>> ascii_art(T) ______o_______ / / / / / _o__ o o o o / / | o o_ o_ / / / / o o o o | o >>> list(T.paths_at_depth(Integer(0))) [()] >>> list(T.paths_at_depth(Integer(2))) [(0, 0), (0, 1), (2, 0)] >>> list(T.paths_at_depth(Integer(4))) [(0, 1, 1, 0)] >>> list(T.paths_at_depth(Integer(5))) [] >>> T2 = OrderedTree([]) >>> list(T2.paths_at_depth(Integer(0))) [()] 
 - paths_to_the_right(path)[source]¶
- Return a generator of paths for all nodes at the same depth and to the right of the node identified by - path.- This iterates over the paths for nodes that are at the same depth as the given one, and strictly to its right. - INPUT: - path– any path in the tree
 - See also - EXAMPLES: - sage: T = OrderedTree([[[], [[]]], [[], [[[]]]], []]) sage: ascii_art(T) ___o____ / / / o_ o_ o / / / / o o o o | | o o | o sage: g = T.paths_to_the_right(()) sage: list(g) [] sage: g = T.paths_to_the_right((0,)) sage: list(g) [(1,), (2,)] sage: g = T.paths_to_the_right((0,1)) sage: list(g) [(1, 0), (1, 1)] sage: g = T.paths_to_the_right((0,1,0)) sage: list(g) [(1, 1, 0)] sage: g = T.paths_to_the_right((1,2)) sage: list(g) [] - >>> from sage.all import * >>> T = OrderedTree([[[], [[]]], [[], [[[]]]], []]) >>> ascii_art(T) ___o____ / / / o_ o_ o / / / / o o o o | | o o | o >>> g = T.paths_to_the_right(()) >>> list(g) [] >>> g = T.paths_to_the_right((Integer(0),)) >>> list(g) [(1,), (2,)] >>> g = T.paths_to_the_right((Integer(0),Integer(1))) >>> list(g) [(1, 0), (1, 1)] >>> g = T.paths_to_the_right((Integer(0),Integer(1),Integer(0))) >>> list(g) [(1, 1, 0)] >>> g = T.paths_to_the_right((Integer(1),Integer(2))) >>> list(g) [] 
 - post_order_traversal(action=None)[source]¶
- 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 as input, and does something during the exploration
 - OUTPUT: - None. (This is not an iterator.)
 - post_order_traversal_iter()[source]¶
- The depth-first post-order traversal iterator. - This method iters each node following the depth-first post-order 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 leaf). - EXAMPLES: - For example on the following binary tree \(b\): - | ___3____ | | / \ | | 1 _7_ | | \ / \ | | 2 5 8 | | / \ | | 4 6 | - (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\). - For another example, consider the labelled tree: - | __1____ | | / / / | | 2 6 8_ | | | | / / | | 3_ 7 9 10 | | / / | | 4 5 | - The algorithm explores this tree in the following order: \(4,5,3,2,7,6,9,10,8,1\). 
 - pre_order_traversal(action=None)[source]¶
- 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 as input, and does something during the exploration
 - OUTPUT: - None. (This is not an iterator.)- EXAMPLES: - For example, on the following binary tree \(b\): - | ___3____ | | / \ | | 1 _7_ | | \ / \ | | 2 5 8 | | / \ | | 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\). - Another example: - | __1____ | | / / / | | 2 6 8_ | | | | / / | | 3_ 7 9 10 | | / / | | 4 5 | - The algorithm explores this tree in the following order: \(1,2,3,4,5,6,7,8,9,10\). 
 - pre_order_traversal_iter()[source]¶
- The depth-first pre-order traversal iterator. - This method iters each node following the depth-first pre-order traversal algorithm (recursive implementation). The algorithm is: - yield the root (in the case of binary trees, if it is not a leaf); then explore each subtree (by the algorithm) from the leftmost one to the rightmost one. - EXAMPLES: - For example, on the following binary tree \(b\): - | ___3____ | | / \ | | 1 _7_ | | \ / \ | | 2 5 8 | | / \ | | 4 6 | - (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: - | __1____ | | / / / | | 2 6 8_ | | | | / / | | 3_ 7 9 10 | | / / | | 4 5 | - The algorithm explores this labelled tree in the following order: \(1,2,3,4,5,6,7,8,9,10\). 
 - subtrees()[source]¶
- Return a generator for all nonempty subtrees of - self.- 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: - sage: list(OrderedTree([]).subtrees()) [[]] 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[., .]] - >>> from sage.all import * >>> list(OrderedTree([]).subtrees()) [[]] >>> list(OrderedTree([[],[[]]]).subtrees()) [[[], [[]]], [], [[]], []] >>> list(OrderedTree([[],[[]]]).canonical_labelling().subtrees()) [1[2[], 3[4[]]], 2[], 3[4[]], 4[]] >>> list(BinaryTree([[],[[],[]]]).subtrees()) [[[., .], [[., .], [., .]]], [., .], [[., .], [., .]], [., .], [., .]] >>> v = BinaryTree([[],[]]) >>> list(v.canonical_labelling().subtrees()) [2[1[., .], 3[., .]], 1[., .], 3[., .]] 
 - to_hexacode()[source]¶
- Transform a tree into a hexadecimal string. - The definition of the hexacode is recursive. The first letter is the valence of the root as a hexadecimal (up to 15), followed by the concatenation of the hexacodes of the subtrees. - This method only works for trees where every vertex has valency at most 15. - See - from_hexacode()for the reverse transformation.- EXAMPLES: - sage: from sage.combinat.abstract_tree import from_hexacode sage: LT = LabelledOrderedTrees() sage: from_hexacode('2010', LT).to_hexacode() '2010' sage: LT.an_element().to_hexacode() '3020010' sage: t = from_hexacode('a0000000000000000', LT) sage: t.to_hexacode() 'a0000000000' sage: OrderedTrees(6).an_element().to_hexacode() '500000' - >>> from sage.all import * >>> from sage.combinat.abstract_tree import from_hexacode >>> LT = LabelledOrderedTrees() >>> from_hexacode('2010', LT).to_hexacode() '2010' >>> LT.an_element().to_hexacode() '3020010' >>> t = from_hexacode('a0000000000000000', LT) >>> t.to_hexacode() 'a0000000000' >>> OrderedTrees(Integer(6)).an_element().to_hexacode() '500000' 
 - tree_factorial()[source]¶
- Return the tree-factorial of - self.- Definition: - The tree-factorial \(T!\) of a tree \(T\) is the product \(\prod_{v\in T}\#\mbox{children}(v)\). - EXAMPLES: - sage: LT = LabelledOrderedTrees() sage: t = LT([LT([],label=6),LT([],label=1)],label=9) sage: t.tree_factorial() 3 sage: BinaryTree([[],[[],[]]]).tree_factorial() 15 - >>> from sage.all import * >>> LT = LabelledOrderedTrees() >>> t = LT([LT([],label=Integer(6)),LT([],label=Integer(1))],label=Integer(9)) >>> t.tree_factorial() 3 >>> BinaryTree([[],[[],[]]]).tree_factorial() 15 
 
- sage.combinat.abstract_tree.from_hexacode(ch, parent=None, label='@')[source]¶
- Transform a hexadecimal string into a tree. - INPUT: - ch– a hexadecimal string
- parent– kind of trees to be produced. If- None, this will be- LabelledOrderedTrees
- label– a label (default:- '@') to be used for every vertex of the tree
 - See - AbstractTree.to_hexacode()for the description of the encoding- See - _from_hexacode_aux()for the actual code- EXAMPLES: - sage: from sage.combinat.abstract_tree import from_hexacode sage: from_hexacode('12000', LabelledOrderedTrees()) @[@[@[], @[]]] sage: from_hexacode('12000') @[@[@[], @[]]] sage: from_hexacode('1200', LabelledOrderedTrees()) @[@[@[], @[]]] - >>> from sage.all import * >>> from sage.combinat.abstract_tree import from_hexacode >>> from_hexacode('12000', LabelledOrderedTrees()) @[@[@[], @[]]] >>> from_hexacode('12000') @[@[@[], @[]]] >>> from_hexacode('1200', LabelledOrderedTrees()) @[@[@[], @[]]] - It can happen that only a prefix of the word is used: - sage: from_hexacode('a'+14*'0', LabelledOrderedTrees()) @[@[], @[], @[], @[], @[], @[], @[], @[], @[], @[]] - >>> from sage.all import * >>> from_hexacode('a'+Integer(14)*'0', LabelledOrderedTrees()) @[@[], @[], @[], @[], @[], @[], @[], @[], @[], @[]] - One can choose the label: - sage: from_hexacode('1200', LabelledOrderedTrees(), label='o') o[o[o[], o[]]] - >>> from sage.all import * >>> from_hexacode('1200', LabelledOrderedTrees(), label='o') o[o[o[], o[]]] - One can also create other kinds of trees: - sage: from_hexacode('1200', OrderedTrees()) [[[], []]] - >>> from sage.all import * >>> from_hexacode('1200', OrderedTrees()) [[[], []]]