def _var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): arr = asanyarray(a) rcount = _count_reduce_items(arr, axis) # Make this warning show up on top. if ddof >= rcount: warnings.warn("Degrees of freedom <= 0 for slice", RuntimeWarning, stacklevel=2) # Cast bool, unsigned int, and int to float64 by default if dtype is None and issubclass(arr.dtype.type, (nt.integer, nt.bool_)): dtype = mu.dtype('f8') # Compute the mean. # Note that if dtype is not of inexact type then arraymean will # not be either. arrmean = umr_sum(arr, axis, dtype, keepdims=True) if isinstance(arrmean, mu.ndarray): arrmean = um.true_divide(arrmean, rcount, out=arrmean, casting='unsafe', subok=False) else: arrmean = arrmean.dtype.type(arrmean / rcount) # Compute sum of squared deviations from mean # Note that x may not be inexact and that we need it to be an array, # not a scalar. x = asanyarray(arr - arrmean) if issubclass(arr.dtype.type, nt.complexfloating): x = um.multiply(x, um.conjugate(x), out=x).real else: x = um.multiply(x, x, out=x) ret = umr_sum(x, axis, dtype, out, keepdims) # Compute degrees of freedom and make sure it is not negative. rcount = max([rcount - ddof, 0]) # divide by degrees of freedom if isinstance(ret, mu.ndarray): ret = um.true_divide(ret, rcount, out=ret, casting='unsafe', subok=False) elif hasattr(ret, 'dtype'): ret = ret.dtype.type(ret / rcount) else: ret = ret / rcount return ret
def _mean(a, axis=None, dtype=None, out=None, keepdims=False): arr = asanyarray(a) is_float16_result = False rcount = _count_reduce_items(arr, axis) # Make this warning show up first if rcount == 0: warnings.warn("Mean of empty slice.", RuntimeWarning, stacklevel=2) # Cast bool, unsigned int, and int to float64 by default if dtype is None: if issubclass(arr.dtype.type, (nt.integer, nt.bool_)): dtype = mu.dtype('f8') elif issubclass(arr.dtype.type, nt.float16): dtype = mu.dtype('f4') is_float16_result = True ret = umr_sum(arr, axis, dtype, out, keepdims) if isinstance(ret, mu.ndarray): ret = um.true_divide(ret, rcount, out=ret, casting='unsafe', subok=False) if is_float16_result and out is None: ret = arr.dtype.type(ret) elif hasattr(ret, 'dtype'): if is_float16_result: ret = arr.dtype.type(ret / rcount) else: ret = ret.dtype.type(ret / rcount) else: ret = ret / rcount return ret
def iscomplex(x): """ Returns a bool array, where True if input element is complex. What is tested is whether the input has a non-zero imaginary part, not if the input type is complex. Parameters ---------- x : array_like Input array. Returns ------- out : ndarray of bools Output array. See Also -------- isreal iscomplexobj : Return True if x is a complex type or an array of complex numbers. Examples -------- >>> np.iscomplex([1+1j, 1+0j, 4.5, 3, 2, 2j]) array([ True, False, False, False, False, True]) """ ax = asanyarray(x) if issubclass(ax.dtype.type, _nx.complexfloating): return ax.imag != 0 res = zeros(ax.shape, bool) return +res # convert to array-scalar if needed
def real_if_close(a, tol=100): """ If complex input returns a real array if complex parts are close to zero. "Close to zero" is defined as `tol` * (machine epsilon of the type for `a`). Parameters ---------- a : array_like Input array. tol : float Tolerance in machine epsilons for the complex part of the elements in the array. Returns ------- out : ndarray If `a` is real, the type of `a` is used for the output. If `a` has complex elements, the returned type is float. See Also -------- real, imag, angle Notes ----- Machine epsilon varies from machine to machine and between data types but Python floats on most platforms have a machine epsilon equal to 2.2204460492503131e-16. You can use 'np.finfo(float).eps' to print out the machine epsilon for floats. Examples -------- >>> np.finfo(float).eps 2.2204460492503131e-16 >>> np.real_if_close([2.1 + 4e-14j], tol=1000) array([ 2.1]) >>> np.real_if_close([2.1 + 4e-13j], tol=1000) array([ 2.1 +4.00000000e-13j]) """ a = asanyarray(a) if not issubclass(a.dtype.type, _nx.complexfloating): return a if tol > 1: from numpy1.core import getlimits f = getlimits.finfo(a.dtype.type) tol = f.eps * tol if _nx.all(_nx.absolute(a.imag) < tol): a = a.real return a
def fix(x, out=None): """ Round to nearest integer towards zero. Round an array of floats element-wise to nearest integer towards zero. The rounded values are returned as floats. Parameters ---------- x : array_like An array of floats to be rounded y : ndarray, optional Output array Returns ------- out : ndarray of floats The array of rounded numbers See Also -------- trunc, floor, ceil around : Round to given number of decimals Examples -------- >>> np.fix(3.14) 3.0 >>> np.fix(3) 3.0 >>> np.fix([2.1, 2.9, -2.1, -2.9]) array([ 2., 2., -2., -2.]) """ # promote back to an array if flattened res = nx.asanyarray(nx.ceil(x, out=out)) res = nx.floor(x, out=res, where=nx.greater_equal(x, 0)) # when no out argument is passed and no subclasses are involved, flatten # scalars if out is None and type(res) is nx.ndarray: res = res[()] return res
def real(val): """ Return the real part of the complex argument. Parameters ---------- val : array_like Input array. Returns ------- out : ndarray or scalar The real component of the complex argument. If `val` is real, the type of `val` is used for the output. If `val` has complex elements, the returned type is float. See Also -------- real_if_close, imag, angle Examples -------- >>> a = np.array([1+2j, 3+4j, 5+6j]) >>> a.real array([ 1., 3., 5.]) >>> a.real = 9 >>> a array([ 9.+2.j, 9.+4.j, 9.+6.j]) >>> a.real = np.array([9, 8, 7]) >>> a array([ 9.+2.j, 8.+4.j, 7.+6.j]) >>> np.real(1 + 1j) 1.0 """ try: return val.real except AttributeError: return asanyarray(val).real
def imag(val): """ Return the imaginary part of the complex argument. Parameters ---------- val : array_like Input array. Returns ------- out : ndarray or scalar The imaginary component of the complex argument. If `val` is real, the type of `val` is used for the output. If `val` has complex elements, the returned type is float. See Also -------- real, angle, real_if_close Examples -------- >>> a = np.array([1+2j, 3+4j, 5+6j]) >>> a.imag array([ 2., 4., 6.]) >>> a.imag = np.array([8, 10, 12]) >>> a array([ 1. +8.j, 3.+10.j, 5.+12.j]) >>> np.imag(1 + 1j) 1.0 """ try: return val.imag except AttributeError: return asanyarray(val).imag
def kron(a, b): """ Kronecker product of two arrays. Computes the Kronecker product, a composite array made of blocks of the second array scaled by the first. Parameters ---------- a, b : array_like Returns ------- out : ndarray See Also -------- outer : The outer product Notes ----- The function assumes that the number of dimensions of `a` and `b` are the same, if necessary prepending the smallest with ones. If `a.shape = (r0,r1,..,rN)` and `b.shape = (s0,s1,...,sN)`, the Kronecker product has shape `(r0*s0, r1*s1, ..., rN*SN)`. The elements are products of elements from `a` and `b`, organized explicitly by:: kron(a,b)[k0,k1,...,kN] = a[i0,i1,...,iN] * b[j0,j1,...,jN] where:: kt = it * st + jt, t = 0,...,N In the common 2-D case (N=1), the block structure can be visualized:: [[ a[0,0]*b, a[0,1]*b, ... , a[0,-1]*b ], [ ... ... ], [ a[-1,0]*b, a[-1,1]*b, ... , a[-1,-1]*b ]] Examples -------- >>> np.kron([1,10,100], [5,6,7]) array([ 5, 6, 7, 50, 60, 70, 500, 600, 700]) >>> np.kron([5,6,7], [1,10,100]) array([ 5, 50, 500, 6, 60, 600, 7, 70, 700]) >>> np.kron(np.eye(2), np.ones((2,2))) array([[ 1., 1., 0., 0.], [ 1., 1., 0., 0.], [ 0., 0., 1., 1.], [ 0., 0., 1., 1.]]) >>> a = np.arange(100).reshape((2,5,2,5)) >>> b = np.arange(24).reshape((2,3,4)) >>> c = np.kron(a,b) >>> c.shape (2, 10, 6, 20) >>> I = (1,3,0,2) >>> J = (0,2,1) >>> J1 = (0,) + J # extend to ndim=4 >>> S1 = (1,) + b.shape >>> K = tuple(np.array(I) * np.array(S1) + np.array(J1)) >>> c[K] == a[I]*b[J] True """ b = asanyarray(b) a = array(a, copy=False, subok=True, ndmin=b.ndim) ndb, nda = b.ndim, a.ndim if (nda == 0 or ndb == 0): return _nx.multiply(a, b) as_ = a.shape bs = b.shape if not a.flags.contiguous: a = reshape(a, as_) if not b.flags.contiguous: b = reshape(b, bs) nd = ndb if (ndb != nda): if (ndb > nda): as_ = (1, ) * (ndb - nda) + as_ else: bs = (1, ) * (nda - ndb) + bs nd = nda result = outer(a, b).reshape(as_ + bs) axis = nd - 1 for _ in range(nd): result = concatenate(result, axis=axis) wrapper = get_array_prepare(a, b) if wrapper is not None: result = wrapper(result) wrapper = get_array_wrap(a, b) if wrapper is not None: result = wrapper(result) return result
def apply_along_axis(func1d, axis, arr, *args, **kwargs): """ Apply a function to 1-D slices along the given axis. Execute `func1d(a, *args)` where `func1d` operates on 1-D arrays and `a` is a 1-D slice of `arr` along `axis`. This is equivalent to (but faster than) the following use of `ndindex` and `s_`, which sets each of ``ii``, ``jj``, and ``kk`` to a tuple of indices:: Ni, Nk = a.shape[:axis], a.shape[axis+1:] for ii in ndindex(Ni): for kk in ndindex(Nk): f = func1d(arr[ii + s_[:,] + kk]) Nj = f.shape for jj in ndindex(Nj): out[ii + jj + kk] = f[jj] Equivalently, eliminating the inner loop, this can be expressed as:: Ni, Nk = a.shape[:axis], a.shape[axis+1:] for ii in ndindex(Ni): for kk in ndindex(Nk): out[ii + s_[...,] + kk] = func1d(arr[ii + s_[:,] + kk]) Parameters ---------- func1d : function (M,) -> (Nj...) This function should accept 1-D arrays. It is applied to 1-D slices of `arr` along the specified axis. axis : integer Axis along which `arr` is sliced. arr : ndarray (Ni..., M, Nk...) Input array. args : any Additional arguments to `func1d`. kwargs : any Additional named arguments to `func1d`. .. versionadded:: 1.9.0 Returns ------- out : ndarray (Ni..., Nj..., Nk...) The output array. The shape of `out` is identical to the shape of `arr`, except along the `axis` dimension. This axis is removed, and replaced with new dimensions equal to the shape of the return value of `func1d`. So if `func1d` returns a scalar `out` will have one fewer dimensions than `arr`. See Also -------- apply_over_axes : Apply a function repeatedly over multiple axes. Examples -------- >>> def my_func(a): ... \"\"\"Average first and last element of a 1-D array\"\"\" ... return (a[0] + a[-1]) * 0.5 >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) >>> np.apply_along_axis(my_func, 0, b) array([ 4., 5., 6.]) >>> np.apply_along_axis(my_func, 1, b) array([ 2., 5., 8.]) For a function that returns a 1D array, the number of dimensions in `outarr` is the same as `arr`. >>> b = np.array([[8,1,7], [4,3,9], [5,2,6]]) >>> np.apply_along_axis(sorted, 1, b) array([[1, 7, 8], [3, 4, 9], [2, 5, 6]]) For a function that returns a higher dimensional array, those dimensions are inserted in place of the `axis` dimension. >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) >>> np.apply_along_axis(np.diag, -1, b) array([[[1, 0, 0], [0, 2, 0], [0, 0, 3]], [[4, 0, 0], [0, 5, 0], [0, 0, 6]], [[7, 0, 0], [0, 8, 0], [0, 0, 9]]]) """ # handle negative axes arr = asanyarray(arr) nd = arr.ndim axis = normalize_axis_index(axis, nd) # arr, with the iteration axis at the end in_dims = list(range(nd)) inarr_view = transpose(arr, in_dims[:axis] + in_dims[axis + 1:] + [axis]) # compute indices for the iteration axes, and append a trailing ellipsis to # prevent 0d arrays decaying to scalars, which fixes gh-8642 inds = ndindex(inarr_view.shape[:-1]) inds = (ind + (Ellipsis, ) for ind in inds) # invoke the function on the first item try: ind0 = next(inds) except StopIteration: raise ValueError( 'Cannot apply_along_axis when any iteration dimensions are 0') res = asanyarray(func1d(inarr_view[ind0], *args, **kwargs)) # build a buffer for storing evaluations of func1d. # remove the requested axis, and add the new ones on the end. # laid out so that each write is contiguous. # for a tuple index inds, buff[inds] = func1d(inarr_view[inds]) buff = zeros(inarr_view.shape[:-1] + res.shape, res.dtype) # permutation of axes such that out = buff.transpose(buff_permute) buff_dims = list(range(buff.ndim)) buff_permute = (buff_dims[0:axis] + buff_dims[buff.ndim - res.ndim:buff.ndim] + buff_dims[axis:buff.ndim - res.ndim]) # matrices have a nasty __array_prepare__ and __array_wrap__ if not isinstance(res, matrix): buff = res.__array_prepare__(buff) # save the first result, then compute and save all remaining results buff[ind0] = res for ind in inds: buff[ind] = asanyarray(func1d(inarr_view[ind], *args, **kwargs)) if not isinstance(res, matrix): # wrap the array, to preserve subclasses buff = res.__array_wrap__(buff) # finally, rotate the inserted axes back to where they belong return transpose(buff, buff_permute) else: # matrices have to be transposed first, because they collapse dimensions! out_arr = transpose(buff, buff_permute) return res.__array_wrap__(out_arr)
def _parse_einsum_input(operands): """ A reproduction of einsum c side einsum parsing in python. Returns ------- input_strings : str Parsed input strings output_string : str Parsed output string operands : list of array_like The operands to use in the numpy contraction Examples -------- The operand list is simplified to reduce printing: >>> a = np.random.rand(4, 4) >>> b = np.random.rand(4, 4, 4) >>> __parse_einsum_input(('...a,...a->...', a, b)) ('za,xza', 'xz', [a, b]) >>> __parse_einsum_input((a, [Ellipsis, 0], b, [Ellipsis, 0])) ('za,xza', 'xz', [a, b]) """ if len(operands) == 0: raise ValueError("No input operands") if isinstance(operands[0], basestring): subscripts = operands[0].replace(" ", "") operands = [asanyarray(v) for v in operands[1:]] # Ensure all characters are valid for s in subscripts: if s in '.,->': continue if s not in einsum_symbols: raise ValueError("Character %s is not a valid symbol." % s) else: tmp_operands = list(operands) operand_list = [] subscript_list = [] for p in range(len(operands) // 2): operand_list.append(tmp_operands.pop(0)) subscript_list.append(tmp_operands.pop(0)) output_list = tmp_operands[-1] if len(tmp_operands) else None operands = [asanyarray(v) for v in operand_list] subscripts = "" last = len(subscript_list) - 1 for num, sub in enumerate(subscript_list): for s in sub: if s is Ellipsis: subscripts += "..." elif isinstance(s, int): subscripts += einsum_symbols[s] else: raise TypeError("For this input type lists must contain " "either int or Ellipsis") if num != last: subscripts += "," if output_list is not None: subscripts += "->" for s in output_list: if s is Ellipsis: subscripts += "..." elif isinstance(s, int): subscripts += einsum_symbols[s] else: raise TypeError("For this input type lists must contain " "either int or Ellipsis") # Check for proper "->" if ("-" in subscripts) or (">" in subscripts): invalid = (subscripts.count("-") > 1) or (subscripts.count(">") > 1) if invalid or (subscripts.count("->") != 1): raise ValueError("Subscripts can only contain one '->'.") # Parse ellipses if "." in subscripts: used = subscripts.replace(".", "").replace(",", "").replace("->", "") unused = list(einsum_symbols_set - set(used)) ellipse_inds = "".join(unused) longest = 0 if "->" in subscripts: input_tmp, output_sub = subscripts.split("->") split_subscripts = input_tmp.split(",") out_sub = True else: split_subscripts = subscripts.split(',') out_sub = False for num, sub in enumerate(split_subscripts): if "." in sub: if (sub.count(".") != 3) or (sub.count("...") != 1): raise ValueError("Invalid Ellipses.") # Take into account numerical values if operands[num].shape == (): ellipse_count = 0 else: ellipse_count = max(operands[num].ndim, 1) ellipse_count -= (len(sub) - 3) if ellipse_count > longest: longest = ellipse_count if ellipse_count < 0: raise ValueError("Ellipses lengths do not match.") elif ellipse_count == 0: split_subscripts[num] = sub.replace('...', '') else: rep_inds = ellipse_inds[-ellipse_count:] split_subscripts[num] = sub.replace('...', rep_inds) subscripts = ",".join(split_subscripts) if longest == 0: out_ellipse = "" else: out_ellipse = ellipse_inds[-longest:] if out_sub: subscripts += "->" + output_sub.replace("...", out_ellipse) else: # Special care for outputless ellipses output_subscript = "" tmp_subscripts = subscripts.replace(",", "") for s in sorted(set(tmp_subscripts)): if s not in (einsum_symbols): raise ValueError("Character %s is not a valid symbol." % s) if tmp_subscripts.count(s) == 1: output_subscript += s normal_inds = ''.join( sorted(set(output_subscript) - set(out_ellipse))) subscripts += "->" + out_ellipse + normal_inds # Build output string if does not exist if "->" in subscripts: input_subscripts, output_subscript = subscripts.split("->") else: input_subscripts = subscripts # Build output subscripts tmp_subscripts = subscripts.replace(",", "") output_subscript = "" for s in sorted(set(tmp_subscripts)): if s not in einsum_symbols: raise ValueError("Character %s is not a valid symbol." % s) if tmp_subscripts.count(s) == 1: output_subscript += s # Make sure output subscripts are in the input for char in output_subscript: if char not in input_subscripts: raise ValueError( "Output character %s did not appear in the input" % char) # Make sure number operands is equivalent to the number of terms if len(input_subscripts.split(',')) != len(operands): raise ValueError("Number of einsum subscripts must be equal to the " "number of operands.") return (input_subscripts, output_subscript, operands)