diff options
-rw-r--r-- | numpy/core/src/multiarray/einsum_sumprod.c.src | 30 | ||||
-rw-r--r-- | numpy/core/tests/test_einsum.py | 48 | ||||
-rw-r--r-- | numpy/distutils/ccompiler.py | 10 | ||||
-rw-r--r-- | numpy/distutils/ccompiler_opt.py | 4 | ||||
-rw-r--r-- | numpy/typing/_generic_alias.py | 2 | ||||
-rw-r--r-- | numpy/typing/tests/test_generic_alias.py | 16 |
6 files changed, 91 insertions, 19 deletions
diff --git a/numpy/core/src/multiarray/einsum_sumprod.c.src b/numpy/core/src/multiarray/einsum_sumprod.c.src index 333b8e188..4a3a460e4 100644 --- a/numpy/core/src/multiarray/einsum_sumprod.c.src +++ b/numpy/core/src/multiarray/einsum_sumprod.c.src @@ -337,13 +337,13 @@ static NPY_GCC_OPT_3 void /**begin repeat2 * #i = 0, 1, 2, 3# */ - const @type@ b@i@ = @from@(data[@i@]); - const @type@ c@i@ = @from@(data_out[@i@]); + const @temptype@ b@i@ = @from@(data[@i@]); + const @temptype@ c@i@ = @from@(data_out[@i@]); /**end repeat2**/ /**begin repeat2 * #i = 0, 1, 2, 3# */ - const @type@ abc@i@ = scalar * b@i@ + c@i@; + const @temptype@ abc@i@ = scalar * b@i@ + c@i@; /**end repeat2**/ /**begin repeat2 * #i = 0, 1, 2, 3# @@ -353,8 +353,8 @@ static NPY_GCC_OPT_3 void } #endif // !NPY_DISABLE_OPTIMIZATION for (; count > 0; --count, ++data, ++data_out) { - const @type@ b = @from@(*data); - const @type@ c = @from@(*data_out); + const @temptype@ b = @from@(*data); + const @temptype@ c = @from@(*data_out); *data_out = @to@(scalar * b + c); } #endif // NPYV check for @type@ @@ -417,14 +417,14 @@ static void /**begin repeat2 * #i = 0, 1, 2, 3# */ - const @type@ a@i@ = @from@(data0[@i@]); - const @type@ b@i@ = @from@(data1[@i@]); - const @type@ c@i@ = @from@(data_out[@i@]); + const @temptype@ a@i@ = @from@(data0[@i@]); + const @temptype@ b@i@ = @from@(data1[@i@]); + const @temptype@ c@i@ = @from@(data_out[@i@]); /**end repeat2**/ /**begin repeat2 * #i = 0, 1, 2, 3# */ - const @type@ abc@i@ = a@i@ * b@i@ + c@i@; + const @temptype@ abc@i@ = a@i@ * b@i@ + c@i@; /**end repeat2**/ /**begin repeat2 * #i = 0, 1, 2, 3# @@ -434,9 +434,9 @@ static void } #endif // !NPY_DISABLE_OPTIMIZATION for (; count > 0; --count, ++data0, ++data1, ++data_out) { - const @type@ a = @from@(*data0); - const @type@ b = @from@(*data1); - const @type@ c = @from@(*data_out); + const @temptype@ a = @from@(*data0); + const @temptype@ b = @from@(*data1); + const @temptype@ c = @from@(*data_out); *data_out = @to@(a * b + c); } #endif // NPYV check for @type@ @@ -521,14 +521,14 @@ static NPY_GCC_OPT_3 void /**begin repeat2 * #i = 0, 1, 2, 3# */ - const @type@ ab@i@ = @from@(data0[@i@]) * @from@(data1[@i@]); + const @temptype@ ab@i@ = @from@(data0[@i@]) * @from@(data1[@i@]); /**end repeat2**/ accum += ab0 + ab1 + ab2 + ab3; } #endif // !NPY_DISABLE_OPTIMIZATION for (; count > 0; --count, ++data0, ++data1) { - const @type@ a = @from@(*data0); - const @type@ b = @from@(*data1); + const @temptype@ a = @from@(*data0); + const @temptype@ b = @from@(*data1); accum += a * b; } #endif // NPYV check for @type@ diff --git a/numpy/core/tests/test_einsum.py b/numpy/core/tests/test_einsum.py index c697d0c2d..8304a0f92 100644 --- a/numpy/core/tests/test_einsum.py +++ b/numpy/core/tests/test_einsum.py @@ -1,5 +1,7 @@ import itertools +import pytest + import numpy as np from numpy.testing import ( assert_, assert_equal, assert_array_equal, assert_almost_equal, @@ -744,6 +746,52 @@ class TestEinsum: np.einsum('ij,jk->ik', x, x, out=out) assert_array_equal(out.base, correct_base) + @pytest.mark.parametrize("dtype", + np.typecodes["AllFloat"] + np.typecodes["AllInteger"]) + def test_different_paths(self, dtype): + # Test originally added to cover broken float16 path: gh-20305 + # Likely most are covered elsewhere, at least partially. + dtype = np.dtype(dtype) + # Simple test, designed to excersize most specialized code paths, + # note the +0.5 for floats. This makes sure we use a float value + # where the results must be exact. + arr = (np.arange(7) + 0.5).astype(dtype) + scalar = np.array(2, dtype=dtype) + + # contig -> scalar: + res = np.einsum('i->', arr) + assert res == arr.sum() + # contig, contig -> contig: + res = np.einsum('i,i->i', arr, arr) + assert_array_equal(res, arr * arr) + # noncontig, noncontig -> contig: + res = np.einsum('i,i->i', arr.repeat(2)[::2], arr.repeat(2)[::2]) + assert_array_equal(res, arr * arr) + # contig + contig -> scalar + assert np.einsum('i,i->', arr, arr) == (arr * arr).sum() + # contig + scalar -> contig (with out) + out = np.ones(7, dtype=dtype) + res = np.einsum('i,->i', arr, dtype.type(2), out=out) + assert_array_equal(res, arr * dtype.type(2)) + # scalar + contig -> contig (with out) + res = np.einsum(',i->i', scalar, arr) + assert_array_equal(res, arr * dtype.type(2)) + # scalar + contig -> scalar + res = np.einsum(',i->', scalar, arr) + # Use einsum to compare to not have difference due to sum round-offs: + assert res == np.einsum('i->', scalar * arr) + # contig + scalar -> scalar + res = np.einsum('i,->', arr, scalar) + # Use einsum to compare to not have difference due to sum round-offs: + assert res == np.einsum('i->', scalar * arr) + # contig + contig + contig -> scalar + arr = np.array([0.5, 0.5, 0.25, 4.5, 3.], dtype=dtype) + res = np.einsum('i,i,i->', arr, arr, arr) + assert_array_equal(res, (arr * arr * arr).sum()) + # four arrays: + res = np.einsum('i,i,i,i->', arr, arr, arr, arr) + assert_array_equal(res, (arr * arr * arr * arr).sum()) + def test_small_boolean_arrays(self): # See gh-5946. # Use array of True embedded in False. diff --git a/numpy/distutils/ccompiler.py b/numpy/distutils/ccompiler.py index 061f4862d..d86bbe31e 100644 --- a/numpy/distutils/ccompiler.py +++ b/numpy/distutils/ccompiler.py @@ -143,12 +143,18 @@ def CCompiler_spawn(self, cmd, display=None): except subprocess.CalledProcessError as exc: o = exc.output s = exc.returncode - except OSError: + except OSError as e: # OSError doesn't have the same hooks for the exception # output, but exec_command() historically would use an # empty string for EnvironmentError (base class for # OSError) - o = b'' + # o = b'' + # still that would make the end-user lost in translation! + o = f"\n\n{e}\n\n\n" + try: + o = o.encode(sys.stdout.encoding) + except AttributeError: + o = o.encode('utf8') # status previously used by exec_command() for parent # of OSError s = 127 diff --git a/numpy/distutils/ccompiler_opt.py b/numpy/distutils/ccompiler_opt.py index 1942aa06e..b18cb17ec 100644 --- a/numpy/distutils/ccompiler_opt.py +++ b/numpy/distutils/ccompiler_opt.py @@ -708,8 +708,8 @@ class _Distutils: except subprocess.CalledProcessError as exc: o = exc.output s = exc.returncode - except OSError: - o = b'' + except OSError as e: + o = e s = 127 else: return None diff --git a/numpy/typing/_generic_alias.py b/numpy/typing/_generic_alias.py index 68523827a..4195cd93e 100644 --- a/numpy/typing/_generic_alias.py +++ b/numpy/typing/_generic_alias.py @@ -178,6 +178,8 @@ class _GenericAlias: "__mro_entries__", "__reduce__", "__reduce_ex__", + "__copy__", + "__deepcopy__", }) def __getattribute__(self, name: str) -> Any: diff --git a/numpy/typing/tests/test_generic_alias.py b/numpy/typing/tests/test_generic_alias.py index 5f0ac9153..35c0da349 100644 --- a/numpy/typing/tests/test_generic_alias.py +++ b/numpy/typing/tests/test_generic_alias.py @@ -1,6 +1,7 @@ from __future__ import annotations import sys +import copy import types import pickle import weakref @@ -74,6 +75,21 @@ class TestGenericAlias: value_ref = func(NDArray_ref) assert value == value_ref + @pytest.mark.parametrize("name,func", [ + ("__copy__", lambda n: n == copy.copy(n)), + ("__deepcopy__", lambda n: n == copy.deepcopy(n)), + ]) + def test_copy(self, name: str, func: FuncType) -> None: + value = func(NDArray) + + # xref bpo-45167 + GE_398 = ( + sys.version_info[:2] == (3, 9) and sys.version_info >= (3, 9, 8) + ) + if GE_398 or sys.version_info >= (3, 10, 1): + value_ref = func(NDArray_ref) + assert value == value_ref + def test_weakref(self) -> None: """Test ``__weakref__``.""" value = weakref.ref(NDArray)() |