Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2Array methods which are called by both the C-code for the method 

3and the Python code for the NumPy-namespace function 

4 

5""" 

6import warnings 

7 

8from numpy.core import multiarray as mu 

9from numpy.core import umath as um 

10from numpy.core._asarray import asanyarray 

11from numpy.core import numerictypes as nt 

12from numpy.core import _exceptions 

13from numpy._globals import _NoValue 

14from numpy.compat import pickle, os_fspath, contextlib_nullcontext 

15 

16# save those O(100) nanoseconds! 

17umr_maximum = um.maximum.reduce 

18umr_minimum = um.minimum.reduce 

19umr_sum = um.add.reduce 

20umr_prod = um.multiply.reduce 

21umr_any = um.logical_or.reduce 

22umr_all = um.logical_and.reduce 

23 

24# Complex types to -> (2,)float view for fast-path computation in _var() 

25_complex_to_float = { 

26 nt.dtype(nt.csingle) : nt.dtype(nt.single), 

27 nt.dtype(nt.cdouble) : nt.dtype(nt.double), 

28} 

29# Special case for windows: ensure double takes precedence 

30if nt.dtype(nt.longdouble) != nt.dtype(nt.double): 

31 _complex_to_float.update({ 

32 nt.dtype(nt.clongdouble) : nt.dtype(nt.longdouble), 

33 }) 

34 

35# avoid keyword arguments to speed up parsing, saves about 15%-20% for very 

36# small reductions 

37def _amax(a, axis=None, out=None, keepdims=False, 

38 initial=_NoValue, where=True): 

39 return umr_maximum(a, axis, None, out, keepdims, initial, where) 

40 

41def _amin(a, axis=None, out=None, keepdims=False, 

42 initial=_NoValue, where=True): 

43 return umr_minimum(a, axis, None, out, keepdims, initial, where) 

44 

45def _sum(a, axis=None, dtype=None, out=None, keepdims=False, 

46 initial=_NoValue, where=True): 

47 return umr_sum(a, axis, dtype, out, keepdims, initial, where) 

48 

49def _prod(a, axis=None, dtype=None, out=None, keepdims=False, 

50 initial=_NoValue, where=True): 

51 return umr_prod(a, axis, dtype, out, keepdims, initial, where) 

52 

53def _any(a, axis=None, dtype=None, out=None, keepdims=False): 

54 return umr_any(a, axis, dtype, out, keepdims) 

55 

56def _all(a, axis=None, dtype=None, out=None, keepdims=False): 

57 return umr_all(a, axis, dtype, out, keepdims) 

58 

59def _count_reduce_items(arr, axis): 

60 if axis is None: 

61 axis = tuple(range(arr.ndim)) 

62 if not isinstance(axis, tuple): 

63 axis = (axis,) 

64 items = 1 

65 for ax in axis: 

66 items *= arr.shape[mu.normalize_axis_index(ax, arr.ndim)] 

67 return items 

68 

69# Numpy 1.17.0, 2019-02-24 

70# Various clip behavior deprecations, marked with _clip_dep as a prefix. 

71 

72def _clip_dep_is_scalar_nan(a): 

73 # guarded to protect circular imports 

74 from numpy.core.fromnumeric import ndim 

75 if ndim(a) != 0: 

76 return False 

77 try: 

78 return um.isnan(a) 

79 except TypeError: 

80 return False 

81 

82def _clip_dep_is_byte_swapped(a): 

83 if isinstance(a, mu.ndarray): 

84 return not a.dtype.isnative 

85 return False 

86 

87def _clip_dep_invoke_with_casting(ufunc, *args, out=None, casting=None, **kwargs): 

88 # normal path 

89 if casting is not None: 

90 return ufunc(*args, out=out, casting=casting, **kwargs) 

91 

92 # try to deal with broken casting rules 

93 try: 

94 return ufunc(*args, out=out, **kwargs) 

95 except _exceptions._UFuncOutputCastingError as e: 

96 # Numpy 1.17.0, 2019-02-24 

97 warnings.warn( 

98 "Converting the output of clip from {!r} to {!r} is deprecated. " 

99 "Pass `casting=\"unsafe\"` explicitly to silence this warning, or " 

100 "correct the type of the variables.".format(e.from_, e.to), 

101 DeprecationWarning, 

102 stacklevel=2 

103 ) 

104 return ufunc(*args, out=out, casting="unsafe", **kwargs) 

105 

106def _clip(a, min=None, max=None, out=None, *, casting=None, **kwargs): 

107 if min is None and max is None: 

108 raise ValueError("One of max or min must be given") 

109 

110 # Numpy 1.17.0, 2019-02-24 

111 # This deprecation probably incurs a substantial slowdown for small arrays, 

112 # it will be good to get rid of it. 

113 if not _clip_dep_is_byte_swapped(a) and not _clip_dep_is_byte_swapped(out): 

114 using_deprecated_nan = False 

115 if _clip_dep_is_scalar_nan(min): 

116 min = -float('inf') 

117 using_deprecated_nan = True 

118 if _clip_dep_is_scalar_nan(max): 

119 max = float('inf') 

120 using_deprecated_nan = True 

121 if using_deprecated_nan: 

122 warnings.warn( 

123 "Passing `np.nan` to mean no clipping in np.clip has always " 

124 "been unreliable, and is now deprecated. " 

125 "In future, this will always return nan, like it already does " 

126 "when min or max are arrays that contain nan. " 

127 "To skip a bound, pass either None or an np.inf of an " 

128 "appropriate sign.", 

129 DeprecationWarning, 

130 stacklevel=2 

131 ) 

132 

133 if min is None: 

134 return _clip_dep_invoke_with_casting( 

135 um.minimum, a, max, out=out, casting=casting, **kwargs) 

136 elif max is None: 

137 return _clip_dep_invoke_with_casting( 

138 um.maximum, a, min, out=out, casting=casting, **kwargs) 

139 else: 

140 return _clip_dep_invoke_with_casting( 

141 um.clip, a, min, max, out=out, casting=casting, **kwargs) 

142 

143def _mean(a, axis=None, dtype=None, out=None, keepdims=False): 

144 arr = asanyarray(a) 

145 

146 is_float16_result = False 

147 rcount = _count_reduce_items(arr, axis) 

148 # Make this warning show up first 

149 if rcount == 0: 

150 warnings.warn("Mean of empty slice.", RuntimeWarning, stacklevel=2) 

151 

152 # Cast bool, unsigned int, and int to float64 by default 

153 if dtype is None: 

154 if issubclass(arr.dtype.type, (nt.integer, nt.bool_)): 

155 dtype = mu.dtype('f8') 

156 elif issubclass(arr.dtype.type, nt.float16): 

157 dtype = mu.dtype('f4') 

158 is_float16_result = True 

159 

160 ret = umr_sum(arr, axis, dtype, out, keepdims) 

161 if isinstance(ret, mu.ndarray): 

162 ret = um.true_divide( 

163 ret, rcount, out=ret, casting='unsafe', subok=False) 

164 if is_float16_result and out is None: 

165 ret = arr.dtype.type(ret) 

166 elif hasattr(ret, 'dtype'): 

167 if is_float16_result: 

168 ret = arr.dtype.type(ret / rcount) 

169 else: 

170 ret = ret.dtype.type(ret / rcount) 

171 else: 

172 ret = ret / rcount 

173 

174 return ret 

175 

176def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): 

177 arr = asanyarray(a) 

178 

179 rcount = _count_reduce_items(arr, axis) 

180 # Make this warning show up on top. 

181 if ddof >= rcount: 

182 warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning, 

183 stacklevel=2) 

184 

185 # Cast bool, unsigned int, and int to float64 by default 

186 if dtype is None and issubclass(arr.dtype.type, (nt.integer, nt.bool_)): 

187 dtype = mu.dtype('f8') 

188 

189 # Compute the mean. 

190 # Note that if dtype is not of inexact type then arraymean will 

191 # not be either. 

192 arrmean = umr_sum(arr, axis, dtype, keepdims=True) 

193 if isinstance(arrmean, mu.ndarray): 

194 arrmean = um.true_divide( 

195 arrmean, rcount, out=arrmean, casting='unsafe', subok=False) 

196 else: 

197 arrmean = arrmean.dtype.type(arrmean / rcount) 

198 

199 # Compute sum of squared deviations from mean 

200 # Note that x may not be inexact and that we need it to be an array, 

201 # not a scalar. 

202 x = asanyarray(arr - arrmean) 

203 

204 if issubclass(arr.dtype.type, (nt.floating, nt.integer)): 

205 x = um.multiply(x, x, out=x) 

206 # Fast-paths for built-in complex types 

207 elif x.dtype in _complex_to_float: 

208 xv = x.view(dtype=(_complex_to_float[x.dtype], (2,))) 

209 um.multiply(xv, xv, out=xv) 

210 x = um.add(xv[..., 0], xv[..., 1], out=x.real).real 

211 # Most general case; includes handling object arrays containing imaginary 

212 # numbers and complex types with non-native byteorder 

213 else: 

214 x = um.multiply(x, um.conjugate(x), out=x).real 

215 

216 ret = umr_sum(x, axis, dtype, out, keepdims) 

217 

218 # Compute degrees of freedom and make sure it is not negative. 

219 rcount = max([rcount - ddof, 0]) 

220 

221 # divide by degrees of freedom 

222 if isinstance(ret, mu.ndarray): 

223 ret = um.true_divide( 

224 ret, rcount, out=ret, casting='unsafe', subok=False) 

225 elif hasattr(ret, 'dtype'): 

226 ret = ret.dtype.type(ret / rcount) 

227 else: 

228 ret = ret / rcount 

229 

230 return ret 

231 

232def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): 

233 ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof, 

234 keepdims=keepdims) 

235 

236 if isinstance(ret, mu.ndarray): 

237 ret = um.sqrt(ret, out=ret) 

238 elif hasattr(ret, 'dtype'): 

239 ret = ret.dtype.type(um.sqrt(ret)) 

240 else: 

241 ret = um.sqrt(ret) 

242 

243 return ret 

244 

245def _ptp(a, axis=None, out=None, keepdims=False): 

246 return um.subtract( 

247 umr_maximum(a, axis, None, out, keepdims), 

248 umr_minimum(a, axis, None, None, keepdims), 

249 out 

250 ) 

251 

252def _dump(self, file, protocol=2): 

253 if hasattr(file, 'write'): 

254 ctx = contextlib_nullcontext(file) 

255 else: 

256 ctx = open(os_fspath(file), "wb") 

257 with ctx as f: 

258 pickle.dump(self, f, protocol=protocol) 

259 

260def _dumps(self, protocol=2): 

261 return pickle.dumps(self, protocol=protocol)