diff options
Diffstat (limited to 'numpy/linalg')
| -rw-r--r-- | numpy/linalg/lapack_lite/f2c.c | 4 | ||||
| -rw-r--r-- | numpy/linalg/lapack_lite/f2c.h | 3 | ||||
| -rw-r--r-- | numpy/linalg/lapack_lite/f2c_blas.c | 20 | ||||
| -rw-r--r-- | numpy/linalg/lapack_lite/f2c_blas.c.patch | 112 | ||||
| -rw-r--r-- | numpy/linalg/linalg.py | 36 | ||||
| -rw-r--r-- | numpy/linalg/meson.build | 56 | ||||
| -rw-r--r-- | numpy/linalg/setup.py | 2 | ||||
| -rw-r--r-- | numpy/linalg/tests/test_linalg.py | 5 | ||||
| -rw-r--r-- | numpy/linalg/tests/test_regression.py | 5 | ||||
| -rw-r--r-- | numpy/linalg/umath_linalg.cpp | 81 |
10 files changed, 259 insertions, 65 deletions
diff --git a/numpy/linalg/lapack_lite/f2c.c b/numpy/linalg/lapack_lite/f2c.c index 869fce5d3..ddaa8d172 100644 --- a/numpy/linalg/lapack_lite/f2c.c +++ b/numpy/linalg/lapack_lite/f2c.c @@ -7,10 +7,14 @@ it is available, and shipping a static library isn't portable. */ +#define PY_SSIZE_T_CLEAN +#include <Python.h> + #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> + #include "f2c.h" diff --git a/numpy/linalg/lapack_lite/f2c.h b/numpy/linalg/lapack_lite/f2c.h index b44aaac44..0db1b9ecb 100644 --- a/numpy/linalg/lapack_lite/f2c.h +++ b/numpy/linalg/lapack_lite/f2c.h @@ -7,6 +7,9 @@ #ifndef F2C_INCLUDE #define F2C_INCLUDE +#define PY_SSIZE_T_CLEAN +#include <Python.h> + #include <math.h> #include "numpy/npy_common.h" #include "npy_cblas.h" diff --git a/numpy/linalg/lapack_lite/f2c_blas.c b/numpy/linalg/lapack_lite/f2c_blas.c index 65286892f..9a9fd3f9b 100644 --- a/numpy/linalg/lapack_lite/f2c_blas.c +++ b/numpy/linalg/lapack_lite/f2c_blas.c @@ -380,7 +380,6 @@ L20: static logical nota, notb; static complex temp; static logical conja, conjb; - static integer ncola; extern logical lsame_(char *, char *); static integer nrowa, nrowb; extern /* Subroutine */ int xerbla_(char *, integer *); @@ -514,7 +513,7 @@ L20: Set NOTA and NOTB as true if A and B respectively are not conjugated or transposed, set CONJA and CONJB as true if A and B respectively are to be transposed but not conjugated and set - NROWA, NCOLA and NROWB as the number of rows and columns of A + NROWA and NROWB as the number of rows and columns of A and the number of rows of B respectively. */ @@ -536,10 +535,8 @@ L20: conjb = lsame_(transb, "C"); if (nota) { nrowa = *m; - ncola = *k; } else { nrowa = *k; - ncola = *m; } if (notb) { nrowb = *k; @@ -6850,7 +6847,6 @@ L60: static integer i__, j, l, info; static logical nota, notb; static doublereal temp; - static integer ncola; extern logical lsame_(char *, char *); static integer nrowa, nrowb; extern /* Subroutine */ int xerbla_(char *, integer *); @@ -6982,7 +6978,7 @@ L60: Set NOTA and NOTB as true if A and B respectively are not - transposed and set NROWA, NCOLA and NROWB as the number of rows + transposed and set NROWA and NROWB as the number of rows and columns of A and the number of rows of B respectively. */ @@ -7002,10 +6998,8 @@ L60: notb = lsame_(transb, "N"); if (nota) { nrowa = *m; - ncola = *k; } else { nrowa = *k; - ncola = *m; } if (notb) { nrowb = *k; @@ -11454,7 +11448,6 @@ L60: static integer i__, j, l, info; static logical nota, notb; static real temp; - static integer ncola; extern logical lsame_(char *, char *); static integer nrowa, nrowb; extern /* Subroutine */ int xerbla_(char *, integer *); @@ -11586,7 +11579,7 @@ L60: Set NOTA and NOTB as true if A and B respectively are not - transposed and set NROWA, NCOLA and NROWB as the number of rows + transposed and set NROWA and NROWB as the number of rows and columns of A and the number of rows of B respectively. */ @@ -11606,10 +11599,8 @@ L60: notb = lsame_(transb, "N"); if (nota) { nrowa = *m; - ncola = *k; } else { nrowa = *k; - ncola = *m; } if (notb) { nrowb = *k; @@ -15667,7 +15658,6 @@ L20: static logical nota, notb; static doublecomplex temp; static logical conja, conjb; - static integer ncola; extern logical lsame_(char *, char *); static integer nrowa, nrowb; extern /* Subroutine */ int xerbla_(char *, integer *); @@ -15801,7 +15791,7 @@ L20: Set NOTA and NOTB as true if A and B respectively are not conjugated or transposed, set CONJA and CONJB as true if A and B respectively are to be transposed but not conjugated and set - NROWA, NCOLA and NROWB as the number of rows and columns of A + NROWA and NROWB as the number of rows and columns of A and the number of rows of B respectively. */ @@ -15823,10 +15813,8 @@ L20: conjb = lsame_(transb, "C"); if (nota) { nrowa = *m; - ncola = *k; } else { nrowa = *k; - ncola = *m; } if (notb) { nrowb = *k; diff --git a/numpy/linalg/lapack_lite/f2c_blas.c.patch b/numpy/linalg/lapack_lite/f2c_blas.c.patch new file mode 100644 index 000000000..59a6a1919 --- /dev/null +++ b/numpy/linalg/lapack_lite/f2c_blas.c.patch @@ -0,0 +1,112 @@ +@@ -380,7 +380,6 @@ L20: + static logical nota, notb; + static complex temp; + static logical conja, conjb; +- static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); +@@ -514,7 +513,7 @@ L20: + Set NOTA and NOTB as true if A and B respectively are not + conjugated or transposed, set CONJA and CONJB as true if A and + B respectively are to be transposed but not conjugated and set +- NROWA, NCOLA and NROWB as the number of rows and columns of A ++ NROWA and NROWB as the number of rows and columns of A + and the number of rows of B respectively. + */ + +@@ -536,10 +535,8 @@ L20: + conjb = lsame_(transb, "C"); + if (nota) { + nrowa = *m; +- ncola = *k; + } else { + nrowa = *k; +- ncola = *m; + } + if (notb) { + nrowb = *k; +@@ -6850,7 +6847,6 @@ L60: + static integer i__, j, l, info; + static logical nota, notb; + static doublereal temp; +- static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); +@@ -6982,7 +6978,7 @@ L60: + + + Set NOTA and NOTB as true if A and B respectively are not +- transposed and set NROWA, NCOLA and NROWB as the number of rows ++ transposed and set NROWA and NROWB as the number of rows + and columns of A and the number of rows of B respectively. + */ + +@@ -7002,10 +6998,8 @@ L60: + notb = lsame_(transb, "N"); + if (nota) { + nrowa = *m; +- ncola = *k; + } else { + nrowa = *k; +- ncola = *m; + } + if (notb) { + nrowb = *k; +@@ -11454,7 +11448,6 @@ L60: + static integer i__, j, l, info; + static logical nota, notb; + static real temp; +- static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); +@@ -11586,7 +11579,7 @@ L60: + + + Set NOTA and NOTB as true if A and B respectively are not +- transposed and set NROWA, NCOLA and NROWB as the number of rows ++ transposed and set NROWA and NROWB as the number of rows + and columns of A and the number of rows of B respectively. + */ + +@@ -11606,10 +11599,8 @@ L60: + notb = lsame_(transb, "N"); + if (nota) { + nrowa = *m; +- ncola = *k; + } else { + nrowa = *k; +- ncola = *m; + } + if (notb) { + nrowb = *k; +@@ -15667,7 +15658,6 @@ L20: + static logical nota, notb; + static doublecomplex temp; + static logical conja, conjb; +- static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); +@@ -15801,7 +15791,7 @@ L20: + Set NOTA and NOTB as true if A and B respectively are not + conjugated or transposed, set CONJA and CONJB as true if A and + B respectively are to be transposed but not conjugated and set +- NROWA, NCOLA and NROWB as the number of rows and columns of A ++ NROWA and NROWB as the number of rows and columns of A + and the number of rows of B respectively. + */ + +@@ -15823,10 +15813,8 @@ L20: + conjb = lsame_(transb, "C"); + if (nota) { + nrowa = *m; +- ncola = *k; + } else { + nrowa = *k; +- ncola = *m; + } + if (notb) { + nrowb = *k; diff --git a/numpy/linalg/linalg.py b/numpy/linalg/linalg.py index 697193321..78927d1ae 100644 --- a/numpy/linalg/linalg.py +++ b/numpy/linalg/linalg.py @@ -18,17 +18,17 @@ import functools import operator import warnings +from .._utils import set_module from numpy.core import ( array, asarray, zeros, empty, empty_like, intc, single, double, csingle, cdouble, inexact, complexfloating, newaxis, all, Inf, dot, add, multiply, sqrt, sum, isfinite, - finfo, errstate, geterrobj, moveaxis, amin, amax, product, abs, + finfo, errstate, geterrobj, moveaxis, amin, amax, prod, abs, atleast_2d, intp, asanyarray, object_, matmul, swapaxes, divide, count_nonzero, isnan, sign, argsort, sort, reciprocal ) from numpy.core.multiarray import normalize_axis_index -from numpy.core.overrides import set_module from numpy.core import overrides from numpy.lib.twodim_base import triu, eye from numpy.linalg import _umath_linalg @@ -42,11 +42,11 @@ fortran_int = intc @set_module('numpy.linalg') -class LinAlgError(Exception): +class LinAlgError(ValueError): """ Generic Python-exception-derived object raised by linalg functions. - General purpose exception class, derived from Python's exception.Exception + General purpose exception class, derived from Python's ValueError class, programmatically raised in linalg functions when a Linear Algebra-related condition would prevent further correct execution of the function. @@ -138,24 +138,24 @@ def _commonType(*arrays): result_type = single is_complex = False for a in arrays: - if issubclass(a.dtype.type, inexact): - if isComplexType(a.dtype.type): + type_ = a.dtype.type + if issubclass(type_, inexact): + if isComplexType(type_): is_complex = True - rt = _realType(a.dtype.type, default=None) - if rt is None: + rt = _realType(type_, default=None) + if rt is double: + result_type = double + elif rt is None: # unsupported inexact scalar raise TypeError("array type %s is unsupported in linalg" % (a.dtype.name,)) else: - rt = double - if rt is double: result_type = double if is_complex: - t = cdouble result_type = _complex_types_map[result_type] + return cdouble, result_type else: - t = double - return t, result_type + return double, result_type def _to_native_byte_order(*arrays): @@ -196,7 +196,7 @@ def _assert_finite(*arrays): def _is_empty_2d(arr): # check size first for efficiency - return arr.size == 0 and product(arr.shape[-2:]) == 0 + return arr.size == 0 and prod(arr.shape[-2:]) == 0 def transpose(a): @@ -899,12 +899,12 @@ def qr(a, mode='reduced'): msg = "".join(( "The 'full' option is deprecated in favor of 'reduced'.\n", "For backward compatibility let mode default.")) - warnings.warn(msg, DeprecationWarning, stacklevel=3) + warnings.warn(msg, DeprecationWarning, stacklevel=2) mode = 'reduced' elif mode in ('e', 'economic'): # 2013-04-01, 1.8 msg = "The 'economic' option is deprecated." - warnings.warn(msg, DeprecationWarning, stacklevel=3) + warnings.warn(msg, DeprecationWarning, stacklevel=2) mode = 'economic' else: raise ValueError(f"Unrecognized mode '{mode}'") @@ -943,7 +943,7 @@ def qr(a, mode='reduced'): return wrap(a) # mc is the number of columns in the resulting q - # matrix. If the mode is complete then it is + # matrix. If the mode is complete then it is # same as number of rows, and if the mode is reduced, # then it is the minimum of number of rows and columns. if mode == 'complete' and m > n: @@ -2267,7 +2267,7 @@ def lstsq(a, b, rcond="warn"): "To use the future default and silence this warning " "we advise to pass `rcond=None`, to keep using the old, " "explicitly pass `rcond=-1`.", - FutureWarning, stacklevel=3) + FutureWarning, stacklevel=2) rcond = -1 if rcond is None: rcond = finfo(t).eps * max(n, m) diff --git a/numpy/linalg/meson.build b/numpy/linalg/meson.build new file mode 100644 index 000000000..083692913 --- /dev/null +++ b/numpy/linalg/meson.build @@ -0,0 +1,56 @@ +lapack_lite_sources = [ + 'lapack_lite/f2c.c', + 'lapack_lite/f2c_c_lapack.c', + 'lapack_lite/f2c_d_lapack.c', + 'lapack_lite/f2c_s_lapack.c', + 'lapack_lite/f2c_z_lapack.c', + 'lapack_lite/f2c_blas.c', + 'lapack_lite/f2c_config.c', + 'lapack_lite/f2c_lapack.c', + 'lapack_lite/python_xerbla.c', +] + +# TODO: ILP64 support + +lapack_lite_module_src = ['lapack_litemodule.c'] +if not have_lapack + warning('LAPACK was not found, NumPy is using an unoptimized, naive build from sources!') + lapack_lite_module_src += lapack_lite_sources +endif + +py.extension_module('lapack_lite', + lapack_lite_module_src, + dependencies: [np_core_dep, lapack], + install: true, + subdir: 'numpy/linalg', +) + +_umath_linalg_src = ['umath_linalg.cpp'] + lapack_lite_sources + +py.extension_module('_umath_linalg', + _umath_linalg_src, + dependencies: np_core_dep, + link_with: npymath_lib, + install: true, + subdir: 'numpy/linalg', +) + +py.install_sources( + [ + '__init__.py', + '__init__.pyi', + 'linalg.py', + 'linalg.pyi', + ], + subdir: 'numpy/linalg' +) + +py.install_sources( + [ + 'tests/__init__.py', + 'tests/test_deprecations.py', + 'tests/test_linalg.py', + 'tests/test_regression.py', + ], + subdir: 'numpy/linalg/tests' +) diff --git a/numpy/linalg/setup.py b/numpy/linalg/setup.py index 1c4e1295e..6f72635ab 100644 --- a/numpy/linalg/setup.py +++ b/numpy/linalg/setup.py @@ -4,7 +4,6 @@ import sysconfig def configuration(parent_package='', top_path=None): from numpy.distutils.misc_util import Configuration - from numpy.distutils.ccompiler_opt import NPY_CXX_FLAGS from numpy.distutils.system_info import get_info, system_info config = Configuration('linalg', parent_package, top_path) @@ -81,7 +80,6 @@ def configuration(parent_package='', top_path=None): sources=['umath_linalg.cpp', get_lapack_lite_sources], depends=['lapack_lite/f2c.h'], extra_info=lapack_info, - extra_cxx_compile_args=NPY_CXX_FLAGS, libraries=['npymath'], ) config.add_data_files('*.pyi') diff --git a/numpy/linalg/tests/test_linalg.py b/numpy/linalg/tests/test_linalg.py index f871a5f8e..b1dbd4c22 100644 --- a/numpy/linalg/tests/test_linalg.py +++ b/numpy/linalg/tests/test_linalg.py @@ -19,7 +19,7 @@ from numpy.linalg.linalg import _multi_dot_matrix_chain_order from numpy.testing import ( assert_, assert_equal, assert_raises, assert_array_equal, assert_almost_equal, assert_allclose, suppress_warnings, - assert_raises_regex, HAS_LAPACK64, + assert_raises_regex, HAS_LAPACK64, IS_WASM ) @@ -1063,6 +1063,7 @@ class TestMatrixPower: assert_raises(LinAlgError, matrix_power, np.array([[1], [2]], dt), 1) assert_raises(LinAlgError, matrix_power, np.ones((4, 3, 2), dt), 1) + @pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm") def test_exceptions_not_invertible(self, dt): if dt in self.dtnoinv: return @@ -1845,6 +1846,7 @@ def test_byteorder_check(): assert_array_equal(res, routine(sw_arr)) +@pytest.mark.skipif(IS_WASM, reason="fp errors don't work in wasm") def test_generalized_raise_multiloop(): # It should raise an error even if the error doesn't occur in the # last iteration of the ufunc inner loop @@ -1908,6 +1910,7 @@ def test_xerbla_override(): pytest.skip('Numpy xerbla not linked in.') +@pytest.mark.skipif(IS_WASM, reason="Cannot start subprocess") @pytest.mark.slow def test_sdot_bug_8577(): # Regression test that loading certain other libraries does not diff --git a/numpy/linalg/tests/test_regression.py b/numpy/linalg/tests/test_regression.py index 7ed932bc9..af38443a9 100644 --- a/numpy/linalg/tests/test_regression.py +++ b/numpy/linalg/tests/test_regression.py @@ -107,10 +107,7 @@ class TestRegression: assert_raises(ValueError, linalg.norm, testvector, ord='nuc') assert_raises(ValueError, linalg.norm, testvector, ord=np.inf) assert_raises(ValueError, linalg.norm, testvector, ord=-np.inf) - with warnings.catch_warnings(): - warnings.simplefilter("error", DeprecationWarning) - assert_raises((AttributeError, DeprecationWarning), - linalg.norm, testvector, ord=0) + assert_raises(ValueError, linalg.norm, testvector, ord=0) assert_raises(ValueError, linalg.norm, testvector, ord=-1) assert_raises(ValueError, linalg.norm, testvector, ord=-2) diff --git a/numpy/linalg/umath_linalg.cpp b/numpy/linalg/umath_linalg.cpp index bbb4bb896..68db2b2f1 100644 --- a/numpy/linalg/umath_linalg.cpp +++ b/numpy/linalg/umath_linalg.cpp @@ -22,6 +22,7 @@ #include <cstdio> #include <cassert> #include <cmath> +#include <type_traits> #include <utility> @@ -1148,7 +1149,7 @@ slogdet(char **args, void *NPY_UNUSED(func)) { fortran_int m; - npy_uint8 *tmp_buff = NULL; + char *tmp_buff = NULL; size_t matrix_size; size_t pivot_size; size_t safe_m; @@ -1162,10 +1163,11 @@ slogdet(char **args, */ INIT_OUTER_LOOP_3 m = (fortran_int) dimensions[0]; - safe_m = m; + /* avoid empty malloc (buffers likely unused) and ensure m is `size_t` */ + safe_m = m != 0 ? m : 1; matrix_size = safe_m * safe_m * sizeof(typ); pivot_size = safe_m * sizeof(fortran_int); - tmp_buff = (npy_uint8 *)malloc(matrix_size + pivot_size); + tmp_buff = (char *)malloc(matrix_size + pivot_size); if (tmp_buff) { LINEARIZE_DATA_t lin_data; @@ -1182,6 +1184,13 @@ slogdet(char **args, free(tmp_buff); } + else { + /* TODO: Requires use of new ufunc API to indicate error return */ + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + PyErr_NoMemory(); + NPY_DISABLE_C_API; + } } template<typename typ, typename basetyp> @@ -1192,7 +1201,7 @@ det(char **args, void *NPY_UNUSED(func)) { fortran_int m; - npy_uint8 *tmp_buff; + char *tmp_buff; size_t matrix_size; size_t pivot_size; size_t safe_m; @@ -1206,10 +1215,11 @@ det(char **args, */ INIT_OUTER_LOOP_2 m = (fortran_int) dimensions[0]; - safe_m = m; + /* avoid empty malloc (buffers likely unused) and ensure m is `size_t` */ + safe_m = m != 0 ? m : 1; matrix_size = safe_m * safe_m * sizeof(typ); pivot_size = safe_m * sizeof(fortran_int); - tmp_buff = (npy_uint8 *)malloc(matrix_size + pivot_size); + tmp_buff = (char *)malloc(matrix_size + pivot_size); if (tmp_buff) { LINEARIZE_DATA_t lin_data; @@ -1230,6 +1240,13 @@ det(char **args, free(tmp_buff); } + else { + /* TODO: Requires use of new ufunc API to indicate error return */ + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + PyErr_NoMemory(); + NPY_DISABLE_C_API; + } } @@ -3737,16 +3754,16 @@ scalar_trait) fortran_int lda = fortran_int_max(1, m); fortran_int ldb = fortran_int_max(1, fortran_int_max(m,n)); - mem_buff = (npy_uint8 *)malloc(a_size + b_size + s_size); - - if (!mem_buff) - goto error; + size_t msize = a_size + b_size + s_size; + mem_buff = (npy_uint8 *)malloc(msize != 0 ? msize : 1); + if (!mem_buff) { + goto no_memory; + } a = mem_buff; b = a + a_size; s = b + b_size; - params->M = m; params->N = n; params->NRHS = nrhs; @@ -3766,9 +3783,9 @@ scalar_trait) params->RWORK = NULL; params->LWORK = -1; - if (call_gelsd(params) != 0) + if (call_gelsd(params) != 0) { goto error; - + } work_count = (fortran_int)work_size_query; work_size = (size_t) work_size_query * sizeof(ftyp); @@ -3776,9 +3793,9 @@ scalar_trait) } mem_buff2 = (npy_uint8 *)malloc(work_size + iwork_size); - if (!mem_buff2) - goto error; - + if (!mem_buff2) { + goto no_memory; + } work = mem_buff2; iwork = work + work_size; @@ -3788,12 +3805,18 @@ scalar_trait) params->LWORK = work_count; return 1; + + no_memory: + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + PyErr_NoMemory(); + NPY_DISABLE_C_API; + error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff); free(mem_buff2); memset(params, 0, sizeof(*params)); - return 0; } @@ -3857,16 +3880,17 @@ using frealtyp = basetype_t<ftyp>; fortran_int lda = fortran_int_max(1, m); fortran_int ldb = fortran_int_max(1, fortran_int_max(m,n)); - mem_buff = (npy_uint8 *)malloc(a_size + b_size + s_size); + size_t msize = a_size + b_size + s_size; + mem_buff = (npy_uint8 *)malloc(msize != 0 ? msize : 1); - if (!mem_buff) - goto error; + if (!mem_buff) { + goto no_memory; + } a = mem_buff; b = a + a_size; s = b + b_size; - params->M = m; params->N = n; params->NRHS = nrhs; @@ -3887,8 +3911,9 @@ using frealtyp = basetype_t<ftyp>; params->RWORK = &rwork_size_query; params->LWORK = -1; - if (call_gelsd(params) != 0) + if (call_gelsd(params) != 0) { goto error; + } work_count = (fortran_int)work_size_query.r; @@ -3898,8 +3923,9 @@ using frealtyp = basetype_t<ftyp>; } mem_buff2 = (npy_uint8 *)malloc(work_size + rwork_size + iwork_size); - if (!mem_buff2) - goto error; + if (!mem_buff2) { + goto no_memory; + } work = mem_buff2; rwork = work + work_size; @@ -3911,6 +3937,13 @@ using frealtyp = basetype_t<ftyp>; params->LWORK = work_count; return 1; + + no_memory: + NPY_ALLOW_C_API_DEF + NPY_ALLOW_C_API; + PyErr_NoMemory(); + NPY_DISABLE_C_API; + error: TRACE_TXT("%s failed init\n", __FUNCTION__); free(mem_buff); |
