Tips & tricks

Tips & tricks#

Long sums and products#

In heyoka.py sums can be constructed in two ways.

The first method involves direct use of the heyoka.sum() function:

import heyoka as hy

x, y, z = hy.make_vars("x", "y", "z")

hy.sum([x, y, z])
(x + y + z)

The heyoka.sum() function takes in input a list of expressions and returns a multivariate summation of those expressions.

The other way is to use the binary + operator:

x + y + z
((x + y) + z)

The binary operator is just a wrapper around the heyoka.sum() function. However, as you can also infer from the screen output, writing x + y + z does not produce a ternary sum. Rather, it produces a binary sum in which the first term is another binary sum - that is, a nested sum. This is a consequence of how binary operators are parsed in Python.

Deeply nested binary sums can be less efficient than flat multivariate sums. Thus, if you need to build long summations, the recommended way is to prepare a list of terms and then invoke heyoka.sum(), rather the repeatedly invoking the + or += operators.

import heyoka as hy

long_sum = hy.expression(0.)

# Suboptimal, avoid this if possible.
for i in range(10):
    long_sum += hy.expression(f"x_{i}")
    
long_sum
(((((((((x_0 + x_1) + x_2) + x_3) + x_4) + x_5) + x_6) + x_7) + x_8) + x_9)
# Do this instead.
terms = [hy.expression(f"x_{i}") for i in range(10)]
long_sum = hy.sum(terms)

long_sum
(x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 + x_8 + x_9)

Note

The builtin sum() function is just a wrapper around the binary + operator. Make sure to use heyoka.sum() instead if you want to create a multivariate summation.

Everything that was said in this section about summations also applies to products (see the heyoka.prod() function).

from heyoka import prod, make_vars
x, y, z = make_vars("x", "y", "z")
prod([x, y, z])
(x * y * z)

Powers#

Whereas previous versions of heyoka.py would automatically turn products into powers when appropriate, starting from heyoka.py 5.0.0 this automatic transformation is not applied any more.

Powers are in general more efficient than products or nested multiplications, as they can be automatically-differentiated faster and, during evaluation, heyoka.py takes care behind the scenes of transforming small integral/rational powers into repeated multiplications.

Thus, you should ensure that powers are created as powers:

# Don't do this!
x * x * x
((x * x) * x)
# Write this instead.
x**3
x**3.0000000000000000

This guideline is most important when squaring, as in this special case the automatic differentiation rule is particularly efficient.