summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/src/multiarray/einsum_sumprod.c.src30
-rw-r--r--numpy/core/tests/test_einsum.py48
-rw-r--r--numpy/distutils/ccompiler.py10
-rw-r--r--numpy/distutils/ccompiler_opt.py4
-rw-r--r--numpy/typing/_generic_alias.py2
-rw-r--r--numpy/typing/tests/test_generic_alias.py16
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)()