Chris@87: from __future__ import division, absolute_import, print_function Chris@87: Chris@87: import warnings Chris@87: Chris@87: import numpy.core.numeric as _nx Chris@87: from numpy.core.numeric import ( Chris@87: asarray, zeros, outer, concatenate, isscalar, array, asanyarray Chris@87: ) Chris@87: from numpy.core.fromnumeric import product, reshape Chris@87: from numpy.core import vstack, atleast_3d Chris@87: Chris@87: Chris@87: __all__ = [ Chris@87: 'column_stack', 'row_stack', 'dstack', 'array_split', 'split', Chris@87: 'hsplit', 'vsplit', 'dsplit', 'apply_over_axes', 'expand_dims', Chris@87: 'apply_along_axis', 'kron', 'tile', 'get_array_wrap' Chris@87: ] Chris@87: Chris@87: Chris@87: def apply_along_axis(func1d, axis, arr, *args, **kwargs): Chris@87: """ Chris@87: Apply a function to 1-D slices along the given axis. Chris@87: Chris@87: Execute `func1d(a, *args)` where `func1d` operates on 1-D arrays and `a` Chris@87: is a 1-D slice of `arr` along `axis`. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: func1d : function Chris@87: This function should accept 1-D arrays. It is applied to 1-D Chris@87: slices of `arr` along the specified axis. Chris@87: axis : integer Chris@87: Axis along which `arr` is sliced. Chris@87: arr : ndarray Chris@87: Input array. Chris@87: args : any Chris@87: Additional arguments to `func1d`. Chris@87: kwargs: any Chris@87: Additional named arguments to `func1d`. Chris@87: Chris@87: .. versionadded:: 1.9.0 Chris@87: Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: apply_along_axis : ndarray Chris@87: The output array. The shape of `outarr` is identical to the shape of Chris@87: `arr`, except along the `axis` dimension, where the length of `outarr` Chris@87: is equal to the size of the return value of `func1d`. If `func1d` Chris@87: returns a scalar `outarr` will have one fewer dimensions than `arr`. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: apply_over_axes : Apply a function repeatedly over multiple axes. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> def my_func(a): Chris@87: ... \"\"\"Average first and last element of a 1-D array\"\"\" Chris@87: ... return (a[0] + a[-1]) * 0.5 Chris@87: >>> b = np.array([[1,2,3], [4,5,6], [7,8,9]]) Chris@87: >>> np.apply_along_axis(my_func, 0, b) Chris@87: array([ 4., 5., 6.]) Chris@87: >>> np.apply_along_axis(my_func, 1, b) Chris@87: array([ 2., 5., 8.]) Chris@87: Chris@87: For a function that doesn't return a scalar, the number of dimensions in Chris@87: `outarr` is the same as `arr`. Chris@87: Chris@87: >>> b = np.array([[8,1,7], [4,3,9], [5,2,6]]) Chris@87: >>> np.apply_along_axis(sorted, 1, b) Chris@87: array([[1, 7, 8], Chris@87: [3, 4, 9], Chris@87: [2, 5, 6]]) Chris@87: Chris@87: """ Chris@87: arr = asarray(arr) Chris@87: nd = arr.ndim Chris@87: if axis < 0: Chris@87: axis += nd Chris@87: if (axis >= nd): Chris@87: raise ValueError("axis must be less than arr.ndim; axis=%d, rank=%d." Chris@87: % (axis, nd)) Chris@87: ind = [0]*(nd-1) Chris@87: i = zeros(nd, 'O') Chris@87: indlist = list(range(nd)) Chris@87: indlist.remove(axis) Chris@87: i[axis] = slice(None, None) Chris@87: outshape = asarray(arr.shape).take(indlist) Chris@87: i.put(indlist, ind) Chris@87: res = func1d(arr[tuple(i.tolist())], *args, **kwargs) Chris@87: # if res is a number, then we have a smaller output array Chris@87: if isscalar(res): Chris@87: outarr = zeros(outshape, asarray(res).dtype) Chris@87: outarr[tuple(ind)] = res Chris@87: Ntot = product(outshape) Chris@87: k = 1 Chris@87: while k < Ntot: Chris@87: # increment the index Chris@87: ind[-1] += 1 Chris@87: n = -1 Chris@87: while (ind[n] >= outshape[n]) and (n > (1-nd)): Chris@87: ind[n-1] += 1 Chris@87: ind[n] = 0 Chris@87: n -= 1 Chris@87: i.put(indlist, ind) Chris@87: res = func1d(arr[tuple(i.tolist())], *args, **kwargs) Chris@87: outarr[tuple(ind)] = res Chris@87: k += 1 Chris@87: return outarr Chris@87: else: Chris@87: Ntot = product(outshape) Chris@87: holdshape = outshape Chris@87: outshape = list(arr.shape) Chris@87: outshape[axis] = len(res) Chris@87: outarr = zeros(outshape, asarray(res).dtype) Chris@87: outarr[tuple(i.tolist())] = res Chris@87: k = 1 Chris@87: while k < Ntot: Chris@87: # increment the index Chris@87: ind[-1] += 1 Chris@87: n = -1 Chris@87: while (ind[n] >= holdshape[n]) and (n > (1-nd)): Chris@87: ind[n-1] += 1 Chris@87: ind[n] = 0 Chris@87: n -= 1 Chris@87: i.put(indlist, ind) Chris@87: res = func1d(arr[tuple(i.tolist())], *args, **kwargs) Chris@87: outarr[tuple(i.tolist())] = res Chris@87: k += 1 Chris@87: return outarr Chris@87: Chris@87: Chris@87: def apply_over_axes(func, a, axes): Chris@87: """ Chris@87: Apply a function repeatedly over multiple axes. Chris@87: Chris@87: `func` is called as `res = func(a, axis)`, where `axis` is the first Chris@87: element of `axes`. The result `res` of the function call must have Chris@87: either the same dimensions as `a` or one less dimension. If `res` Chris@87: has one less dimension than `a`, a dimension is inserted before Chris@87: `axis`. The call to `func` is then repeated for each axis in `axes`, Chris@87: with `res` as the first argument. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: func : function Chris@87: This function must take two arguments, `func(a, axis)`. Chris@87: a : array_like Chris@87: Input array. Chris@87: axes : array_like Chris@87: Axes over which `func` is applied; the elements must be integers. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: apply_over_axis : ndarray Chris@87: The output array. The number of dimensions is the same as `a`, Chris@87: but the shape can be different. This depends on whether `func` Chris@87: changes the shape of its output with respect to its input. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: apply_along_axis : Chris@87: Apply a function to 1-D slices of an array along the given axis. Chris@87: Chris@87: Notes Chris@87: ------ Chris@87: This function is equivalent to tuple axis arguments to reorderable ufuncs Chris@87: with keepdims=True. Tuple axis arguments to ufuncs have been availabe since Chris@87: version 1.7.0. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.arange(24).reshape(2,3,4) Chris@87: >>> a Chris@87: array([[[ 0, 1, 2, 3], Chris@87: [ 4, 5, 6, 7], Chris@87: [ 8, 9, 10, 11]], Chris@87: [[12, 13, 14, 15], Chris@87: [16, 17, 18, 19], Chris@87: [20, 21, 22, 23]]]) Chris@87: Chris@87: Sum over axes 0 and 2. The result has same number of dimensions Chris@87: as the original array: Chris@87: Chris@87: >>> np.apply_over_axes(np.sum, a, [0,2]) Chris@87: array([[[ 60], Chris@87: [ 92], Chris@87: [124]]]) Chris@87: Chris@87: Tuple axis arguments to ufuncs are equivalent: Chris@87: Chris@87: >>> np.sum(a, axis=(0,2), keepdims=True) Chris@87: array([[[ 60], Chris@87: [ 92], Chris@87: [124]]]) Chris@87: Chris@87: """ Chris@87: val = asarray(a) Chris@87: N = a.ndim Chris@87: if array(axes).ndim == 0: Chris@87: axes = (axes,) Chris@87: for axis in axes: Chris@87: if axis < 0: Chris@87: axis = N + axis Chris@87: args = (val, axis) Chris@87: res = func(*args) Chris@87: if res.ndim == val.ndim: Chris@87: val = res Chris@87: else: Chris@87: res = expand_dims(res, axis) Chris@87: if res.ndim == val.ndim: Chris@87: val = res Chris@87: else: Chris@87: raise ValueError("function is not returning " Chris@87: "an array of the correct shape") Chris@87: return val Chris@87: Chris@87: def expand_dims(a, axis): Chris@87: """ Chris@87: Expand the shape of an array. Chris@87: Chris@87: Insert a new axis, corresponding to a given position in the array shape. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Input array. Chris@87: axis : int Chris@87: Position (amongst axes) where new axis is to be inserted. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: res : ndarray Chris@87: Output array. The number of dimensions is one greater than that of Chris@87: the input array. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: doc.indexing, atleast_1d, atleast_2d, atleast_3d Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> x = np.array([1,2]) Chris@87: >>> x.shape Chris@87: (2,) Chris@87: Chris@87: The following is equivalent to ``x[np.newaxis,:]`` or ``x[np.newaxis]``: Chris@87: Chris@87: >>> y = np.expand_dims(x, axis=0) Chris@87: >>> y Chris@87: array([[1, 2]]) Chris@87: >>> y.shape Chris@87: (1, 2) Chris@87: Chris@87: >>> y = np.expand_dims(x, axis=1) # Equivalent to x[:,newaxis] Chris@87: >>> y Chris@87: array([[1], Chris@87: [2]]) Chris@87: >>> y.shape Chris@87: (2, 1) Chris@87: Chris@87: Note that some examples may use ``None`` instead of ``np.newaxis``. These Chris@87: are the same objects: Chris@87: Chris@87: >>> np.newaxis is None Chris@87: True Chris@87: Chris@87: """ Chris@87: a = asarray(a) Chris@87: shape = a.shape Chris@87: if axis < 0: Chris@87: axis = axis + len(shape) + 1 Chris@87: return a.reshape(shape[:axis] + (1,) + shape[axis:]) Chris@87: Chris@87: row_stack = vstack Chris@87: Chris@87: def column_stack(tup): Chris@87: """ Chris@87: Stack 1-D arrays as columns into a 2-D array. Chris@87: Chris@87: Take a sequence of 1-D arrays and stack them as columns Chris@87: to make a single 2-D array. 2-D arrays are stacked as-is, Chris@87: just like with `hstack`. 1-D arrays are turned into 2-D columns Chris@87: first. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: tup : sequence of 1-D or 2-D arrays. Chris@87: Arrays to stack. All of them must have the same first dimension. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: stacked : 2-D array Chris@87: The array formed by stacking the given arrays. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: hstack, vstack, concatenate Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array((1,2,3)) Chris@87: >>> b = np.array((2,3,4)) Chris@87: >>> np.column_stack((a,b)) Chris@87: array([[1, 2], Chris@87: [2, 3], Chris@87: [3, 4]]) Chris@87: Chris@87: """ Chris@87: arrays = [] Chris@87: for v in tup: Chris@87: arr = array(v, copy=False, subok=True) Chris@87: if arr.ndim < 2: Chris@87: arr = array(arr, copy=False, subok=True, ndmin=2).T Chris@87: arrays.append(arr) Chris@87: return _nx.concatenate(arrays, 1) Chris@87: Chris@87: def dstack(tup): Chris@87: """ Chris@87: Stack arrays in sequence depth wise (along third axis). Chris@87: Chris@87: Takes a sequence of arrays and stack them along the third axis Chris@87: to make a single array. Rebuilds arrays divided by `dsplit`. Chris@87: This is a simple way to stack 2D arrays (images) into a single Chris@87: 3D array for processing. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: tup : sequence of arrays Chris@87: Arrays to stack. All of them must have the same shape along all Chris@87: but the third axis. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: stacked : ndarray Chris@87: The array formed by stacking the given arrays. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: vstack : Stack along first axis. Chris@87: hstack : Stack along second axis. Chris@87: concatenate : Join arrays. Chris@87: dsplit : Split array along third axis. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: Equivalent to ``np.concatenate(tup, axis=2)``. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array((1,2,3)) Chris@87: >>> b = np.array((2,3,4)) Chris@87: >>> np.dstack((a,b)) Chris@87: array([[[1, 2], Chris@87: [2, 3], Chris@87: [3, 4]]]) Chris@87: Chris@87: >>> a = np.array([[1],[2],[3]]) Chris@87: >>> b = np.array([[2],[3],[4]]) Chris@87: >>> np.dstack((a,b)) Chris@87: array([[[1, 2]], Chris@87: [[2, 3]], Chris@87: [[3, 4]]]) Chris@87: Chris@87: """ Chris@87: return _nx.concatenate([atleast_3d(_m) for _m in tup], 2) Chris@87: Chris@87: def _replace_zero_by_x_arrays(sub_arys): Chris@87: for i in range(len(sub_arys)): Chris@87: if len(_nx.shape(sub_arys[i])) == 0: Chris@87: sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype) Chris@87: elif _nx.sometrue(_nx.equal(_nx.shape(sub_arys[i]), 0)): Chris@87: sub_arys[i] = _nx.empty(0, dtype=sub_arys[i].dtype) Chris@87: return sub_arys Chris@87: Chris@87: def array_split(ary, indices_or_sections, axis=0): Chris@87: """ Chris@87: Split an array into multiple sub-arrays. Chris@87: Chris@87: Please refer to the ``split`` documentation. The only difference Chris@87: between these functions is that ``array_split`` allows Chris@87: `indices_or_sections` to be an integer that does *not* equally Chris@87: divide the axis. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: split : Split array into multiple sub-arrays of equal size. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> x = np.arange(8.0) Chris@87: >>> np.array_split(x, 3) Chris@87: [array([ 0., 1., 2.]), array([ 3., 4., 5.]), array([ 6., 7.])] Chris@87: Chris@87: """ Chris@87: try: Chris@87: Ntotal = ary.shape[axis] Chris@87: except AttributeError: Chris@87: Ntotal = len(ary) Chris@87: try: Chris@87: # handle scalar case. Chris@87: Nsections = len(indices_or_sections) + 1 Chris@87: div_points = [0] + list(indices_or_sections) + [Ntotal] Chris@87: except TypeError: Chris@87: # indices_or_sections is a scalar, not an array. Chris@87: Nsections = int(indices_or_sections) Chris@87: if Nsections <= 0: Chris@87: raise ValueError('number sections must be larger than 0.') Chris@87: Neach_section, extras = divmod(Ntotal, Nsections) Chris@87: section_sizes = ([0] + Chris@87: extras * [Neach_section+1] + Chris@87: (Nsections-extras) * [Neach_section]) Chris@87: div_points = _nx.array(section_sizes).cumsum() Chris@87: Chris@87: sub_arys = [] Chris@87: sary = _nx.swapaxes(ary, axis, 0) Chris@87: for i in range(Nsections): Chris@87: st = div_points[i] Chris@87: end = div_points[i + 1] Chris@87: sub_arys.append(_nx.swapaxes(sary[st:end], axis, 0)) Chris@87: Chris@87: # This "kludge" was introduced here to replace arrays shaped (0, 10) Chris@87: # or similar with an array shaped (0,). Chris@87: # There seems no need for this, so give a FutureWarning to remove later. Chris@87: if sub_arys[-1].size == 0 and sub_arys[-1].ndim != 1: Chris@87: warnings.warn("in the future np.array_split will retain the shape of " Chris@87: "arrays with a zero size, instead of replacing them by " Chris@87: "`array([])`, which always has a shape of (0,).", Chris@87: FutureWarning) Chris@87: sub_arys = _replace_zero_by_x_arrays(sub_arys) Chris@87: Chris@87: return sub_arys Chris@87: Chris@87: def split(ary,indices_or_sections,axis=0): Chris@87: """ Chris@87: Split an array into multiple sub-arrays. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: ary : ndarray Chris@87: Array to be divided into sub-arrays. Chris@87: indices_or_sections : int or 1-D array Chris@87: If `indices_or_sections` is an integer, N, the array will be divided Chris@87: into N equal arrays along `axis`. If such a split is not possible, Chris@87: an error is raised. Chris@87: Chris@87: If `indices_or_sections` is a 1-D array of sorted integers, the entries Chris@87: indicate where along `axis` the array is split. For example, Chris@87: ``[2, 3]`` would, for ``axis=0``, result in Chris@87: Chris@87: - ary[:2] Chris@87: - ary[2:3] Chris@87: - ary[3:] Chris@87: Chris@87: If an index exceeds the dimension of the array along `axis`, Chris@87: an empty sub-array is returned correspondingly. Chris@87: axis : int, optional Chris@87: The axis along which to split, default is 0. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: sub-arrays : list of ndarrays Chris@87: A list of sub-arrays. Chris@87: Chris@87: Raises Chris@87: ------ Chris@87: ValueError Chris@87: If `indices_or_sections` is given as an integer, but Chris@87: a split does not result in equal division. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: array_split : Split an array into multiple sub-arrays of equal or Chris@87: near-equal size. Does not raise an exception if Chris@87: an equal division cannot be made. Chris@87: hsplit : Split array into multiple sub-arrays horizontally (column-wise). Chris@87: vsplit : Split array into multiple sub-arrays vertically (row wise). Chris@87: dsplit : Split array into multiple sub-arrays along the 3rd axis (depth). Chris@87: concatenate : Join arrays together. Chris@87: hstack : Stack arrays in sequence horizontally (column wise). Chris@87: vstack : Stack arrays in sequence vertically (row wise). Chris@87: dstack : Stack arrays in sequence depth wise (along third dimension). Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> x = np.arange(9.0) Chris@87: >>> np.split(x, 3) Chris@87: [array([ 0., 1., 2.]), array([ 3., 4., 5.]), array([ 6., 7., 8.])] Chris@87: Chris@87: >>> x = np.arange(8.0) Chris@87: >>> np.split(x, [3, 5, 6, 10]) Chris@87: [array([ 0., 1., 2.]), Chris@87: array([ 3., 4.]), Chris@87: array([ 5.]), Chris@87: array([ 6., 7.]), Chris@87: array([], dtype=float64)] Chris@87: Chris@87: """ Chris@87: try: Chris@87: len(indices_or_sections) Chris@87: except TypeError: Chris@87: sections = indices_or_sections Chris@87: N = ary.shape[axis] Chris@87: if N % sections: Chris@87: raise ValueError( Chris@87: 'array split does not result in an equal division') Chris@87: res = array_split(ary, indices_or_sections, axis) Chris@87: return res Chris@87: Chris@87: def hsplit(ary, indices_or_sections): Chris@87: """ Chris@87: Split an array into multiple sub-arrays horizontally (column-wise). Chris@87: Chris@87: Please refer to the `split` documentation. `hsplit` is equivalent Chris@87: to `split` with ``axis=1``, the array is always split along the second Chris@87: axis regardless of the array dimension. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: split : Split an array into multiple sub-arrays of equal size. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> x = np.arange(16.0).reshape(4, 4) Chris@87: >>> x Chris@87: array([[ 0., 1., 2., 3.], Chris@87: [ 4., 5., 6., 7.], Chris@87: [ 8., 9., 10., 11.], Chris@87: [ 12., 13., 14., 15.]]) Chris@87: >>> np.hsplit(x, 2) Chris@87: [array([[ 0., 1.], Chris@87: [ 4., 5.], Chris@87: [ 8., 9.], Chris@87: [ 12., 13.]]), Chris@87: array([[ 2., 3.], Chris@87: [ 6., 7.], Chris@87: [ 10., 11.], Chris@87: [ 14., 15.]])] Chris@87: >>> np.hsplit(x, np.array([3, 6])) Chris@87: [array([[ 0., 1., 2.], Chris@87: [ 4., 5., 6.], Chris@87: [ 8., 9., 10.], Chris@87: [ 12., 13., 14.]]), Chris@87: array([[ 3.], Chris@87: [ 7.], Chris@87: [ 11.], Chris@87: [ 15.]]), Chris@87: array([], dtype=float64)] Chris@87: Chris@87: With a higher dimensional array the split is still along the second axis. Chris@87: Chris@87: >>> x = np.arange(8.0).reshape(2, 2, 2) Chris@87: >>> x Chris@87: array([[[ 0., 1.], Chris@87: [ 2., 3.]], Chris@87: [[ 4., 5.], Chris@87: [ 6., 7.]]]) Chris@87: >>> np.hsplit(x, 2) Chris@87: [array([[[ 0., 1.]], Chris@87: [[ 4., 5.]]]), Chris@87: array([[[ 2., 3.]], Chris@87: [[ 6., 7.]]])] Chris@87: Chris@87: """ Chris@87: if len(_nx.shape(ary)) == 0: Chris@87: raise ValueError('hsplit only works on arrays of 1 or more dimensions') Chris@87: if len(ary.shape) > 1: Chris@87: return split(ary, indices_or_sections, 1) Chris@87: else: Chris@87: return split(ary, indices_or_sections, 0) Chris@87: Chris@87: def vsplit(ary, indices_or_sections): Chris@87: """ Chris@87: Split an array into multiple sub-arrays vertically (row-wise). Chris@87: Chris@87: Please refer to the ``split`` documentation. ``vsplit`` is equivalent Chris@87: to ``split`` with `axis=0` (default), the array is always split along the Chris@87: first axis regardless of the array dimension. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: split : Split an array into multiple sub-arrays of equal size. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> x = np.arange(16.0).reshape(4, 4) Chris@87: >>> x Chris@87: array([[ 0., 1., 2., 3.], Chris@87: [ 4., 5., 6., 7.], Chris@87: [ 8., 9., 10., 11.], Chris@87: [ 12., 13., 14., 15.]]) Chris@87: >>> np.vsplit(x, 2) Chris@87: [array([[ 0., 1., 2., 3.], Chris@87: [ 4., 5., 6., 7.]]), Chris@87: array([[ 8., 9., 10., 11.], Chris@87: [ 12., 13., 14., 15.]])] Chris@87: >>> np.vsplit(x, np.array([3, 6])) Chris@87: [array([[ 0., 1., 2., 3.], Chris@87: [ 4., 5., 6., 7.], Chris@87: [ 8., 9., 10., 11.]]), Chris@87: array([[ 12., 13., 14., 15.]]), Chris@87: array([], dtype=float64)] Chris@87: Chris@87: With a higher dimensional array the split is still along the first axis. Chris@87: Chris@87: >>> x = np.arange(8.0).reshape(2, 2, 2) Chris@87: >>> x Chris@87: array([[[ 0., 1.], Chris@87: [ 2., 3.]], Chris@87: [[ 4., 5.], Chris@87: [ 6., 7.]]]) Chris@87: >>> np.vsplit(x, 2) Chris@87: [array([[[ 0., 1.], Chris@87: [ 2., 3.]]]), Chris@87: array([[[ 4., 5.], Chris@87: [ 6., 7.]]])] Chris@87: Chris@87: """ Chris@87: if len(_nx.shape(ary)) < 2: Chris@87: raise ValueError('vsplit only works on arrays of 2 or more dimensions') Chris@87: return split(ary, indices_or_sections, 0) Chris@87: Chris@87: def dsplit(ary, indices_or_sections): Chris@87: """ Chris@87: Split array into multiple sub-arrays along the 3rd axis (depth). Chris@87: Chris@87: Please refer to the `split` documentation. `dsplit` is equivalent Chris@87: to `split` with ``axis=2``, the array is always split along the third Chris@87: axis provided the array dimension is greater than or equal to 3. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: split : Split an array into multiple sub-arrays of equal size. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> x = np.arange(16.0).reshape(2, 2, 4) Chris@87: >>> x Chris@87: array([[[ 0., 1., 2., 3.], Chris@87: [ 4., 5., 6., 7.]], Chris@87: [[ 8., 9., 10., 11.], Chris@87: [ 12., 13., 14., 15.]]]) Chris@87: >>> np.dsplit(x, 2) Chris@87: [array([[[ 0., 1.], Chris@87: [ 4., 5.]], Chris@87: [[ 8., 9.], Chris@87: [ 12., 13.]]]), Chris@87: array([[[ 2., 3.], Chris@87: [ 6., 7.]], Chris@87: [[ 10., 11.], Chris@87: [ 14., 15.]]])] Chris@87: >>> np.dsplit(x, np.array([3, 6])) Chris@87: [array([[[ 0., 1., 2.], Chris@87: [ 4., 5., 6.]], Chris@87: [[ 8., 9., 10.], Chris@87: [ 12., 13., 14.]]]), Chris@87: array([[[ 3.], Chris@87: [ 7.]], Chris@87: [[ 11.], Chris@87: [ 15.]]]), Chris@87: array([], dtype=float64)] Chris@87: Chris@87: """ Chris@87: if len(_nx.shape(ary)) < 3: Chris@87: raise ValueError('dsplit only works on arrays of 3 or more dimensions') Chris@87: return split(ary, indices_or_sections, 2) Chris@87: Chris@87: def get_array_prepare(*args): Chris@87: """Find the wrapper for the array with the highest priority. Chris@87: Chris@87: In case of ties, leftmost wins. If no wrapper is found, return None Chris@87: """ Chris@87: wrappers = sorted((getattr(x, '__array_priority__', 0), -i, Chris@87: x.__array_prepare__) for i, x in enumerate(args) Chris@87: if hasattr(x, '__array_prepare__')) Chris@87: if wrappers: Chris@87: return wrappers[-1][-1] Chris@87: return None Chris@87: Chris@87: def get_array_wrap(*args): Chris@87: """Find the wrapper for the array with the highest priority. Chris@87: Chris@87: In case of ties, leftmost wins. If no wrapper is found, return None Chris@87: """ Chris@87: wrappers = sorted((getattr(x, '__array_priority__', 0), -i, Chris@87: x.__array_wrap__) for i, x in enumerate(args) Chris@87: if hasattr(x, '__array_wrap__')) Chris@87: if wrappers: Chris@87: return wrappers[-1][-1] Chris@87: return None Chris@87: Chris@87: def kron(a, b): Chris@87: """ Chris@87: Kronecker product of two arrays. Chris@87: Chris@87: Computes the Kronecker product, a composite array made of blocks of the Chris@87: second array scaled by the first. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a, b : array_like Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: out : ndarray Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: outer : The outer product Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: The function assumes that the number of dimenensions of `a` and `b` Chris@87: are the same, if necessary prepending the smallest with ones. Chris@87: If `a.shape = (r0,r1,..,rN)` and `b.shape = (s0,s1,...,sN)`, Chris@87: the Kronecker product has shape `(r0*s0, r1*s1, ..., rN*SN)`. Chris@87: The elements are products of elements from `a` and `b`, organized Chris@87: explicitly by:: Chris@87: Chris@87: kron(a,b)[k0,k1,...,kN] = a[i0,i1,...,iN] * b[j0,j1,...,jN] Chris@87: Chris@87: where:: Chris@87: Chris@87: kt = it * st + jt, t = 0,...,N Chris@87: Chris@87: In the common 2-D case (N=1), the block structure can be visualized:: Chris@87: Chris@87: [[ a[0,0]*b, a[0,1]*b, ... , a[0,-1]*b ], Chris@87: [ ... ... ], Chris@87: [ a[-1,0]*b, a[-1,1]*b, ... , a[-1,-1]*b ]] Chris@87: Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> np.kron([1,10,100], [5,6,7]) Chris@87: array([ 5, 6, 7, 50, 60, 70, 500, 600, 700]) Chris@87: >>> np.kron([5,6,7], [1,10,100]) Chris@87: array([ 5, 50, 500, 6, 60, 600, 7, 70, 700]) Chris@87: Chris@87: >>> np.kron(np.eye(2), np.ones((2,2))) Chris@87: array([[ 1., 1., 0., 0.], Chris@87: [ 1., 1., 0., 0.], Chris@87: [ 0., 0., 1., 1.], Chris@87: [ 0., 0., 1., 1.]]) Chris@87: Chris@87: >>> a = np.arange(100).reshape((2,5,2,5)) Chris@87: >>> b = np.arange(24).reshape((2,3,4)) Chris@87: >>> c = np.kron(a,b) Chris@87: >>> c.shape Chris@87: (2, 10, 6, 20) Chris@87: >>> I = (1,3,0,2) Chris@87: >>> J = (0,2,1) Chris@87: >>> J1 = (0,) + J # extend to ndim=4 Chris@87: >>> S1 = (1,) + b.shape Chris@87: >>> K = tuple(np.array(I) * np.array(S1) + np.array(J1)) Chris@87: >>> c[K] == a[I]*b[J] Chris@87: True Chris@87: Chris@87: """ Chris@87: b = asanyarray(b) Chris@87: a = array(a, copy=False, subok=True, ndmin=b.ndim) Chris@87: ndb, nda = b.ndim, a.ndim Chris@87: if (nda == 0 or ndb == 0): Chris@87: return _nx.multiply(a, b) Chris@87: as_ = a.shape Chris@87: bs = b.shape Chris@87: if not a.flags.contiguous: Chris@87: a = reshape(a, as_) Chris@87: if not b.flags.contiguous: Chris@87: b = reshape(b, bs) Chris@87: nd = ndb Chris@87: if (ndb != nda): Chris@87: if (ndb > nda): Chris@87: as_ = (1,)*(ndb-nda) + as_ Chris@87: else: Chris@87: bs = (1,)*(nda-ndb) + bs Chris@87: nd = nda Chris@87: result = outer(a, b).reshape(as_+bs) Chris@87: axis = nd-1 Chris@87: for _ in range(nd): Chris@87: result = concatenate(result, axis=axis) Chris@87: wrapper = get_array_prepare(a, b) Chris@87: if wrapper is not None: Chris@87: result = wrapper(result) Chris@87: wrapper = get_array_wrap(a, b) Chris@87: if wrapper is not None: Chris@87: result = wrapper(result) Chris@87: return result Chris@87: Chris@87: Chris@87: def tile(A, reps): Chris@87: """ Chris@87: Construct an array by repeating A the number of times given by reps. Chris@87: Chris@87: If `reps` has length ``d``, the result will have dimension of Chris@87: ``max(d, A.ndim)``. Chris@87: Chris@87: If ``A.ndim < d``, `A` is promoted to be d-dimensional by prepending new Chris@87: axes. So a shape (3,) array is promoted to (1, 3) for 2-D replication, Chris@87: or shape (1, 1, 3) for 3-D replication. If this is not the desired Chris@87: behavior, promote `A` to d-dimensions manually before calling this Chris@87: function. Chris@87: Chris@87: If ``A.ndim > d``, `reps` is promoted to `A`.ndim by pre-pending 1's to it. Chris@87: Thus for an `A` of shape (2, 3, 4, 5), a `reps` of (2, 2) is treated as Chris@87: (1, 1, 2, 2). Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: A : array_like Chris@87: The input array. Chris@87: reps : array_like Chris@87: The number of repetitions of `A` along each axis. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: c : ndarray Chris@87: The tiled output array. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: repeat : Repeat elements of an array. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([0, 1, 2]) Chris@87: >>> np.tile(a, 2) Chris@87: array([0, 1, 2, 0, 1, 2]) Chris@87: >>> np.tile(a, (2, 2)) Chris@87: array([[0, 1, 2, 0, 1, 2], Chris@87: [0, 1, 2, 0, 1, 2]]) Chris@87: >>> np.tile(a, (2, 1, 2)) Chris@87: array([[[0, 1, 2, 0, 1, 2]], Chris@87: [[0, 1, 2, 0, 1, 2]]]) Chris@87: Chris@87: >>> b = np.array([[1, 2], [3, 4]]) Chris@87: >>> np.tile(b, 2) Chris@87: array([[1, 2, 1, 2], Chris@87: [3, 4, 3, 4]]) Chris@87: >>> np.tile(b, (2, 1)) Chris@87: array([[1, 2], Chris@87: [3, 4], Chris@87: [1, 2], Chris@87: [3, 4]]) Chris@87: Chris@87: """ Chris@87: try: Chris@87: tup = tuple(reps) Chris@87: except TypeError: Chris@87: tup = (reps,) Chris@87: d = len(tup) Chris@87: c = _nx.array(A, copy=False, subok=True, ndmin=d) Chris@87: shape = list(c.shape) Chris@87: n = max(c.size, 1) Chris@87: if (d < c.ndim): Chris@87: tup = (1,)*(c.ndim-d) + tup Chris@87: for i, nrep in enumerate(tup): Chris@87: if nrep != 1: Chris@87: c = c.reshape(-1, n).repeat(nrep, 0) Chris@87: dim_in = shape[i] Chris@87: dim_out = dim_in*nrep Chris@87: shape[i] = dim_out Chris@87: n //= max(dim_in, 1) Chris@87: return c.reshape(shape)