Thursday, June 16, 2022
HomeMathNew in 13: Timber

# New in 13: Timber

Two years in the past we launched Model 12.0 of the Wolfram Language. Listed here are the updates in bushes since then, together with the newest options in 13.0. The contents of this put up are compiled from Stephen Wolfram’s Launch Bulletins for 12.1, 12.2, 12.3 and 13.0.

### Timber! (Could 2021)

Based mostly on the variety of new built-in features the clear winner for the most important new framework in Model 12.3 is the one for bushes. We’ve been capable of deal with bushes as a particular case of graphs for greater than a decade (and naturally all symbolic expressions within the Wolfram Language are in the end represented as bushes). However in Model 12.3 we’re introducing bushes as first-class objects within the system.

The elemental object is Tree:

 ✕ `Tree[a, {b, Tree[c, {d, e}], f, g}]`

Tree takes two arguments: a “payload” (which could be any expression), and an inventory of subtrees. (And, sure, bushes are by default rendered barely inexperienced, in a nod to their botanical analogs.)

There are a selection of “*Tree” features for establishing bushes, and “Tree*” features for changing bushes to different issues. RulesTree, for instance, constructs a tree from a nested assortment of guidelines:

 ✕ `RulesTree[a -> {b, c -> {d, e}, f, g}]`

And TreeRules goes the opposite approach, changing a tree to a nested assortment of guidelines:

 ✕ `TreeRules[%]`

ExpressionTree creates a tree from the construction of an expression:

 ✕ `ExpressionTree[Integrate[1/(x^2 - 1), x]]`

In a way, it is a direct illustration of a FullForm expression, as proven, for instance, in TreeForm. However there are additionally methods to show an expression right into a tree. This takes the nodes of the tree to comprise full subexpressions—in order that the expressions on a given stage within the tree are basically what a perform like Map would think about to be the expressions at that stage (with Heads → True):

 ✕ `ExpressionTree[Integrate[1/(x^2 - 1), x], "Subexpressions"]`

Right here’s one other model, now successfully eradicating the redundancy of nested subexpressions, and treating heads of expressions identical to different components (in “S-expression model”):

 ✕ `ExpressionTree[Integrate[1/(x^2 - 1), x], "Atoms"]`

Why do we’d like Tree when we’ve Graph? The reply is that there are a number of particular options of bushes which are essential. In a Graph, for instance, each node has a reputation, and the names need to be distinctive. In a tree, nodes don’t need to be named, however they will have “payloads” that don’t need to be distinctive. As well as, in a graph, the perimeters at a given node don’t seem in any specific order; in a tree they do. Lastly, a tree has a particular root node; a graph doesn’t essentially have something like this.

Once we have been designing Tree we at first thought we’d need to have separate symbolic representations of complete bushes, subtrees and leaf nodes. However it turned out that we have been capable of make a chic design with Tree alone. Nodes in a tree sometimes have the shape Tree[payload, {child1child2, …}] the place the babyi are subtrees. A node doesn’t essentially need to have a payload, during which case it may well simply be given as Tree[{child1child2, …}]. A leaf node is then Tree[exprNone] or Tree[None].

One very good function of this design is that bushes can instantly be constructed from subtrees simply by nesting expressions:

 ✕ ```Tree[{!(* GraphicsBox[ NamespaceBox["Trees", DynamicModuleBox[{Typeset`tree = HoldComplete[ Tree[\$CellContext`a, { Tree[\$CellContext`b, None], Tree[\$CellContext`c, { Tree[\$CellContext`d, None], Tree[\$CellContext`e, None]}]}]]}, { {RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1], Opacity[0.7], StyleBox[{ LineBox[{{0.4472135954999579, 1.7888543819998317`}, {0., 0.8944271909999159}}], LineBox[{{0.4472135954999579, 1.7888543819998317`}, { 0.8944271909999159, 0.8944271909999159}}], LineBox[{{0.8944271909999159, 0.8944271909999159}, { 0.4472135954999579, 0.}}], LineBox[{{0.8944271909999159, 0.8944271909999159}, { 1.3416407864998738`, 0.}}]}, GraphicsHighlightColor->RGBColor[ 0.403921568627451, 0.8705882352941177, 0.7176470588235294]]}, {GrayLevel[0], EdgeForm[{GrayLevel[0], Opacity[0.7]}], StyleBox[{InsetBox[ FrameBox["a", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->4, StripOnInput->False], {0.4472135954999579, 1.7888543819998317}], InsetBox[ FrameBox["b", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->0, StripOnInput->False], {0., 0.8944271909999159}], InsetBox[ FrameBox["c", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->4, StripOnInput->False], {0.8944271909999159, 0.8944271909999159}], InsetBox[ FrameBox["d", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->0, StripOnInput->False], {0.4472135954999579, 0.}], InsetBox[ FrameBox["e", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->0, StripOnInput->False], {1.3416407864998738, 0.}]}, GraphicsHighlightColor->RGBColor[ 0.403921568627451, 0.8705882352941177, 0.7176470588235294]]}}]], BaseStyle->{ FrontEnd`GraphicsHighlightColor -> RGBColor[ 0.403921568627451, 0.8705882352941177, 0.7176470588235294]}, FormatType->StandardForm, FrameTicks->None, ImageSize->{69.1171875, Automated}]), !(* GraphicsBox[ NamespaceBox["Trees", DynamicModuleBox[{Typeset`tree = HoldComplete[ Tree[\$CellContext`a, { Tree[\$CellContext`b, None], Tree[\$CellContext`c, { Tree[\$CellContext`d, None], Tree[\$CellContext`e, None]}]}]]}, { {RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1], Opacity[0.7], StyleBox[{ LineBox[{{0.4472135954999579, 1.7888543819998317`}, {0., 0.8944271909999159}}], LineBox[{{0.4472135954999579, 1.7888543819998317`}, { 0.8944271909999159, 0.8944271909999159}}], LineBox[{{0.8944271909999159, 0.8944271909999159}, { 0.4472135954999579, 0.}}], LineBox[{{0.8944271909999159, 0.8944271909999159}, { 1.3416407864998738`, 0.}}]}, GraphicsHighlightColor->RGBColor[ 0.403921568627451, 0.8705882352941177, 0.7176470588235294]]}, {GrayLevel[0], EdgeForm[{GrayLevel[0], Opacity[0.7]}], StyleBox[{InsetBox[ FrameBox["a", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->4, StripOnInput->False], {0.4472135954999579, 1.7888543819998317}], InsetBox[ FrameBox["b", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->0, StripOnInput->False], {0., 0.8944271909999159}], InsetBox[ FrameBox["c", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->4, StripOnInput->False], {0.8944271909999159, 0.8944271909999159}], InsetBox[ FrameBox["d", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->0, StripOnInput->False], {0.4472135954999579, 0.}], InsetBox[ FrameBox["e", Background->RGBColor[ 0.9607843137254902, 0.9882352941176471, 0.9764705882352941], FrameStyle->Directive[ RGBColor[0.6588235294117647, 0.7294117647058823, 0.7058823529411765], AbsoluteThickness[1]], ImageSize->Automated, RoundingRadius->0, StripOnInput->False], {1.3416407864998738, 0.}]}, GraphicsHighlightColor->RGBColor[ 0.403921568627451, 0.8705882352941177, 0.7176470588235294]]}}]], BaseStyle->{ FrontEnd`GraphicsHighlightColor -> RGBColor[ 0.403921568627451, 0.8705882352941177, 0.7176470588235294]}, FormatType->StandardForm, FrameTicks->None, ImageSize->{68.625, Automated}]), Tree[{CloudGet["http://wolfr.am/VAsaSro1"]}]}]```

By the way in which, we are able to flip this right into a generic Graph object with TreeGraph:

 ✕ `TreeGraph[%]`

Discover that since Graph doesn’t take note of ordering of nodes, some nodes have successfully been flipped on this rendering. The nodes have additionally needed to be given distinct names so as to protect the tree construction:

 ✕ `Graph[CloudGet["http://wolfr.am/VAsb0AqA"], VertexLabels -> Automated]`

If there’s a generic graph that occurs to be a tree, GraphTree converts it to express Tree type:

 ✕ `GraphTree[KaryTree[20]]`

RandomTree produces a random tree of a given measurement:

 ✕ `RandomTree[20]`

One may also make bushes from nesting features: NestTree produces a tree by nestedly producing payloads of kid nodes from payloads of father or mother nodes:

 ✕ `NestTree[{f[#], g[#]} &, x, 2]`

OK, so given a tree, what can we do with it? There are a selection of tree features which are direct analogs of features for generic expressions. For instance, TreeDepth offers the depth of a tree:

 ✕ `TreeDepth[CloudGet["http://wolfr.am/VAsbf4XX"]]`

TreeLevel is immediately analogous to Degree. Right here we’re getting subtrees that begin at stage 2 within the tree:

 ✕ `TreeLevel[CloudGet["http://wolfr.am/VAsbnJeT"], {2}]`

How do you get a specific subtree of a given tree? Mainly it has a place, simply as a subexpression would have a place in an abnormal expression:

 ✕ `TreeExtract[CloudGet["http://wolfr.am/VAsbnJeT"], {2, 2}]`

TreeSelect lets you choose subtrees in a given tree:

 ✕ `TreeSelect[CloudGet["http://wolfr.am/VAsbnJeT"], TreeDepth[#] > 2 &]`

TreeData picks out payloads, by default for the roots of bushes (TreeChildren picks out subtrees):

 ✕ `TreeData /@ %`

There are additionally TreeCases, TreeCount and TreePosition—which by default seek for subtrees whose payloads match a specified sample. One can do purposeful programming with bushes identical to with generic expressions. TreeMap maps a perform over (the payloads in) a tree:

 ✕ `TreeMap[f, CloudGet["http://wolfr.am/VAsbCysJ"]]`

TreeFold does a barely extra sophisticated operation. Right here f is successfully “accumulating knowledge” by scanning the tree, with g being utilized to the payload of every leaf (to “initialize the buildup”):

 ✕ `TreeFold[{f, g}, CloudGet["http://wolfr.am/VAsbCysJ"]]`

There are many issues that may be represented by bushes. A basic instance is household bushes. Right here’s a case the place there’s built-in knowledge we are able to use:

 ✕ ```Entity["Person", "QueenElizabethII::f5243"][ EntityProperty["Person", "Children"]]```

This constructs a 2-level household tree:

 ✕ ```NestTree[#[EntityProperty["Person", "Children"]] &, Entity["Person", "QueenElizabethII::f5243"], 2]```

By the way in which, our Tree system could be very scalable, and might fortunately deal with bushes with thousands and thousands of nodes. However in Model 12.3 we’re actually simply beginning out; in subsequent variations there’ll be all kinds of different tree performance, in addition to functions to parse bushes, XML bushes, and many others.

### Timber Proceed to Develop (December 2021)

We launched Tree as a fundamental assemble in Model 12.3. In 13.0 we’re extending Tree and including some enhancements. To start with, there at the moment are choices for tree format and visualization.

For instance, this lays out a tree radially (notice that realizing it’s a tree moderately than a common graph makes it potential to do rather more systematic embeddings):

 ✕

This provides choices for styling components, with one specific factor specified by its tree place being singled out as blue:

 ✕

One of many extra refined new “tree ideas” is TreeTraversalOrder. Think about you’re going to “map throughout” a tree. In what order do you have to go to the nodes? Right here’s the default conduct. Arrange a tree:

 ✕

Now present during which order the nodes are visited by TreeScan:

 ✕

This explicitly labels the nodes within the order they’re visited:

 ✕

This order is by default depth first. However now TreeTraversalOrder lets you ask for different orderings. Right here’s breadth-first order:

 ✕

Right here’s a barely extra ornate ordering:

 ✕

Why does this matter? “Traversal order” seems to be associated to deep questions on analysis processes and what I now name multicomputation. In a way a traversal order defines the “reference body” by which an “observer” of the tree samples it. And, sure, that language feels like physics, and for a very good cause: that is all deeply associated to a bunch of ideas about elementary physics that come up in our Physics Venture. And the parametrization of traversal order—aside from being helpful for a bunch of current algorithms—begins to open the door to connecting computational processes to concepts from physics, and new notions about what I’m calling multicomputation.

div.bottomstripe {
max-width:620px;
margin-bottom:10px;
background-color: #fff39a;
border: strong 2px #ffd400;
line-height: 1.2;}
div.bottomstripe a,
#weblog .post_content .bottomstripe a:visited {
font-family:”Supply Sans Professional”,Arial,Sans Serif;
font-size:11pt;
colour:#aa0d00;}
div.bottomstripe.purple {
background-color: #f7f2ff;
border: strong 2px #e4d9f4;}
div.bottomstripe.purple a,
#weblog .post_content .bottomstripe.purple a:visited {
colour:#531368;}

RELATED ARTICLES