From d3b628a94e615b6290736256ec5c3c6d488a20d6 Mon Sep 17 00:00:00 2001 From: warren Date: Thu, 28 Jul 2022 01:51:44 -0400 Subject: [PATCH] MAINT: stats: Work around Cython bug. Because of a bug in Cython, the inner function weigh() (a closure in _weightedrankedtau()) cannot refer to the memoryview arguments of _weightedrankedtau(). The work-around here is to assign the arguments to local variables. Closes gh-16718 --- scipy/stats/_stats.pyx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/scipy/stats/_stats.pyx b/scipy/stats/_stats.pyx index 8c06789e9ed6..6c8c3ad53714 100644 --- a/scipy/stats/_stats.pyx +++ b/scipy/stats/_stats.pyx @@ -171,6 +171,11 @@ def _toint64(x): @cython.wraparound(False) @cython.boundscheck(False) def _weightedrankedtau(ordered[:] x, ordered[:] y, intp_t[:] rank, weigher, bool additive): + # y_local and rank_local (declared below) are a work-around for a Cython + # bug; see gh-16718. When we can require Cython 3.0, y_local and + # rank_local can be removed, and the closure weigh() can refer directly + # to y and rank. + cdef ordered[:] y_local = y cdef intp_t i, first cdef float64_t t, u, v, w, s, sq cdef int64_t n = np.int64(len(x)) @@ -189,6 +194,8 @@ def _weightedrankedtau(ordered[:] x, ordered[:] y, intp_t[:] rank, weigher, bool rank[...] = perm[::-1] _invert_in_place(rank) + cdef intp_t[:] rank_local = rank + # weigh joint ties first = 0 t = 0 @@ -237,28 +244,28 @@ def _weightedrankedtau(ordered[:] x, ordered[:] y, intp_t[:] rank, weigher, bool cdef float64_t weight, residual if length == 1: - return weigher(rank[perm[offset]]) + return weigher(rank_local[perm[offset]]) length0 = length // 2 length1 = length - length0 middle = offset + length0 residual = weigh(offset, length0) weight = weigh(middle, length1) + residual - if y[perm[middle - 1]] < y[perm[middle]]: + if y_local[perm[middle - 1]] < y_local[perm[middle]]: return weight # merging i = j = k = 0 while j < length0 and k < length1: - if y[perm[offset + j]] <= y[perm[middle + k]]: + if y_local[perm[offset + j]] <= y_local[perm[middle + k]]: temp[i] = perm[offset + j] - residual -= weigher(rank[temp[i]]) + residual -= weigher(rank_local[temp[i]]) j += 1 else: temp[i] = perm[middle + k] - exchanges_weight[0] += weigher(rank[temp[i]]) * ( + exchanges_weight[0] += weigher(rank_local[temp[i]]) * ( length0 - j) + residual if additive else weigher( - rank[temp[i]]) * residual + rank_local[temp[i]]) * residual k += 1 i += 1