summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2021-05-04 15:31:41 -0600
committerGitHub <noreply@github.com>2021-05-04 15:31:41 -0600
commita59973902c6706cfc4e6958e69e9a9b33db333fb (patch)
treed6be2c2b035ee0c2ff7dc38b4dc0b8e26ed1401c /numpy
parent4d753a0cd67cc381af9d096afdafda674a37c971 (diff)
parent06fffd94729a920961648dd86a8b8e86f6c25326 (diff)
downloadnumpy-a59973902c6706cfc4e6958e69e9a9b33db333fb.tar.gz
Merge pull request #18874 from Matthew-Badin/enable-accelerate
BLD, ENH: Enable Accelerate Framework
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/setup.py5
-rw-r--r--numpy/core/tests/test_multiarray.py65
-rw-r--r--numpy/distutils/system_info.py28
-rw-r--r--numpy/linalg/setup.py5
4 files changed, 72 insertions, 31 deletions
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index df405bcaf..d1229ee8f 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -405,11 +405,6 @@ def configuration(parent_package='',top_path=None):
from numpy.distutils.system_info import (get_info, blas_opt_info,
lapack_opt_info)
- # Accelerate is buggy, disallow it. See also numpy/linalg/setup.py
- for opt_order in (blas_opt_info.blas_order, lapack_opt_info.lapack_order):
- if 'accelerate' in opt_order:
- opt_order.remove('accelerate')
-
config = Configuration('core', parent_package, top_path)
local_dir = config.local_path
codegen_dir = join(local_dir, 'code_generators')
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 2dea5518c..1ac2abba1 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -6212,6 +6212,71 @@ class TestDot:
assert_equal(np.dot(b, a), res)
assert_equal(np.dot(b, b), res)
+ def test_accelerate_framework_sgemv_fix(self):
+
+ def aligned_array(shape, align, dtype, order='C'):
+ d = dtype(0)
+ N = np.prod(shape)
+ tmp = np.zeros(N * d.nbytes + align, dtype=np.uint8)
+ address = tmp.__array_interface__["data"][0]
+ for offset in range(align):
+ if (address + offset) % align == 0:
+ break
+ tmp = tmp[offset:offset+N*d.nbytes].view(dtype=dtype)
+ return tmp.reshape(shape, order=order)
+
+ def as_aligned(arr, align, dtype, order='C'):
+ aligned = aligned_array(arr.shape, align, dtype, order)
+ aligned[:] = arr[:]
+ return aligned
+
+ def assert_dot_close(A, X, desired):
+ assert_allclose(np.dot(A, X), desired, rtol=1e-5, atol=1e-7)
+
+ m = aligned_array(100, 15, np.float32)
+ s = aligned_array((100, 100), 15, np.float32)
+ np.dot(s, m) # this will always segfault if the bug is present
+
+ testdata = itertools.product((15, 32), (10000,), (200, 89), ('C', 'F'))
+ for align, m, n, a_order in testdata:
+ # Calculation in double precision
+ A_d = np.random.rand(m, n)
+ X_d = np.random.rand(n)
+ desired = np.dot(A_d, X_d)
+ # Calculation with aligned single precision
+ A_f = as_aligned(A_d, align, np.float32, order=a_order)
+ X_f = as_aligned(X_d, align, np.float32)
+ assert_dot_close(A_f, X_f, desired)
+ # Strided A rows
+ A_d_2 = A_d[::2]
+ desired = np.dot(A_d_2, X_d)
+ A_f_2 = A_f[::2]
+ assert_dot_close(A_f_2, X_f, desired)
+ # Strided A columns, strided X vector
+ A_d_22 = A_d_2[:, ::2]
+ X_d_2 = X_d[::2]
+ desired = np.dot(A_d_22, X_d_2)
+ A_f_22 = A_f_2[:, ::2]
+ X_f_2 = X_f[::2]
+ assert_dot_close(A_f_22, X_f_2, desired)
+ # Check the strides are as expected
+ if a_order == 'F':
+ assert_equal(A_f_22.strides, (8, 8 * m))
+ else:
+ assert_equal(A_f_22.strides, (8 * n, 8))
+ assert_equal(X_f_2.strides, (8,))
+ # Strides in A rows + cols only
+ X_f_2c = as_aligned(X_f_2, align, np.float32)
+ assert_dot_close(A_f_22, X_f_2c, desired)
+ # Strides just in A cols
+ A_d_12 = A_d[:, ::2]
+ desired = np.dot(A_d_12, X_d_2)
+ A_f_12 = A_f[:, ::2]
+ assert_dot_close(A_f_12, X_f_2c, desired)
+ # Strides in A cols and X
+ assert_dot_close(A_f_12, X_f_2, desired)
+
+
class MatmulCommon:
"""Common tests for '@' operator and numpy.matmul.
diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py
index 85a0c9321..82e864a5c 100644
--- a/numpy/distutils/system_info.py
+++ b/numpy/distutils/system_info.py
@@ -375,22 +375,6 @@ default_src_dirs = [_m for _m in default_src_dirs if os.path.isdir(_m)]
so_ext = get_shared_lib_extension()
-def is_symlink_to_accelerate(filename):
- accelpath = '/System/Library/Frameworks/Accelerate.framework'
- return (sys.platform == 'darwin' and os.path.islink(filename) and
- os.path.realpath(filename).startswith(accelpath))
-
-
-_accel_msg = (
- 'Found {filename}, but that file is a symbolic link to the '
- 'MacOS Accelerate framework, which is not supported by NumPy. '
- 'You must configure the build to use a different optimized library, '
- 'or disable the use of optimized BLAS and LAPACK by setting the '
- 'environment variables NPY_BLAS_ORDER="" and NPY_LAPACK_ORDER="" '
- 'before building NumPy.'
-)
-
-
def get_standard_file(fname):
"""Returns a list of files named 'fname' from
1) System-wide directory (directory-location of this module)
@@ -539,6 +523,7 @@ def get_info(name, notfound_action=0):
'blis': blis_info, # use blas_opt instead
'lapack_mkl': lapack_mkl_info, # use lapack_opt instead
'blas_mkl': blas_mkl_info, # use blas_opt instead
+ 'accelerate': accelerate_info, # use blas_opt instead
'openblas64_': openblas64__info,
'openblas64__lapack': openblas64__lapack_info,
'openblas_ilp64': openblas_ilp64_info,
@@ -1029,9 +1014,6 @@ class system_info:
for prefix in lib_prefixes:
p = self.combine_paths(lib_dir, prefix + lib + ext)
if p:
- # p[0] is the full path to the binary library file.
- if is_symlink_to_accelerate(p[0]):
- raise RuntimeError(_accel_msg.format(filename=p[0]))
break
if p:
assert len(p) == 1
@@ -1766,8 +1748,10 @@ def get_atlas_version(**config):
class lapack_opt_info(system_info):
notfounderror = LapackNotFoundError
+
# List of all known LAPACK libraries, in the default order
- lapack_order = ['mkl', 'openblas', 'flame', 'atlas', 'lapack']
+ lapack_order = ['mkl', 'openblas', 'flame',
+ 'accelerate', 'atlas', 'lapack']
order_env_var_name = 'NPY_LAPACK_ORDER'
def _calc_info_mkl(self):
@@ -1942,7 +1926,9 @@ class lapack64__opt_info(lapack_ilp64_opt_info):
class blas_opt_info(system_info):
notfounderror = BlasNotFoundError
# List of all known BLAS libraries, in the default order
- blas_order = ['mkl', 'blis', 'openblas', 'atlas', 'blas']
+
+ blas_order = ['mkl', 'blis', 'openblas',
+ 'accelerate', 'atlas', 'blas']
order_env_var_name = 'NPY_BLAS_ORDER'
def _calc_info_mkl(self):
diff --git a/numpy/linalg/setup.py b/numpy/linalg/setup.py
index 5c9f2a4cb..e2944f38c 100644
--- a/numpy/linalg/setup.py
+++ b/numpy/linalg/setup.py
@@ -9,11 +9,6 @@ def configuration(parent_package='', top_path=None):
config.add_subpackage('tests')
- # Accelerate is buggy, disallow it. See also numpy/core/setup.py
- for opt_order in (blas_opt_info.blas_order, lapack_opt_info.lapack_order):
- if 'accelerate' in opt_order:
- opt_order.remove('accelerate')
-
# Configure lapack_lite
src_dir = 'lapack_lite'