Skip to content

Speed up __pow__ for exponent -2 and -0.5 #9363

@TomDLT

Description

@TomDLT

Numpy uses different functions for power internally:

  • When the exponent is in {-1, 0, 0.5, 1, 2}, it uses respectively {reciprocal, one_like, sqrt, ~identity, square}.
  • For any other exponent, it uses a much slower routine.

Therefore, calling a **= 2; a **= -1 is much faster than a **= -2.

I guess it could be possible to improve the logic in fast_scalar_power to also handle the cases {-2, -0.5}, cf. scikit-learn/scikit-learn#9277 (comment)

A benchmark on a **= b; a **= -1 versus a **= -b gives me (v1.11.3):
figure_1

(Click on details to show the script)

import numpy as np
from time import time
import matplotlib.pyplot as plt

n_points = int(1e6)
power_range = np.arange(0, 4.1, 0.1)
durations = np.zeros((2, power_range.size))

array = np.random.randn(n_points)
np.abs(array, array)

for i, power in enumerate(power_range):
    array_copy = array.copy()
    start = time()
    array_copy **= -power
    durations[0, i] = time() - start

    array_copy = array.copy()
    start = time()
    array_copy **= power
    array_copy **= -1
    durations[1, i] = time() - start


plt.figure(figsize=(10, 4))
ax = plt.gca()
ax.plot(power_range, durations[0], '-o', label='one operation')
ax.plot(power_range, durations[1], '-o', label='two operations')
ax.set(xlabel='power', ylabel='time', title='Elementwise power in Numpy')
ax.legend()
plt.show()

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions