Imported Upstream version 1.17.4 upstream/1.17.4
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 00:49:57 +0000 (09:49 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 31 Dec 2020 00:49:57 +0000 (09:49 +0900)
27 files changed:
doc/changelog/1.17.4-changelog.rst [new file with mode: 0644]
doc/release/1.17.4-notes.rst [new file with mode: 0644]
doc/source/release.rst
numpy/core/_internal.py
numpy/core/setup.py
numpy/core/setup_common.py
numpy/core/src/multiarray/arrayobject.c
numpy/core/src/multiarray/arraytypes.c.src
numpy/core/src/multiarray/buffer.c
numpy/core/src/multiarray/buffer.h [deleted file]
numpy/core/src/multiarray/common.c
numpy/core/src/multiarray/conversion_utils.c
numpy/core/src/multiarray/ctors.c
numpy/core/src/multiarray/descriptor.c
numpy/core/src/multiarray/einsum.c.src
numpy/core/src/multiarray/getset.c
numpy/core/src/multiarray/npy_buffer.h [new file with mode: 0644]
numpy/core/src/multiarray/scalartypes.c.src
numpy/core/tests/test_einsum.py
numpy/core/tests/test_multiarray.py
numpy/lib/histograms.py
numpy/lib/tests/test_histograms.py
numpy/random/src/distributions/distributions.c
numpy/random/tests/test_generator_mt19937.py
pavement.py
setup.py
shippable.yml

diff --git a/doc/changelog/1.17.4-changelog.rst b/doc/changelog/1.17.4-changelog.rst
new file mode 100644 (file)
index 0000000..96d9f3e
--- /dev/null
@@ -0,0 +1,26 @@
+
+Contributors
+============
+
+A total of 5 people contributed to this release.  People with a "+" by their
+names contributed a patch for the first time.
+
+* Charles Harris
+* Chris Burr +
+* Matti Picus
+* Qiming Sun +
+* Warren Weckesser
+
+Pull requests merged
+====================
+
+A total of 8 pull requests were merged for this release.
+
+* `#14758 <https://github.com/numpy/numpy/pull/14758>`__: BLD: declare support for python 3.8
+* `#14781 <https://github.com/numpy/numpy/pull/14781>`__: BUG: random: biased samples from integers() with 8 or 16 bit...
+* `#14851 <https://github.com/numpy/numpy/pull/14851>`__: BUG: Fix _ctypes class circular reference. (#13808)
+* `#14852 <https://github.com/numpy/numpy/pull/14852>`__: BLD: add 'apt update' to shippable
+* `#14855 <https://github.com/numpy/numpy/pull/14855>`__: BUG: Fix `np.einsum` errors on Power9 Linux and z/Linux
+* `#14857 <https://github.com/numpy/numpy/pull/14857>`__: BUG: lib: Fix histogram problem with signed integer arrays.
+* `#14858 <https://github.com/numpy/numpy/pull/14858>`__: BLD: Prevent -flto from optimising long double representation...
+* `#14866 <https://github.com/numpy/numpy/pull/14866>`__: MAINT: move buffer.h -> npy_buffer.h to avoid conflicts
diff --git a/doc/release/1.17.4-notes.rst b/doc/release/1.17.4-notes.rst
new file mode 100644 (file)
index 0000000..47f4725
--- /dev/null
@@ -0,0 +1,49 @@
+.. currentmodule:: numpy
+
+==========================
+NumPy 1.17.4 Release Notes
+==========================
+
+This release contains fixes for bugs reported against NumPy 1.17.3 along with
+some build improvements. The Python versions supported in this release
+are 3.5-3.8.
+
+Downstream developers should use Cython >= 0.29.13 for Python 3.8 support and
+OpenBLAS >= 3.7 to avoid errors on the Skylake architecture.
+
+
+Highlights
+==========
+
+- Fixed `random.random_integers` biased generation of 8 and 16 bit integers.
+- Fixed `np.einsum` regression on Power9 and z/Linux.
+- Fixed histogram problem with signed integer arrays.
+
+
+Contributors
+============
+
+A total of 5 people contributed to this release.  People with a "+" by their
+names contributed a patch for the first time.
+
+* Charles Harris
+* Chris Burr +
+* Matti Picus
+* Qiming Sun +
+* Warren Weckesser
+
+
+Pull requests merged
+====================
+
+A total of 8 pull requests were merged for this release.
+
+* `#14758 <https://github.com/numpy/numpy/pull/14758>`__: BLD: declare support for python 3.8
+* `#14781 <https://github.com/numpy/numpy/pull/14781>`__: BUG: random: biased samples from integers() with 8 or 16 bit...
+* `#14851 <https://github.com/numpy/numpy/pull/14851>`__: BUG: Fix _ctypes class circular reference. (#13808)
+* `#14852 <https://github.com/numpy/numpy/pull/14852>`__: BLD: add 'apt update' to shippable
+* `#14855 <https://github.com/numpy/numpy/pull/14855>`__: BUG: Fix `np.einsum` errors on Power9 Linux and z/Linux
+* `#14857 <https://github.com/numpy/numpy/pull/14857>`__: BUG: lib: Fix histogram problem with signed integer arrays.
+* `#14858 <https://github.com/numpy/numpy/pull/14858>`__: BLD: Prevent -flto from optimising long double representation...
+* `#14866 <https://github.com/numpy/numpy/pull/14866>`__: MAINT: move buffer.h -> npy_buffer.h to avoid conflicts
+
index d02b552e2738b31ec6e43ad6ccb3492ba52b8804..d07dda3b992a162996a3cac7104012f95ae7572a 100644 (file)
@@ -2,6 +2,7 @@
 Release Notes
 *************
 
+.. include:: ../release/1.17.4-notes.rst
 .. include:: ../release/1.17.3-notes.rst
 .. include:: ../release/1.17.2-notes.rst
 .. include:: ../release/1.17.1-notes.rst
index b0ea603e12a44669a66eb96ade68d379d2a8f752..5fd643505b8552988ac159e1141407213c3d7524 100644 (file)
@@ -247,55 +247,13 @@ class _missing_ctypes(object):
             self.value = ptr
 
 
-class _unsafe_first_element_pointer(object):
-    """
-    Helper to allow viewing an array as a ctypes pointer to the first element
-
-    This avoids:
-      * dealing with strides
-      * `.view` rejecting object-containing arrays
-      * `memoryview` not supporting overlapping fields
-    """
-    def __init__(self, arr):
-        self.base = arr
-
-    @property
-    def __array_interface__(self):
-        i = dict(
-            shape=(),
-            typestr='|V0',
-            data=(self.base.__array_interface__['data'][0], False),
-            strides=(),
-            version=3,
-        )
-        return i
-
-
-def _get_void_ptr(arr):
-    """
-    Get a `ctypes.c_void_p` to arr.data, that keeps a reference to the array
-    """
-    import numpy as np
-    # convert to a 0d array that has a data pointer referrign to the start
-    # of arr. This holds a reference to arr.
-    simple_arr = np.asarray(_unsafe_first_element_pointer(arr))
-
-    # create a `char[0]` using the same memory.
-    c_arr = (ctypes.c_char * 0).from_buffer(simple_arr)
-
-    # finally cast to void*
-    return ctypes.cast(ctypes.pointer(c_arr), ctypes.c_void_p)
-
-
 class _ctypes(object):
     def __init__(self, array, ptr=None):
         self._arr = array
 
         if ctypes:
             self._ctypes = ctypes
-            # get a void pointer to the buffer, which keeps the array alive
-            self._data = _get_void_ptr(array)
-            assert self._data.value == ptr
+            self._data = self._ctypes.c_void_p(ptr)
         else:
             # fake a pointer-like object that holds onto the reference
             self._ctypes = _missing_ctypes()
@@ -317,7 +275,14 @@ class _ctypes(object):
 
         The returned pointer will keep a reference to the array.
         """
-        return self._ctypes.cast(self._data, obj)
+        # _ctypes.cast function causes a circular reference of self._data in
+        # self._data._objects. Attributes of self._data cannot be released
+        # until gc.collect is called. Make a copy of the pointer first then let
+        # it hold the array reference. This is a workaround to circumvent the
+        # CPython bug https://bugs.python.org/issue12836
+        ptr = self._ctypes.cast(self._data, obj)
+        ptr._arr = self._arr
+        return ptr
 
     def shape_as(self, obj):
         """
@@ -385,7 +350,7 @@ class _ctypes(object):
 
         Enables `c_func(some_array.ctypes)`
         """
-        return self._data
+        return self.data_as(ctypes.c_void_p)
 
     # kept for compatibility
     get_data = data.fget
index 338502791383b0c3eed4056198e9a3d8e6430cf1..0a2a8233e53d78958c1a64f322dec7eb5a12e086 100644 (file)
@@ -782,7 +782,7 @@ def configuration(parent_package='',top_path=None):
             join('src', 'multiarray', 'arrayobject.h'),
             join('src', 'multiarray', 'arraytypes.h'),
             join('src', 'multiarray', 'arrayfunction_override.h'),
-            join('src', 'multiarray', 'buffer.h'),
+            join('src', 'multiarray', 'npy_buffer.h'),
             join('src', 'multiarray', 'calculation.h'),
             join('src', 'multiarray', 'common.h'),
             join('src', 'multiarray', 'convert_datatype.h'),
index 307fab334322b17e7e88a5d4df6fc5f6ee17a865..80706c99f01564a9f6e3773a2fa7dfcf053a94f2 100644 (file)
@@ -265,8 +265,9 @@ def check_long_double_representation(cmd):
     except ValueError:
         # try linking to support CC="gcc -flto" or icc -ipo
         # struct needs to be volatile so it isn't optimized away
+        # additionally "clang -flto" requires the foo struct to be used
         body = body.replace('struct', 'volatile struct')
-        body += "int main(void) { return 0; }\n"
+        body += "int main(void) { return foo.before[0]; }\n"
         src, obj = cmd._compile(body, None, None, 'c')
         cmd.temp_files.append("_configtest")
         cmd.compiler.link_executable([obj], "_configtest")
index bbb736fd00248220fb557ac07de038ed1b3919f3..ebcb9b0b0fc6d9daee28324b8d29735ac33eb313 100644 (file)
@@ -48,7 +48,7 @@ maintainer email:  oliphant.travis@ieee.org
 #include "mapping.h"
 #include "getset.h"
 #include "sequence.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 #include "array_assign.h"
 #include "alloc.h"
 #include "mem_overlap.h"
index c586a0b1d5956ec57d977da09e7aa4e7256f25cd..ef51112d6796ee60258d0cf9c867b10765694718 100644 (file)
@@ -36,7 +36,7 @@
 
 #include "cblasfuncs.h"
 #include "npy_cblas.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 
 /* check for sequences, but ignore the types numpy considers scalars */
 static NPY_INLINE npy_bool
index b729027ad4be83b1d493c265c31cff2a514d5c8e..0edadee982c23562ee4f107b40effe45267438f5 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "npy_pycompat.h"
 
-#include "buffer.h"
+#include "npy_buffer.h"
 #include "common.h"
 #include "numpyos.h"
 #include "arrayobject.h"
diff --git a/numpy/core/src/multiarray/buffer.h b/numpy/core/src/multiarray/buffer.h
deleted file mode 100644 (file)
index fae413c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _NPY_PRIVATE_BUFFER_H_
-#define _NPY_PRIVATE_BUFFER_H_
-
-extern NPY_NO_EXPORT PyBufferProcs array_as_buffer;
-
-NPY_NO_EXPORT void
-_dealloc_cached_buffer_info(PyObject *self);
-
-NPY_NO_EXPORT PyArray_Descr*
-_descriptor_from_pep3118_format(char *s);
-
-NPY_NO_EXPORT int
-gentype_getbuffer(PyObject *obj, Py_buffer *view, int flags);
-
-#endif
index a17d775860cd4ea8b5afd6261bead660126dbb21..6b8cac9a77d2a89321c4e2ed15abac2d46bd5873 100644 (file)
@@ -12,7 +12,7 @@
 #include "usertypes.h"
 
 #include "common.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 
 #include "get_attr_string.h"
 #include "mem_overlap.h"
index a370874a6eaeb3cf8b7b6414b914505f756b4f75..52cb587269de7656dbf2b1a1b068b11f37f03ec2 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "conversion_utils.h"
 #include "alloc.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 
 static int
 PyArray_PyIntAsInt_ErrMsg(PyObject *o, const char * msg) NPY_GCC_NONNULL(2);
index 40e69c05c0799cdf420b004a93a677b3c29e586b..0897feaf4e94fd0123a2b0ce7265aa9b749a6160 100644 (file)
@@ -19,7 +19,7 @@
 #include "ctors.h"
 #include "convert_datatype.h"
 #include "shape.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 #include "lowlevel_strided_loops.h"
 #include "methods.h"
 #include "_datetime.h"
index 4d22c9ee73ddac835e649fec57025b704a047c97..cb4d7964e537454de57ad8d983dec45d5b7229ff 100644 (file)
@@ -19,7 +19,7 @@
 #include "descriptor.h"
 #include "alloc.h"
 #include "assert.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 
 /*
  * offset:    A starting offset.
index e7bbc3d0b284c47c6c3b7b83337ee096bac7a34a..58af4409192148d9c49f4eba80c058b5b8dcba6a 100644 (file)
@@ -1876,7 +1876,7 @@ parse_operand_subscripts(char *subscripts, int length,
      * later where it matters the char is cast to a signed char.
      */
     for (idim = 0; idim < ndim - 1; ++idim) {
-        int label = op_labels[idim];
+        int label = (signed char)op_labels[idim];
         /* If it is a proper label, find any duplicates of it. */
         if (label > 0) {
             /* Search for the next matching label. */
index bed92403fe41871cf7fac520b07604a69d88bfe8..2c4969d23b468de1d4f6d21a73edc0e4311b2e94 100644 (file)
@@ -20,7 +20,7 @@
 #include "arrayobject.h"
 #include "mem_overlap.h"
 #include "alloc.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 
 /*******************  array attribute get and set routines ******************/
 
diff --git a/numpy/core/src/multiarray/npy_buffer.h b/numpy/core/src/multiarray/npy_buffer.h
new file mode 100644 (file)
index 0000000..fae413c
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _NPY_PRIVATE_BUFFER_H_
+#define _NPY_PRIVATE_BUFFER_H_
+
+extern NPY_NO_EXPORT PyBufferProcs array_as_buffer;
+
+NPY_NO_EXPORT void
+_dealloc_cached_buffer_info(PyObject *self);
+
+NPY_NO_EXPORT PyArray_Descr*
+_descriptor_from_pep3118_format(char *s);
+
+NPY_NO_EXPORT int
+gentype_getbuffer(PyObject *obj, Py_buffer *view, int flags);
+
+#endif
index 34839b866278c851944f0921054fe3bf98a9ced4..cfb21f50e02bcd3a48a71145a91e63ed15a71453 100644 (file)
@@ -28,7 +28,7 @@
 #include "npy_import.h"
 #include "dragon4.h"
 #include "npy_longdouble.h"
-#include "buffer.h"
+#include "npy_buffer.h"
 
 #include <stdlib.h>
 
index cfeeb8a90d2f58fb849bb3cabc6bded76e566415..1b5b4cb262445b1cfbd4e41d51278ad6bfdaa469 100644 (file)
@@ -5,7 +5,7 @@ import itertools
 import numpy as np
 from numpy.testing import (
     assert_, assert_equal, assert_array_equal, assert_almost_equal,
-    assert_raises, suppress_warnings, assert_raises_regex
+    assert_raises, suppress_warnings, assert_raises_regex, assert_allclose
     )
 
 # Setup for optimize einsum
@@ -700,6 +700,14 @@ class TestEinsum(object):
         y2 = x[idx[:, None], idx[:, None], idx, idx]
         assert_equal(y1, y2)
 
+    def test_einsum_failed_on_p9_and_s390x(self):
+        # Issues gh-14692 and gh-12689
+        # Bug with signed vs unsigned char errored on power9 and s390x Linux
+        tensor = np.random.random_sample((10, 10, 10, 10))
+        x = np.einsum('ijij->', tensor)
+        y = tensor.trace(axis1=0, axis2=2).trace()
+        assert_allclose(x, y)
+
     def test_einsum_all_contig_non_contig_output(self):
         # Issue gh-5907, tests that the all contiguous special case
         # actually checks the contiguity of the output
index a0426a808ead65d3f091085d4c1d859632746dbc..6fa8548a07aeb280528a8f814fe6acc6fa903ecc 100644 (file)
@@ -7921,6 +7921,8 @@ class TestFormat(object):
                 dst = object.__format__(a, '30')
                 assert_equal(res, dst)
 
+from numpy.testing import IS_PYPY
+
 class TestCTypes(object):
 
     def test_ctypes_is_available(self):
@@ -7987,7 +7989,29 @@ class TestCTypes(object):
 
         # but when the `ctypes_ptr` object dies, so should `arr`
         del ctypes_ptr
+        if IS_PYPY:
+            # Pypy does not recycle arr objects immediately. Trigger gc to
+            # release arr. Cpython uses refcounts. An explicit call to gc
+            # should not be needed here.
+            break_cycles()
+        assert_(arr_ref() is None, "unknowable whether ctypes pointer holds a reference")
+
+    def test_ctypes_as_parameter_holds_reference(self):
+        arr = np.array([None]).copy()
+
+        arr_ref = weakref.ref(arr)
+
+        ctypes_ptr = arr.ctypes._as_parameter_
+
+        # `ctypes_ptr` should hold onto `arr`
+        del arr
         break_cycles()
+        assert_(arr_ref() is not None, "ctypes pointer did not hold onto a reference")
+
+        # but when the `ctypes_ptr` object dies, so should `arr`
+        del ctypes_ptr
+        if IS_PYPY:
+            break_cycles()
         assert_(arr_ref() is None, "unknowable whether ctypes pointer holds a reference")
 
 
index 8474bd5d3c474c405f0d2e7cb840b84926019c54..03c365ab6e3c8c9461578f1d18ce52729d055341 100644 (file)
@@ -22,6 +22,16 @@ array_function_dispatch = functools.partial(
 _range = range
 
 
+def _ptp(x):
+    """Peak-to-peak value of x.
+
+    This implementation avoids the problem of signed integer arrays having a
+    peak-to-peak value that cannot be represented with the array's data type.
+    This function returns an unsigned value for signed integer arrays.
+    """
+    return _unsigned_subtract(x.max(), x.min())
+
+
 def _hist_bin_sqrt(x, range):
     """
     Square root histogram bin estimator.
@@ -40,7 +50,7 @@ def _hist_bin_sqrt(x, range):
     h : An estimate of the optimal bin width for the given data.
     """
     del range  # unused
-    return x.ptp() / np.sqrt(x.size)
+    return _ptp(x) / np.sqrt(x.size)
 
 
 def _hist_bin_sturges(x, range):
@@ -63,7 +73,7 @@ def _hist_bin_sturges(x, range):
     h : An estimate of the optimal bin width for the given data.
     """
     del range  # unused
-    return x.ptp() / (np.log2(x.size) + 1.0)
+    return _ptp(x) / (np.log2(x.size) + 1.0)
 
 
 def _hist_bin_rice(x, range):
@@ -87,7 +97,7 @@ def _hist_bin_rice(x, range):
     h : An estimate of the optimal bin width for the given data.
     """
     del range  # unused
-    return x.ptp() / (2.0 * x.size ** (1.0 / 3))
+    return _ptp(x) / (2.0 * x.size ** (1.0 / 3))
 
 
 def _hist_bin_scott(x, range):
@@ -137,7 +147,7 @@ def _hist_bin_stone(x, range):
     """
 
     n = x.size
-    ptp_x = np.ptp(x)
+    ptp_x = _ptp(x)
     if n <= 1 or ptp_x == 0:
         return 0
 
@@ -184,7 +194,7 @@ def _hist_bin_doane(x, range):
             np.true_divide(temp, sigma, temp)
             np.power(temp, 3, temp)
             g1 = np.mean(temp)
-            return x.ptp() / (1.0 + np.log2(x.size) +
+            return _ptp(x) / (1.0 + np.log2(x.size) +
                                     np.log2(1.0 + np.absolute(g1) / sg1))
     return 0.0
 
index 4895a722cd8c2b8c296f3c6dfbcf65433c64ae54..dbf189f3e5e141f28a6a7f51e133edaf6565d48b 100644 (file)
@@ -8,6 +8,7 @@ from numpy.testing import (
     assert_array_almost_equal, assert_raises, assert_allclose,
     assert_array_max_ulp, assert_raises_regex, suppress_warnings,
     )
+import pytest
 
 
 class TestHistogram(object):
@@ -591,6 +592,16 @@ class TestHistogramOptimBinNums(object):
                 msg += " with datasize of {0}".format(testlen)
                 assert_equal(len(a), numbins, err_msg=msg)
 
+    @pytest.mark.parametrize("bins", ['auto', 'fd', 'doane', 'scott',
+                                      'stone', 'rice', 'sturges'])
+    def test_signed_integer_data(self, bins):
+        # Regression test for gh-14379.
+        a = np.array([-2, 0, 127], dtype=np.int8)
+        hist, edges = np.histogram(a, bins=bins)
+        hist32, edges32 = np.histogram(a.astype(np.int32), bins=bins)
+        assert_array_equal(hist, hist32)
+        assert_array_equal(edges, edges32)
+
     def test_simple_weighted(self):
         """
         Check that weighted data raises a TypeError
index 1244ffe653bc979c560fd76acb9ee6935989f19c..45f062c06e2a95b30e4260787fb7619e6bce77d4 100644 (file)
@@ -1297,10 +1297,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(bitgen_t *bitgen_state,
 
   if (leftover < rng_excl) {
     /* `rng_excl` is a simple upper bound for `threshold`. */
-
-    const uint64_t threshold = -rng_excl % rng_excl;
-    /* Same as: threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) %
-     * rng_excl; */
+    const uint64_t threshold = (UINT64_MAX - rng) % rng_excl;
 
     while (leftover < threshold) {
       m = ((__uint128_t)next_uint64(bitgen_state)) * rng_excl;
@@ -1323,10 +1320,7 @@ static NPY_INLINE uint64_t bounded_lemire_uint64(bitgen_t *bitgen_state,
 
   if (leftover < rng_excl) {
     /* `rng_excl` is a simple upper bound for `threshold`. */
-
-    const uint64_t threshold = -rng_excl % rng_excl;
-    /* Same as:threshold=((uint64_t)(0x10000000000000000ULLL - rng_excl)) %
-     * rng_excl; */
+    const uint64_t threshold = (UINT64_MAX - rng) % rng_excl;
 
     while (leftover < threshold) {
       x = next_uint64(bitgen_state);
@@ -1387,8 +1381,7 @@ static NPY_INLINE uint32_t buffered_bounded_lemire_uint32(
 
   if (leftover < rng_excl) {
     /* `rng_excl` is a simple upper bound for `threshold`. */
-    const uint32_t threshold = -rng_excl % rng_excl;
-    /* Same as: threshold=((uint64_t)(0x100000000ULL - rng_excl)) % rng_excl; */
+    const uint32_t threshold = (UINT32_MAX - rng) % rng_excl;
 
     while (leftover < threshold) {
       m = ((uint64_t)next_uint32(bitgen_state)) * rng_excl;
@@ -1422,8 +1415,7 @@ static NPY_INLINE uint16_t buffered_bounded_lemire_uint16(
 
   if (leftover < rng_excl) {
     /* `rng_excl` is a simple upper bound for `threshold`. */
-    const uint16_t threshold = -rng_excl % rng_excl;
-    /* Same as: threshold=((uint32_t)(0x10000ULL - rng_excl)) % rng_excl; */
+    const uint16_t threshold = (UINT16_MAX - rng) % rng_excl;
 
     while (leftover < threshold) {
       m = ((uint32_t)buffered_uint16(bitgen_state, bcnt, buf)) * rng_excl;
@@ -1458,8 +1450,7 @@ static NPY_INLINE uint8_t buffered_bounded_lemire_uint8(bitgen_t *bitgen_state,
 
   if (leftover < rng_excl) {
     /* `rng_excl` is a simple upper bound for `threshold`. */
-    const uint8_t threshold = -rng_excl % rng_excl;
-    /* Same as: threshold=((uint16_t)(0x100ULL - rng_excl)) % rng_excl; */
+    const uint8_t threshold = (UINT8_MAX - rng) % rng_excl;
 
     while (leftover < threshold) {
       m = ((uint16_t)buffered_uint8(bitgen_state, bcnt, buf)) * rng_excl;
index 853d86fbab6c4df8ea6c7f6663d2acc2ed91b88b..1f18c9ca1db1516a76df9b599551e539c8aa8705 100644 (file)
@@ -329,11 +329,11 @@ class TestIntegers(object):
                'int16':  '39624ead49ad67e37545744024d2648b',
                'int32':  '5c4810373f979336c6c0c999996e47a1',
                'int64':  'ab126c15edff26f55c50d2b7e37391ac',
-               'int8':   'd1746364b48a020dab9ef0568e6c0cd2',
+               'int8':   'ba71ccaffeeeb9eeb1860f8075020b9c',
                'uint16': '39624ead49ad67e37545744024d2648b',
                'uint32': '5c4810373f979336c6c0c999996e47a1',
                'uint64': 'ab126c15edff26f55c50d2b7e37391ac',
-               'uint8':  'd1746364b48a020dab9ef0568e6c0cd2'}
+               'uint8':  'ba71ccaffeeeb9eeb1860f8075020b9c'}
 
         for dt in self.itype[1:]:
             random = Generator(MT19937(1234))
@@ -484,6 +484,24 @@ class TestIntegers(object):
         with pytest.raises(ValueError):
             random.integers(0, 200, size=10, dtype=other_byteord_dt)
 
+    # chi2max is the maximum acceptable chi-squared value.
+    @pytest.mark.slow
+    @pytest.mark.parametrize('sample_size,high,dtype,chi2max',
+        [(5000000, 5, np.int8, 125.0),          # p-value ~4.6e-25
+         (5000000, 7, np.uint8, 150.0),         # p-value ~7.7e-30
+         (10000000, 2500, np.int16, 3300.0),    # p-value ~3.0e-25
+         (50000000, 5000, np.uint16, 6500.0),   # p-value ~3.5e-25
+        ])
+    def test_integers_small_dtype_chisquared(self, sample_size, high,
+                                             dtype, chi2max):
+        # Regression test for gh-14774.
+        samples = random.integers(high, size=sample_size, dtype=dtype)
+
+        values, counts = np.unique(samples, return_counts=True)
+        expected = sample_size / high
+        chi2 = ((counts - expected)**2 / expected).sum()
+        assert chi2 < chi2max
+
 
 class TestRandomDist(object):
     # Make sure the random distribution returns the correct value for a
index e0d3ad2233a4638e1f2daf290ede808abe0322e1..426627ebd9e5db9fd5b929d4820f3b497e615c0b 100644 (file)
@@ -42,7 +42,7 @@ from paver.easy import Bunch, options, task, sh
 #-----------------------------------
 
 # Path to the release notes
-RELEASE_NOTES = 'doc/release/1.17.3-notes.rst'
+RELEASE_NOTES = 'doc/release/1.17.4-notes.rst'
 
 
 #-------------------------------------------------------
index 6e80bcb0d87a892ffa2f3ff3936db2a1f021fd4a..a205913f27fc411bbb4eb64346cf25b4feffeb28 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -44,6 +44,7 @@ Programming Language :: Python :: 3
 Programming Language :: Python :: 3.5
 Programming Language :: Python :: 3.6
 Programming Language :: Python :: 3.7
+Programming Language :: Python :: 3.8
 Programming Language :: Python :: Implementation :: CPython
 Topic :: Software Development
 Topic :: Scientific/Engineering
@@ -55,7 +56,7 @@ Operating System :: MacOS
 
 MAJOR               = 1
 MINOR               = 17
-MICRO               = 3
+MICRO               = 4
 ISRELEASED          = True
 VERSION             = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
 
index cf09b791dbd6c304d829daa41b148d762d05a4f4..e281a4c400c8718bbfb2e99a5d0b8261802af7bf 100644 (file)
@@ -22,6 +22,7 @@ runtime:
 build:
     ci:
     # install dependencies
+    - sudo apt-get update
     - sudo apt-get install gcc gfortran
     - target=$(python tools/openblas_support.py)
     - sudo cp -r "${target}"/64/lib/* /usr/lib