Function Repository Resource:

LeafComplexity

Source Notebook

Compute a sum or other complexity measure over all atoms of an expression

Contributed by: Daniele Gregori

ResourceFunction["LeafComplexity"][expr]

gives the sum of all the numeric indivisible subexpressions in expr.

ResourceFunction["LeafComplexity"][expr, f]

apply a function f to each indivisible subexpression in expr and take the Total.

ResourceFunction["LeafComplexity"][expr, f, g]

apply a function f to each indivisible subexpression in expr and Apply to it recursively another unary or binary function g.

Details and Options

Any Wolfram Language expression can be broken down as a TreeForm. An expression's LeafCount gives its total number of indivisible subexpressions or leaves.
LeafComplexity directly extends LeafCount by weighing each leaf by its absolute numeric value and then taking their sum. If a leaf is non-numeric, it is counted by default as 1. Even if already atoms, expressions with Rational, Complex or Association heads are decomposed into their subparts.
ResourceFunction["LeafComplexity"] also accepts as second argument a custom Function f to be applied to all leaves before taking their Total. Even more generally, a third argument can be specified to recursively Apply to each function-of-the-leaf another unary or binary function g. Setting this to Plus recovers the other definitions UpTo two arguments.
ResourceFunction["LeafComplexity"] accepts the following options:
HeadsTrueconsider also the subexpression heads as leaves
ResourceFunction["LeafComplexity"] can work as a measure of complexity for algebraic expressions.
An important detail in the definition and design of ResourceFunction["LeafComplexity"] is the following. Since in the most general usage case one may sometimes want to choose as third argument Times instead of the default Plus, then in order to avoid returning identically null results, all ResourceFunction["LeafComplexity"] usage definitions are implemented as recursions starting from initial condition 1 instead of 0. This in practice induces the somewhat akward "correspondence principle" that if all leaves are equal 1 or -1, ResourceFunction["LeafComplexity"][expr]=LeafCount[expr]+1. One may desire to see complete equality with LeafCount in this special case, but a better trade-off seems to maintain the internal consistency and generality of ResourceFunction["LeafComplexity"] itself.

Examples

Basic Examples (2) 

Expressions with the same LeafCount may have different total over their leaves:

In[1]:=
ResourceFunction["LeafComplexity"][x + 2]
Out[1]=
In[2]:=
ResourceFunction["LeafComplexity"][x + 10]
Out[2]=

Apply a function to each leaf before taking the total:

In[3]:=
ResourceFunction["LeafComplexity"][x + 1000000, Log10]
Out[3]=

Scope (6) 

Take the total over the leaves of a rational expression:

In[4]:=
ResourceFunction["LeafComplexity"][(x + 2)/(y - 2)]
Out[4]=

Sum over all leaves of an algebraic or complex expression:

In[5]:=
ResourceFunction["LeafComplexity"][(Sqrt[x] - 1)/(y^(1/5) + 2)]
Out[5]=
In[6]:=
ResourceFunction["LeafComplexity"][(x + I)/(x - 2 - 2 I) - 4 I/x^2]
Out[6]=

Sum over non-integer leaves:

In[7]:=
ResourceFunction["LeafComplexity"][1.5 x^2 + 1.1 Log[y]]
Out[7]=
In[8]:=
ResourceFunction["LeafComplexity"][E^x + Pi^2]
Out[8]=

Sum over the leaves of any expression:

In[9]:=
ResourceFunction[
 "LeafComplexity"][{1, 2, {4, 0, 1, {0, 6, 3, 4, {2, 3, 0}, {5, 2, 0}, 1}, 0}}]
Out[9]=
In[10]:=
ResourceFunction[
 "LeafComplexity"][<|a -> {2, 3}, b -> <|{0, 1} -> <|\[Gamma] -> 20, \[Delta] -> 40|>, {-1, -2} -> 50|>|>]
Out[10]=

Apply an arbitrary function to each leaf:

In[11]:=
ResourceFunction["LeafComplexity"][Exp[-Exp[-Exp[x]]], Abs@Log[#] &]
Out[11]=
In[12]:=
ResourceFunction[
 "LeafComplexity"][{a[2], a[E], a[4], a[8], a[E^2], a[16]}, If[Mod[#, 2] =!= 0, 0, Log2[#]] &]
Out[12]=

Apply a custom wrapping function other than Plus to each leaf and function-of-the-leaf:

In[13]:=
range = Range[5]
Out[13]=
In[14]:=
ResourceFunction["LeafComplexity"][range, Exp, Times]
Out[14]=
In[15]:=
ResourceFunction["LeafComplexity"][range, Exp[#] &, Exp[#2] &]
Out[15]=
In[16]:=
ResourceFunction["LeafComplexity"][range, Exp[#] &, Exp[#1] &]
Out[16]=

Options (2) 

Heads (2) 

Through the option Heads set to False, only proper leaf nodes are counted (parent nodes count 0):

In[17]:=
ResourceFunction["LeafComplexity"][x + 1, Heads -> False]
Out[17]=
In[18]:=
ResourceFunction["LeafComplexity"][x + 1]
Out[18]=

Another example with 4 discarded heads:

In[19]:=
expr = (x + 1)/(y - 3);
In[20]:=
leaftot = ResourceFunction["LeafComplexity"][expr, Heads -> False]
Out[20]=
In[21]:=
ResourceFunction["LeafComplexity"][expr] - leaftot
Out[21]=

Check the FullForm:

In[22]:=
FullForm[expr]
Out[22]=

Applications (3) 

LeafTotal can be used as option value for ComplexityFunction to Simplify algebraic expressions:

In[23]:=
Simplify[(-4 - 4 a b^2 - 2 a^2 b)/(a b)]
Out[23]=
In[24]:=
Simplify[(-4 - 4 a b^2 - 2 a^2 b)/(a b), ComplexityFunction -> ResourceFunction["LeafComplexity"]]
Out[24]=

Another example with Log:

In[25]:=
Simplify[2 Log[a] + 4 Log[-4]]
Out[25]=
In[26]:=
Simplify[2 Log[a] + 4 Log[-4], ComplexityFunction -> ResourceFunction["LeafComplexity"]]
Out[26]=

Select the "simplest" element of a list according to a custom function applied to each leaf:

In[27]:=
list = f /@ RandomInteger[{0, 300}, 10]
Out[27]=
In[28]:=
First@MinimalBy[
  list,
  ResourceFunction["LeafComplexity"][#, Mean[{DigitSum[#], Length@FactorInteger[#]}] &] &]
Out[28]=

Certain functions like ResourceFunction["AlgebraicRange"] tend to overproduce complex closed forms:

In[29]:=
algrg = ResourceFunction["AlgebraicRange"][0, 50, 1/50];
In[30]:=
Length[algrg]
Out[30]=
In[31]:=
RandomSample[algrg, 10] // SortBy[N]
Out[31]=
In[32]:=
Histogram[ResourceFunction["LeafComplexity"] /@ algrg]
Out[32]=

LeafTotal[expr] allows to select only the simpler ones:

In[33]:=
simpalgrg = Select[algrg, ResourceFunction["LeafComplexity"][#] <= 30 &];
In[34]:=
Length[simpalgrg]
Out[34]=
In[35]:=
RandomSample[simpalgrg, 10] // SortBy[N]
Out[35]=

The resulting numeric distribution can still be nearly uniform:

In[36]:=
NumberLinePlot[simpalgrg]
Out[36]=

Properties and Relations (4) 

If all numeric leaves of an algebraic expression are equal to 1 or -1, LeafComplexity[expr] has the same value as LeafCount[expr]+1:

In[37]:=
ResourceFunction["LeafComplexity"][(x + 1)/(x - 1) + 1/x]
Out[37]=
In[38]:=
LeafCount[(x + 1)/(x - 1) + 1/x] + 1
Out[38]=

If no 0 appears in the expression, LeafComplexity[expr] is greater than LeafCount[expr]+1:

In[39]:=
ResourceFunction["LeafComplexity"][(2 x + 1)/(Sqrt[x] - 1) + 1/x]
Out[39]=
In[40]:=
LeafCount[(2 x + 1)/(Sqrt[x] - 1) + 1/x] + 1
Out[40]=

If 0s are present in the expression, LeafComplexity[expr] can be less than LeafCount[expr]+1:

In[41]:=
ResourceFunction["LeafComplexity"][{1, 0, 0, 0}]
Out[41]=
In[42]:=
LeafCount[{1, 0, 0, 0}] + 1
Out[42]=

If Infinity appears anywhere in the expression and does evaluate to 0, infinite is also the value of LeafComplexity:

In[43]:=
ResourceFunction["LeafComplexity"][x + 1/Infinity]
Out[43]=
In[44]:=
ResourceFunction["LeafComplexity"][x + Infinity]
Out[44]=

LeafComplexity[expr] can be also computed in terms of Cases as follows:

In[45]:=
casesLC[expr_] :=
 1 + Total[
   Abs /@ Flatten@
     Map[Cases[# //. {_Symbol?(! NumericQ[#] &) -> 1, c_Complex :> ReIm[c], r_Rational :> NumeratorDenominator[r]}, _?NumericQ, {0, Infinity}, Heads -> True] &, Cases[expr, _?(NumericQ[#] && AtomQ[#] &) | _Symbol?(! NumericQ[#] &), {0, Infinity}, Heads -> True]]]
In[46]:=
expr = (2 x^(1/3) + I)/(x - 2 - 3 I) - 5/x^2;
In[47]:=
ResourceFunction["LeafComplexity"][expr] // RepeatedTiming
Out[47]=
In[48]:=
casesLC[expr] // RepeatedTiming
Out[48]=

Notice though this is more involved and less efficient than the actual recursive definition.

Neat Examples (2) 

Define a general LeafComplexity with doubly nested Log and Exp:

In[49]:=
log2Exp2Complexity[range_] := ResourceFunction["LeafComplexity"][range, Log[1 - Log[1 - #]] &, Exp[#1 - Exp[#2]] &]

Applying this to Range[n] for a few natural numbers n shows no Overflow and some interesting symbolic and numeric pattern:

In[50]:=
Table[
   With[{expr = Range[n]},
    {llec = log2Exp2Complexity[expr]},
    {n, N@llec, llec}], {n, 1, 12}]~
  Prepend~{"n", "N[Log2Exp2Complexity[Range[n]]", "Log2Exp2Complexity[Range[n]]"} // TableForm
Out[50]=

Publisher

Daniele Gregori

Requirements

Wolfram Language 12.0 (April 2019) or above

Version History

  • 1.0.0 – 20 July 2026

Related Resources

Author Notes

The design of this function benefited from suggestions by the Wolfram Review Team.

License Information