Ask Your Question

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: