Function Repository Resource:

ParenthesesTrees

Source Notebook

Obtain a list of syntax trees consistent with a valid pattern of parentheses

Contributed by: Bradley Klee

ResourceFunction["ParenthesesTrees"][str]

lists valid syntax trees for reading pairs of parentheses from the input string str.

Details

Every valid input is a string containing only equal numbers of open and close parentheses characters, "(" and ")". Additionally, when reading left to right, the count of "(" must always equal or exceed the count of ")". For example, neither "({})" nor "()())(" are valid, while "(()(()))" is valid.
Valid inputs are read into trees according to a grammar found in the notes of New Kind of Science:
"()" → xixi=Tree[Null,{"(",")"}]close
"(xj)" → xkxk=Tree[Null,{"(",xj,")"}]continue
"xmxn" → xpxp=Tree[Null,{xm,xn}]combine
The third rule for combining groups of characters is not uniquely applicable when three or more xi terms occur directly in sequence. Consequently most inputs have more than one valid interpretation as a syntax tree.
ParenthesisTree takes the same options as Tree, and uniformly applies those options to all trees returned.
ParenthesisTree also allows for a custom TreeLayout, called "SerializedLeaves", which puts leaves in a left-to-right order and sets TreeElementCoordinates to make the serial ordering more obvious.

Examples

Basic Examples (4) 

There is only one parenthesis tree with two leaves:

In[1]:=
ResourceFunction["ParenthesesTrees"]["()"]
Out[1]=

The smallest input with non-unique output has three pairs of open-close parentheses:

In[2]:=
ResourceFunction["ParenthesesTrees"]["()()()"]
Out[2]=

It's not too difficult to find ever-larger inputs with unique syntax trees:

In[3]:=
ResourceFunction["ParenthesesTrees"]["(()())((()(()(()))))"]
Out[3]=

It's also easy to find larger inputs with many equivalent syntax trees:

In[4]:=
ResourceFunction["ParenthesesTrees"]["(()())(()(()))()(())"]
Out[4]=

Scope (1) 

The Null string is uniquely interpreted as a tree consisting only of a root node:

In[5]:=
ResourceFunction["ParenthesesTrees"][""]
Out[5]=

Options (2) 

Using the option setting TreeLayout"SerializedLeafs" causes ParenthesesTrees to use a unique layout, making leaves easier to read across:

In[6]:=
First[ResourceFunction["ParenthesesTrees"]["(()())((()(()(()))))",
  TreeLayout -> "SerializedLeafs"]]
Out[6]=

The "SerializedLeafs" layout also works with AspectRatio:

In[7]:=
First[ResourceFunction["ParenthesesTrees"]["(()())((()(()(()))))",
  TreeLayout -> "SerializedLeafs", AspectRatio -> 3]]
Out[7]=

Neat Examples (2) 

Enumerate valid inputs up to length 14 and count them:

In[8]:=
CatalanStrings[ind_] := Map[StringJoin, ReplaceAll[
   Select[Permutations[Catenate[
      ConstantArray[#, ind] & /@ {1, -1}]],
    AllTrue[Accumulate[#], # >= 0 &] &], {1 -> "(", -1 -> ")"}]]
In[9]:=
Length[CatalanStrings[#]] & /@ Range[7]
Out[9]=

Also enumerate and count the number of unique syntax trees:

In[10]:=
Length[Catenate[
    ResourceFunction["ParenthesesTrees"] /@ CatalanStrings[#]]] & /@ Range[7]
Out[10]=

Publisher

Brad Klee

Version History

  • 1.0.0 – 06 March 2023

Related Resources

License Information