# Revision history [back]

To every expression one can associate a syntactic tree.

The function you have in mind seems to be counting the size of that tree; not only the leaves but all the tree's vertices. With that in mind, I would not call it LeafCount.

Sage may have the function you need; I know it has an ExpressionTreeWalker.

Anyway, let us write a small tree_size function.

It gives the tree size of a symbolic expression, as well as of a list, tuple, or vector of symbolic expressions.

def tree_size(expr):
try:
x, aa = expr.operator(), expr.operands()
except AttributeError:
return 1 + sum(tree_size(a) for a in expr)
if x is None:
return 1
else:
return 1 + sum(tree_size(a) for a in aa)


Here is a companion function for the string length:

def string_size(expr):
return len(str(expr))


Let us define a list of the test cases in the question.

a, b, x = SR.var('a, b, x')
ee = [
x,
1/2*(log(b*x + a) - log(b*x - a))/(a*b),
arctan(b*x/a)/(a*b),
-1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x))),
[-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)],
]


and run the function on them:

sage: print('\n'.join(f'* {e}\n  {tree_size(e)}, {string_size(e)}' for e in ee))
* x
1, 1
* 1/2*(log(b*x + a) - log(b*x - a))/(a*b)
25, 39
* arctan(b*x/a)/(a*b)
14, 19
* -1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x)))
31, 75
* [-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)]
68, 117


Perfect match with the desired values!

To every expression one can associate a syntactic tree.

The function you have in mind seems to be counting the size of that tree; not only the leaves but all the tree's vertices. With that in mind, I would not call it LeafCount.

Sage may have the function you need; I know or it has an may be easy to define using Sage's ExpressionTreeWalker. and "map reduce".

Anyway, let us write a small tree_size function.

It gives the tree size of a symbolic expression, as well as of a list, tuple, or vector of symbolic expressions.

def tree_size(expr):
try:
x, aa = expr.operator(), expr.operands()
except AttributeError:
return 1 + sum(tree_size(a) for a in expr)
if x is None:
return 1
else:
return 1 + sum(tree_size(a) for a in aa)


Here is a companion function for the string length:

def string_size(expr):
return len(str(expr))


Let us define a list of the test cases in the question.

a, b, x = SR.var('a, b, x')
ee = [
x,
1/2*(log(b*x + a) - log(b*x - a))/(a*b),
arctan(b*x/a)/(a*b),
-1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x))),
[-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)],
]


and run the function on them:

sage: print('\n'.join(f'* {e}\n  {tree_size(e)}, {string_size(e)}' for e in ee))
* x
1, 1
* 1/2*(log(b*x + a) - log(b*x - a))/(a*b)
25, 39
* arctan(b*x/a)/(a*b)
14, 19
* -1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x)))
31, 75
* [-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)]
68, 117


Perfect match with the desired values!

To every expression one can associate a syntactic tree.

The function you have in mind seems to be counting the size of that tree; not only the leaves but all the tree's vertices. With that in mind, I would not call it LeafCount.

Sage may have the function you need; or it may be easy to define using Sage's ExpressionTreeWalker and "map reduce".

Anyway, let us write a small tree_size function.

It gives the tree size of a symbolic expression, as well as of a list, tuple, or vector of symbolic expressions.

def tree_size(expr):
try:
x, aa = expr.operator(), expr.operands()
except AttributeError:
try:

return 1 + sum(tree_size(a) for a in expr)
if x is None:
return 1
else:
return 1 + sum(tree_size(a) for a in aa)


Here is a companion function for the string length:

def string_size(expr):
return len(str(expr))


Let us define a list of the test cases in the question.

a, b, x = SR.var('a, b, x')
ee = [
x,
1/2*(log(b*x + a) - log(b*x - a))/(a*b),
arctan(b*x/a)/(a*b),
-1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x))),
[-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)],
]


and run the function on them:

sage: print('\n'.join(f'* {e}\n  {tree_size(e)}, {string_size(e)}' for e in ee))
* x
1, 1
* 1/2*(log(b*x + a) - log(b*x - a))/(a*b)
25, 39
* arctan(b*x/a)/(a*b)
14, 19
* -1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x)))
31, 75
* [-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)]
68, 117


Perfect match with the desired values!

To every expression one can associate a syntactic tree.

The function you have in mind seems to be counting the size of that tree; not only the leaves but all the tree's vertices. With that in mind, I would not call it LeafCount.

Sage may have the function you need; or it may be easy to define using Sage's ExpressionTreeWalker and "map reduce".

Anyway, let us write a small tree_size function.

It gives the tree size of a symbolic expression, as well as of a list, tuple, or vector of symbolic expressions.

def tree_size(expr):
try:
r"""
Return the tree size of this expression.
""""
if expr not in SR:
# deal with lists, tuples, vectors
return 1 + sum(tree_size(a) for a in expr)
expr = SR(expr)
x, aa = expr.operator(), expr.operands()
except AttributeError:
try:

return 1 + sum(tree_size(a) for a in expr)
if x is None:
return 1
else:
return 1 + sum(tree_size(a) for a in aa)


Here is a companion function for the string length:

def string_size(expr):
return len(str(expr))


Let us define a list of the test cases in the question.

a, b, x = SR.var('a, b, x')
ee = [
x,
1/2*(log(b*x + a) - log(b*x - a))/(a*b),
arctan(b*x/a)/(a*b),
-1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x))),
[-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)],
]


and run the function on them:

sage: print('\n'.join(f'* {e}\n  {tree_size(e)}, {string_size(e)}' for e in ee))
* x
1, 1
* 1/2*(log(b*x + a) - log(b*x - a))/(a*b)
25, 39
* arctan(b*x/a)/(a*b)
14, 19
* -1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x)))
31, 75
* [-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)]
68, 117


Perfect match with the desired values!

To every expression one can associate a syntactic tree.

The function you have in mind seems to be counting the size of that tree; not only the leaves but all the tree's vertices. With that in mind, I would not call it LeafCount.

Sage may have the function you need; or it may be easy to define using Sage's ExpressionTreeWalker and "map reduce".

Anyway, let us write a small tree_size function.

It gives the tree size of a symbolic expression, as well as of a list, tuple, or vector of symbolic expressions.

def tree_size(expr):
r"""
Return the tree size of this expression.
""""
"""
if expr not in SR:
# deal with lists, tuples, vectors
return 1 + sum(tree_size(a) for a in expr)
expr = SR(expr)
x, aa = expr.operator(), expr.operands()
if x is None:
return 1
else:
return 1 + sum(tree_size(a) for a in aa)


Here is a companion function for the string length:

def string_size(expr):
return len(str(expr))


Let us define a list of the test cases in the question.

a, b, x = SR.var('a, b, x')
ee = [
x,
1/2*(log(b*x + a) - log(b*x - a))/(a*b),
arctan(b*x/a)/(a*b),
-1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x))),
[-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)],
]


and run the function on them:

sage: print('\n'.join(f'* {e}\n  {tree_size(e)}, {string_size(e)}' for e in ee))
* x
1, 1
* 1/2*(log(b*x + a) - log(b*x - a))/(a*b)
25, 39
* arctan(b*x/a)/(a*b)
14, 19
* -1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x)))
31, 75
* [-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)]
68, 117


Perfect match with the desired values!

To every expression one can associate a syntactic tree.

The function you have in mind seems to be counting the size You are asking for the size of that tree; not only the leaves but tree.

Since all the tree's vertices. With that in mind, tree vertices count I would not call it LeafCount.

Sage may have the function you need; or it may be easy to define using Sage's ExpressionTreeWalker and "map reduce".

Anyway, "tree size" rather than "leaf count".

So let us write a small tree_size function.

It I don't know whether Sage already has such a function, or whether a shorter one might use Sage's "expression tree walker" and "map reduce".

The function below gives the tree size of a symbolic expression, expression, as well as as of a list, tuple, or vector of symbolic expressions.expressions, or any Sage object that can be converted to a symbolic expression.

def tree_size(expr):
r"""
Return the tree size of this expression.
"""
if expr not in SR:
# deal with lists, tuples, vectors
return 1 + sum(tree_size(a) for a in expr)
expr = SR(expr)
x, aa = expr.operator(), expr.operands()
if x is None:
return 1
else:
return 1 + sum(tree_size(a) for a in aa)


Here is a companion function for the string length:

def string_size(expr):
r"""
Return the length of the string representation of this expression.
"""
return len(str(expr))


Let us define a list of the test cases in the question.

a, b, x = SR.var('a, b, x')
ee = [
x,
1/2*(log(b*x + a) - log(b*x - a))/(a*b),
arctan(b*x/a)/(a*b),
-1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x))),
[-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)],
]


and run the function on them:

sage: print('\n'.join(f'* {e}\n  {tree_size(e)}, {string_size(e)}' for e in ee))
* x
1, 1
* 1/2*(log(b*x + a) - log(b*x - a))/(a*b)
25, 39
* arctan(b*x/a)/(a*b)
14, 19
* -1/12*sqrt(3)*arctan(1/12*(7*sqrt(3)*cos(x)^2 - 4*sqrt(3))/(cos(x)*sin(x)))
31, 75
* [-sqrt(-a*b)*log((a*x - b - 2*sqrt(-a*b)*sqrt(x))/(a*x + b))/(a*b),
-2*sqrt(a*b)*arctan(sqrt(a*b)/(a*sqrt(x)))/(a*b)]
68, 117


Perfect match with the desired values!

values from the question!

Now also works for the follow-up requests in the comment:

sage: [tree_size(a) for a in [1, 1/2, 3.4, i, CC(3, 2)]]
[1, 1, 1, 1, 1]
sage: x = polygen(ZZ)
sage: p = x - x^2
sage: p
-x^2 + x
sage: tree_size(p)
7
sage: f = (x - x^2) / (1 - 3*x)
sage: f
(-x^2 + x)/(-3*x + 1)
sage: tree_size(f)
15


Related: