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