Я пытаюсь оптимизировать некоторый код из пакета teneto
. В частности, следующие функции bezier_points
, make_bezier
, pascal_row
Вот оригинальная реализация: https://teneto.readthedocs.io/en/latest/_modules/teneto/plot/slice_plot.html#slice_plot
Вот моя реализация:
import numpy as np
def bezier_points(p1, p2, number_of_nodes, granularity=20):
"""
Credit: William Hedley Thompson
https://teneto.readthedocs.io/en/latest/_modules/teneto/plot/slice_plot.html#slice_plot
This has been adapted from the teneto package.
"""
def pascal_row(n):
# This returns the nth row of Pascal's Triangle
result = [1]
x, numerator = 1, n
for denominator in range(1, n // 2 + 1):
x *= numerator
x /= denominator
result.append(x)
numerator -= 1
if n & 1 == 0:
# n is even
result.extend(reversed(result[:-1]))
else:
result.extend(reversed(result))
return np.asarray(result)
# These two functions originated from the plot.ly's documentation for python API.
# They create points along a curve.
def make_bezier(points):
# xys should be a sequence of 2-tuples (Bezier control points)
n = len(points)
combinations = pascal_row(n - 1)
def bezier(ts):
# This uses the generalized formula for bezier curves
# http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Generalization
result = []
for t in ts:
tpowers = np.power(np.ones_like(n)*t, np.arange(n))
upowers = np.power(np.ones_like(n)*(1-t), np.arange(n))[::-1]
coefs = combinations*tpowers*upowers
print((coefs * points.reshape(1,-1)).shape)
result.append(
tuple(np.sum(coefs*ps) for ps in zip(*points)))
return result
return bezier
ts = np.arange(granularity+1)/granularity
d = p1[0] - (max(p1[1], p2[1]) - min(p1[1], p2[1])) / number_of_nodes
points = np.asarray([p1, (d, p1[1]), (d, p2[1]), p2])
bezier = make_bezier(points)
points = bezier(ts)
bvx = [i[0] for i in points]
bvy = [i[1] for i in points]
return np.asarray([bvx, bvy])
Вот как я тестирую ее в отношении исходной функции:
gold_standard = np.asarray([[ 0.0000e+00, -1.3000e-03, -1.7000e-03, -4.5000e-04, 3.2000e-03,
1.0000e-02, 2.0700e-02, 3.6050e-02, 5.6800e-02, 8.3700e-02,
1.1750e-01, 1.5895e-01, 2.0880e-01, 2.6780e-01, 3.3670e-01,
4.1625e-01, 5.0720e-01, 6.1030e-01, 7.2630e-01, 8.5595e-01,
1.0000e+00],
[ 0.0000e+00, 7.2500e-03, 2.8000e-02, 6.0750e-02, 1.0400e-01,
1.5625e-01, 2.1600e-01, 2.8175e-01, 3.5200e-01, 4.2525e-01,
5.0000e-01, 5.7475e-01, 6.4800e-01, 7.1825e-01, 7.8400e-01,
8.4375e-01, 8.9600e-01, 9.3925e-01, 9.7200e-01, 9.9275e-01,
1.0000e+00]])
output = bezier_points([0,0], [1,1], 100, 20)
np.allclose(output, gold_standard)
Часть, которую я не могу понять, как оптимизировать с помощью NumPy, - это следующая строка:
result.append(tuple(sum([coef * p for coef, p in zip(coefs, ps)]) for ps in zip(*xys)))
Лучше всего я могу сделать это следующим образом (заметьте, я изменил xys
на points
):
result.append(tuple(np.sum(coefs*ps) for ps in zip(*points)))
Кто-нибудь знает, какоптимизировать этот цикл for с помощью NumPy
?