You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							548 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
	
	
							548 lines
						
					
					
						
							18 KiB
						
					
					
				"""
 | 
						|
Utilities that manipulate strides to achieve desirable effects.
 | 
						|
 | 
						|
An explanation of strides can be found in the "ndarray.rst" file in the
 | 
						|
NumPy reference guide.
 | 
						|
 | 
						|
"""
 | 
						|
import numpy as np
 | 
						|
from numpy.core.numeric import normalize_axis_tuple
 | 
						|
from numpy.core.overrides import array_function_dispatch, set_module
 | 
						|
 | 
						|
__all__ = ['broadcast_to', 'broadcast_arrays', 'broadcast_shapes']
 | 
						|
 | 
						|
 | 
						|
class DummyArray:
 | 
						|
    """Dummy object that just exists to hang __array_interface__ dictionaries
 | 
						|
    and possibly keep alive a reference to a base array.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, interface, base=None):
 | 
						|
        self.__array_interface__ = interface
 | 
						|
        self.base = base
 | 
						|
 | 
						|
 | 
						|
def _maybe_view_as_subclass(original_array, new_array):
 | 
						|
    if type(original_array) is not type(new_array):
 | 
						|
        # if input was an ndarray subclass and subclasses were OK,
 | 
						|
        # then view the result as that subclass.
 | 
						|
        new_array = new_array.view(type=type(original_array))
 | 
						|
        # Since we have done something akin to a view from original_array, we
 | 
						|
        # should let the subclass finalize (if it has it implemented, i.e., is
 | 
						|
        # not None).
 | 
						|
        if new_array.__array_finalize__:
 | 
						|
            new_array.__array_finalize__(original_array)
 | 
						|
    return new_array
 | 
						|
 | 
						|
 | 
						|
def as_strided(x, shape=None, strides=None, subok=False, writeable=True):
 | 
						|
    """
 | 
						|
    Create a view into the array with the given shape and strides.
 | 
						|
 | 
						|
    .. warning:: This function has to be used with extreme care, see notes.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    x : ndarray
 | 
						|
        Array to create a new.
 | 
						|
    shape : sequence of int, optional
 | 
						|
        The shape of the new array. Defaults to ``x.shape``.
 | 
						|
    strides : sequence of int, optional
 | 
						|
        The strides of the new array. Defaults to ``x.strides``.
 | 
						|
    subok : bool, optional
 | 
						|
        .. versionadded:: 1.10
 | 
						|
 | 
						|
        If True, subclasses are preserved.
 | 
						|
    writeable : bool, optional
 | 
						|
        .. versionadded:: 1.12
 | 
						|
 | 
						|
        If set to False, the returned array will always be readonly.
 | 
						|
        Otherwise it will be writable if the original array was. It
 | 
						|
        is advisable to set this to False if possible (see Notes).
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    view : ndarray
 | 
						|
 | 
						|
    See also
 | 
						|
    --------
 | 
						|
    broadcast_to : broadcast an array to a given shape.
 | 
						|
    reshape : reshape an array.
 | 
						|
    lib.stride_tricks.sliding_window_view :
 | 
						|
        userfriendly and safe function for the creation of sliding window views.
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    ``as_strided`` creates a view into the array given the exact strides
 | 
						|
    and shape. This means it manipulates the internal data structure of
 | 
						|
    ndarray and, if done incorrectly, the array elements can point to
 | 
						|
    invalid memory and can corrupt results or crash your program.
 | 
						|
    It is advisable to always use the original ``x.strides`` when
 | 
						|
    calculating new strides to avoid reliance on a contiguous memory
 | 
						|
    layout.
 | 
						|
 | 
						|
    Furthermore, arrays created with this function often contain self
 | 
						|
    overlapping memory, so that two elements are identical.
 | 
						|
    Vectorized write operations on such arrays will typically be
 | 
						|
    unpredictable. They may even give different results for small, large,
 | 
						|
    or transposed arrays.
 | 
						|
 | 
						|
    Since writing to these arrays has to be tested and done with great
 | 
						|
    care, you may want to use ``writeable=False`` to avoid accidental write
 | 
						|
    operations.
 | 
						|
 | 
						|
    For these reasons it is advisable to avoid ``as_strided`` when
 | 
						|
    possible.
 | 
						|
    """
 | 
						|
    # first convert input to array, possibly keeping subclass
 | 
						|
    x = np.array(x, copy=False, subok=subok)
 | 
						|
    interface = dict(x.__array_interface__)
 | 
						|
    if shape is not None:
 | 
						|
        interface['shape'] = tuple(shape)
 | 
						|
    if strides is not None:
 | 
						|
        interface['strides'] = tuple(strides)
 | 
						|
 | 
						|
    array = np.asarray(DummyArray(interface, base=x))
 | 
						|
    # The route via `__interface__` does not preserve structured
 | 
						|
    # dtypes. Since dtype should remain unchanged, we set it explicitly.
 | 
						|
    array.dtype = x.dtype
 | 
						|
 | 
						|
    view = _maybe_view_as_subclass(x, array)
 | 
						|
 | 
						|
    if view.flags.writeable and not writeable:
 | 
						|
        view.flags.writeable = False
 | 
						|
 | 
						|
    return view
 | 
						|
 | 
						|
 | 
						|
def _sliding_window_view_dispatcher(x, window_shape, axis=None, *,
 | 
						|
                                    subok=None, writeable=None):
 | 
						|
    return (x,)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_sliding_window_view_dispatcher)
 | 
						|
def sliding_window_view(x, window_shape, axis=None, *,
 | 
						|
                        subok=False, writeable=False):
 | 
						|
    """
 | 
						|
    Create a sliding window view into the array with the given window shape.
 | 
						|
 | 
						|
    Also known as rolling or moving window, the window slides across all
 | 
						|
    dimensions of the array and extracts subsets of the array at all window
 | 
						|
    positions.
 | 
						|
    
 | 
						|
    .. versionadded:: 1.20.0
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    x : array_like
 | 
						|
        Array to create the sliding window view from.
 | 
						|
    window_shape : int or tuple of int
 | 
						|
        Size of window over each axis that takes part in the sliding window.
 | 
						|
        If `axis` is not present, must have same length as the number of input
 | 
						|
        array dimensions. Single integers `i` are treated as if they were the
 | 
						|
        tuple `(i,)`.
 | 
						|
    axis : int or tuple of int, optional
 | 
						|
        Axis or axes along which the sliding window is applied.
 | 
						|
        By default, the sliding window is applied to all axes and
 | 
						|
        `window_shape[i]` will refer to axis `i` of `x`.
 | 
						|
        If `axis` is given as a `tuple of int`, `window_shape[i]` will refer to
 | 
						|
        the axis `axis[i]` of `x`.
 | 
						|
        Single integers `i` are treated as if they were the tuple `(i,)`.
 | 
						|
    subok : bool, optional
 | 
						|
        If True, sub-classes will be passed-through, otherwise the returned
 | 
						|
        array will be forced to be a base-class array (default).
 | 
						|
    writeable : bool, optional
 | 
						|
        When true, allow writing to the returned view. The default is false,
 | 
						|
        as this should be used with caution: the returned view contains the
 | 
						|
        same memory location multiple times, so writing to one location will
 | 
						|
        cause others to change.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    view : ndarray
 | 
						|
        Sliding window view of the array. The sliding window dimensions are
 | 
						|
        inserted at the end, and the original dimensions are trimmed as
 | 
						|
        required by the size of the sliding window.
 | 
						|
        That is, ``view.shape = x_shape_trimmed + window_shape``, where
 | 
						|
        ``x_shape_trimmed`` is ``x.shape`` with every entry reduced by one less
 | 
						|
        than the corresponding window size.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    lib.stride_tricks.as_strided: A lower-level and less safe routine for
 | 
						|
        creating arbitrary views from custom shape and strides.
 | 
						|
    broadcast_to: broadcast an array to a given shape.
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    For many applications using a sliding window view can be convenient, but
 | 
						|
    potentially very slow. Often specialized solutions exist, for example:
 | 
						|
 | 
						|
    - `scipy.signal.fftconvolve`
 | 
						|
 | 
						|
    - filtering functions in `scipy.ndimage`
 | 
						|
 | 
						|
    - moving window functions provided by
 | 
						|
      `bottleneck <https://github.com/pydata/bottleneck>`_.
 | 
						|
 | 
						|
    As a rough estimate, a sliding window approach with an input size of `N`
 | 
						|
    and a window size of `W` will scale as `O(N*W)` where frequently a special
 | 
						|
    algorithm can achieve `O(N)`. That means that the sliding window variant
 | 
						|
    for a window size of 100 can be a 100 times slower than a more specialized
 | 
						|
    version.
 | 
						|
 | 
						|
    Nevertheless, for small window sizes, when no custom algorithm exists, or
 | 
						|
    as a prototyping and developing tool, this function can be a good solution.
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> x = np.arange(6)
 | 
						|
    >>> x.shape
 | 
						|
    (6,)
 | 
						|
    >>> v = sliding_window_view(x, 3)
 | 
						|
    >>> v.shape
 | 
						|
    (4, 3)
 | 
						|
    >>> v
 | 
						|
    array([[0, 1, 2],
 | 
						|
           [1, 2, 3],
 | 
						|
           [2, 3, 4],
 | 
						|
           [3, 4, 5]])
 | 
						|
 | 
						|
    This also works in more dimensions, e.g.
 | 
						|
 | 
						|
    >>> i, j = np.ogrid[:3, :4]
 | 
						|
    >>> x = 10*i + j
 | 
						|
    >>> x.shape
 | 
						|
    (3, 4)
 | 
						|
    >>> x
 | 
						|
    array([[ 0,  1,  2,  3],
 | 
						|
           [10, 11, 12, 13],
 | 
						|
           [20, 21, 22, 23]])
 | 
						|
    >>> shape = (2,2)
 | 
						|
    >>> v = sliding_window_view(x, shape)
 | 
						|
    >>> v.shape
 | 
						|
    (2, 3, 2, 2)
 | 
						|
    >>> v
 | 
						|
    array([[[[ 0,  1],
 | 
						|
             [10, 11]],
 | 
						|
            [[ 1,  2],
 | 
						|
             [11, 12]],
 | 
						|
            [[ 2,  3],
 | 
						|
             [12, 13]]],
 | 
						|
           [[[10, 11],
 | 
						|
             [20, 21]],
 | 
						|
            [[11, 12],
 | 
						|
             [21, 22]],
 | 
						|
            [[12, 13],
 | 
						|
             [22, 23]]]])
 | 
						|
 | 
						|
    The axis can be specified explicitly:
 | 
						|
 | 
						|
    >>> v = sliding_window_view(x, 3, 0)
 | 
						|
    >>> v.shape
 | 
						|
    (1, 4, 3)
 | 
						|
    >>> v
 | 
						|
    array([[[ 0, 10, 20],
 | 
						|
            [ 1, 11, 21],
 | 
						|
            [ 2, 12, 22],
 | 
						|
            [ 3, 13, 23]]])
 | 
						|
 | 
						|
    The same axis can be used several times. In that case, every use reduces
 | 
						|
    the corresponding original dimension:
 | 
						|
 | 
						|
    >>> v = sliding_window_view(x, (2, 3), (1, 1))
 | 
						|
    >>> v.shape
 | 
						|
    (3, 1, 2, 3)
 | 
						|
    >>> v
 | 
						|
    array([[[[ 0,  1,  2],
 | 
						|
             [ 1,  2,  3]]],
 | 
						|
           [[[10, 11, 12],
 | 
						|
             [11, 12, 13]]],
 | 
						|
           [[[20, 21, 22],
 | 
						|
             [21, 22, 23]]]])
 | 
						|
 | 
						|
    Combining with stepped slicing (`::step`), this can be used to take sliding
 | 
						|
    views which skip elements:
 | 
						|
 | 
						|
    >>> x = np.arange(7)
 | 
						|
    >>> sliding_window_view(x, 5)[:, ::2]
 | 
						|
    array([[0, 2, 4],
 | 
						|
           [1, 3, 5],
 | 
						|
           [2, 4, 6]])
 | 
						|
 | 
						|
    or views which move by multiple elements
 | 
						|
 | 
						|
    >>> x = np.arange(7)
 | 
						|
    >>> sliding_window_view(x, 3)[::2, :]
 | 
						|
    array([[0, 1, 2],
 | 
						|
           [2, 3, 4],
 | 
						|
           [4, 5, 6]])
 | 
						|
 | 
						|
    A common application of `sliding_window_view` is the calculation of running
 | 
						|
    statistics. The simplest example is the
 | 
						|
    `moving average <https://en.wikipedia.org/wiki/Moving_average>`_:
 | 
						|
 | 
						|
    >>> x = np.arange(6)
 | 
						|
    >>> x.shape
 | 
						|
    (6,)
 | 
						|
    >>> v = sliding_window_view(x, 3)
 | 
						|
    >>> v.shape
 | 
						|
    (4, 3)
 | 
						|
    >>> v
 | 
						|
    array([[0, 1, 2],
 | 
						|
           [1, 2, 3],
 | 
						|
           [2, 3, 4],
 | 
						|
           [3, 4, 5]])
 | 
						|
    >>> moving_average = v.mean(axis=-1)
 | 
						|
    >>> moving_average
 | 
						|
    array([1., 2., 3., 4.])
 | 
						|
 | 
						|
    Note that a sliding window approach is often **not** optimal (see Notes).
 | 
						|
    """
 | 
						|
    window_shape = (tuple(window_shape)
 | 
						|
                    if np.iterable(window_shape)
 | 
						|
                    else (window_shape,))
 | 
						|
    # first convert input to array, possibly keeping subclass
 | 
						|
    x = np.array(x, copy=False, subok=subok)
 | 
						|
 | 
						|
    window_shape_array = np.array(window_shape)
 | 
						|
    if np.any(window_shape_array < 0):
 | 
						|
        raise ValueError('`window_shape` cannot contain negative values')
 | 
						|
 | 
						|
    if axis is None:
 | 
						|
        axis = tuple(range(x.ndim))
 | 
						|
        if len(window_shape) != len(axis):
 | 
						|
            raise ValueError(f'Since axis is `None`, must provide '
 | 
						|
                             f'window_shape for all dimensions of `x`; '
 | 
						|
                             f'got {len(window_shape)} window_shape elements '
 | 
						|
                             f'and `x.ndim` is {x.ndim}.')
 | 
						|
    else:
 | 
						|
        axis = normalize_axis_tuple(axis, x.ndim, allow_duplicate=True)
 | 
						|
        if len(window_shape) != len(axis):
 | 
						|
            raise ValueError(f'Must provide matching length window_shape and '
 | 
						|
                             f'axis; got {len(window_shape)} window_shape '
 | 
						|
                             f'elements and {len(axis)} axes elements.')
 | 
						|
 | 
						|
    out_strides = x.strides + tuple(x.strides[ax] for ax in axis)
 | 
						|
 | 
						|
    # note: same axis can be windowed repeatedly
 | 
						|
    x_shape_trimmed = list(x.shape)
 | 
						|
    for ax, dim in zip(axis, window_shape):
 | 
						|
        if x_shape_trimmed[ax] < dim:
 | 
						|
            raise ValueError(
 | 
						|
                'window shape cannot be larger than input array shape')
 | 
						|
        x_shape_trimmed[ax] -= dim - 1
 | 
						|
    out_shape = tuple(x_shape_trimmed) + window_shape
 | 
						|
    return as_strided(x, strides=out_strides, shape=out_shape,
 | 
						|
                      subok=subok, writeable=writeable)
 | 
						|
 | 
						|
 | 
						|
def _broadcast_to(array, shape, subok, readonly):
 | 
						|
    shape = tuple(shape) if np.iterable(shape) else (shape,)
 | 
						|
    array = np.array(array, copy=False, subok=subok)
 | 
						|
    if not shape and array.shape:
 | 
						|
        raise ValueError('cannot broadcast a non-scalar to a scalar array')
 | 
						|
    if any(size < 0 for size in shape):
 | 
						|
        raise ValueError('all elements of broadcast shape must be non-'
 | 
						|
                         'negative')
 | 
						|
    extras = []
 | 
						|
    it = np.nditer(
 | 
						|
        (array,), flags=['multi_index', 'refs_ok', 'zerosize_ok'] + extras,
 | 
						|
        op_flags=['readonly'], itershape=shape, order='C')
 | 
						|
    with it:
 | 
						|
        # never really has writebackifcopy semantics
 | 
						|
        broadcast = it.itviews[0]
 | 
						|
    result = _maybe_view_as_subclass(array, broadcast)
 | 
						|
    # In a future version this will go away
 | 
						|
    if not readonly and array.flags._writeable_no_warn:
 | 
						|
        result.flags.writeable = True
 | 
						|
        result.flags._warn_on_write = True
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def _broadcast_to_dispatcher(array, shape, subok=None):
 | 
						|
    return (array,)
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_broadcast_to_dispatcher, module='numpy')
 | 
						|
def broadcast_to(array, shape, subok=False):
 | 
						|
    """Broadcast an array to a new shape.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    array : array_like
 | 
						|
        The array to broadcast.
 | 
						|
    shape : tuple or int
 | 
						|
        The shape of the desired array. A single integer ``i`` is interpreted
 | 
						|
        as ``(i,)``.
 | 
						|
    subok : bool, optional
 | 
						|
        If True, then sub-classes will be passed-through, otherwise
 | 
						|
        the returned array will be forced to be a base-class array (default).
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    broadcast : array
 | 
						|
        A readonly view on the original array with the given shape. It is
 | 
						|
        typically not contiguous. Furthermore, more than one element of a
 | 
						|
        broadcasted array may refer to a single memory location.
 | 
						|
 | 
						|
    Raises
 | 
						|
    ------
 | 
						|
    ValueError
 | 
						|
        If the array is not compatible with the new shape according to NumPy's
 | 
						|
        broadcasting rules.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    broadcast
 | 
						|
    broadcast_arrays
 | 
						|
    broadcast_shapes
 | 
						|
 | 
						|
    Notes
 | 
						|
    -----
 | 
						|
    .. versionadded:: 1.10.0
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> x = np.array([1, 2, 3])
 | 
						|
    >>> np.broadcast_to(x, (3, 3))
 | 
						|
    array([[1, 2, 3],
 | 
						|
           [1, 2, 3],
 | 
						|
           [1, 2, 3]])
 | 
						|
    """
 | 
						|
    return _broadcast_to(array, shape, subok=subok, readonly=True)
 | 
						|
 | 
						|
 | 
						|
def _broadcast_shape(*args):
 | 
						|
    """Returns the shape of the arrays that would result from broadcasting the
 | 
						|
    supplied arrays against each other.
 | 
						|
    """
 | 
						|
    # use the old-iterator because np.nditer does not handle size 0 arrays
 | 
						|
    # consistently
 | 
						|
    b = np.broadcast(*args[:32])
 | 
						|
    # unfortunately, it cannot handle 32 or more arguments directly
 | 
						|
    for pos in range(32, len(args), 31):
 | 
						|
        # ironically, np.broadcast does not properly handle np.broadcast
 | 
						|
        # objects (it treats them as scalars)
 | 
						|
        # use broadcasting to avoid allocating the full array
 | 
						|
        b = broadcast_to(0, b.shape)
 | 
						|
        b = np.broadcast(b, *args[pos:(pos + 31)])
 | 
						|
    return b.shape
 | 
						|
 | 
						|
 | 
						|
@set_module('numpy')
 | 
						|
def broadcast_shapes(*args):
 | 
						|
    """
 | 
						|
    Broadcast the input shapes into a single shape.
 | 
						|
 | 
						|
    :ref:`Learn more about broadcasting here <basics.broadcasting>`.
 | 
						|
 | 
						|
    .. versionadded:: 1.20.0
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    `*args` : tuples of ints, or ints
 | 
						|
        The shapes to be broadcast against each other.
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    tuple
 | 
						|
        Broadcasted shape.
 | 
						|
 | 
						|
    Raises
 | 
						|
    ------
 | 
						|
    ValueError
 | 
						|
        If the shapes are not compatible and cannot be broadcast according
 | 
						|
        to NumPy's broadcasting rules.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    broadcast
 | 
						|
    broadcast_arrays
 | 
						|
    broadcast_to
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> np.broadcast_shapes((1, 2), (3, 1), (3, 2))
 | 
						|
    (3, 2)
 | 
						|
 | 
						|
    >>> np.broadcast_shapes((6, 7), (5, 6, 1), (7,), (5, 1, 7))
 | 
						|
    (5, 6, 7)
 | 
						|
    """
 | 
						|
    arrays = [np.empty(x, dtype=[]) for x in args]
 | 
						|
    return _broadcast_shape(*arrays)
 | 
						|
 | 
						|
 | 
						|
def _broadcast_arrays_dispatcher(*args, subok=None):
 | 
						|
    return args
 | 
						|
 | 
						|
 | 
						|
@array_function_dispatch(_broadcast_arrays_dispatcher, module='numpy')
 | 
						|
def broadcast_arrays(*args, subok=False):
 | 
						|
    """
 | 
						|
    Broadcast any number of arrays against each other.
 | 
						|
 | 
						|
    Parameters
 | 
						|
    ----------
 | 
						|
    `*args` : array_likes
 | 
						|
        The arrays to broadcast.
 | 
						|
 | 
						|
    subok : bool, optional
 | 
						|
        If True, then sub-classes will be passed-through, otherwise
 | 
						|
        the returned arrays will be forced to be a base-class array (default).
 | 
						|
 | 
						|
    Returns
 | 
						|
    -------
 | 
						|
    broadcasted : list of arrays
 | 
						|
        These arrays are views on the original arrays.  They are typically
 | 
						|
        not contiguous.  Furthermore, more than one element of a
 | 
						|
        broadcasted array may refer to a single memory location. If you need
 | 
						|
        to write to the arrays, make copies first. While you can set the
 | 
						|
        ``writable`` flag True, writing to a single output value may end up
 | 
						|
        changing more than one location in the output array.
 | 
						|
 | 
						|
        .. deprecated:: 1.17
 | 
						|
            The output is currently marked so that if written to, a deprecation
 | 
						|
            warning will be emitted. A future version will set the
 | 
						|
            ``writable`` flag False so writing to it will raise an error.
 | 
						|
 | 
						|
    See Also
 | 
						|
    --------
 | 
						|
    broadcast
 | 
						|
    broadcast_to
 | 
						|
    broadcast_shapes
 | 
						|
 | 
						|
    Examples
 | 
						|
    --------
 | 
						|
    >>> x = np.array([[1,2,3]])
 | 
						|
    >>> y = np.array([[4],[5]])
 | 
						|
    >>> np.broadcast_arrays(x, y)
 | 
						|
    [array([[1, 2, 3],
 | 
						|
           [1, 2, 3]]), array([[4, 4, 4],
 | 
						|
           [5, 5, 5]])]
 | 
						|
 | 
						|
    Here is a useful idiom for getting contiguous copies instead of
 | 
						|
    non-contiguous views.
 | 
						|
 | 
						|
    >>> [np.array(a) for a in np.broadcast_arrays(x, y)]
 | 
						|
    [array([[1, 2, 3],
 | 
						|
           [1, 2, 3]]), array([[4, 4, 4],
 | 
						|
           [5, 5, 5]])]
 | 
						|
 | 
						|
    """
 | 
						|
    # nditer is not used here to avoid the limit of 32 arrays.
 | 
						|
    # Otherwise, something like the following one-liner would suffice:
 | 
						|
    # return np.nditer(args, flags=['multi_index', 'zerosize_ok'],
 | 
						|
    #                  order='C').itviews
 | 
						|
 | 
						|
    args = [np.array(_m, copy=False, subok=subok) for _m in args]
 | 
						|
 | 
						|
    shape = _broadcast_shape(*args)
 | 
						|
 | 
						|
    if all(array.shape == shape for array in args):
 | 
						|
        # Common case where nothing needs to be broadcasted.
 | 
						|
        return args
 | 
						|
 | 
						|
    return [_broadcast_to(array, shape, subok=subok, readonly=False)
 | 
						|
            for array in args]
 |