Skip to content
Merged
1 change: 1 addition & 0 deletions docs/source/reference/numpysupported.rst
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ The following top-level functions are supported:
* :func:`numpy.bincount`
* :func:`numpy.blackman`
* :func:`numpy.broadcast_to` (only the 2 first arguments)
* :func:`numpy.broadcast_arrays` (only the first argument)
* :func:`numpy.column_stack`
* :func:`numpy.concatenate`
* :func:`numpy.convolve` (only the 2 first arguments)
Expand Down
30 changes: 30 additions & 0 deletions numba/cpython/unsafe/tuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,36 @@ def codegen(context, builder, signature, args):
return sig, codegen


@intrinsic
def build_int_tuple(tyctx, sz):
"""Creates a sz-tuple of integers."""
if not isinstance(sz, types.IntegerLiteral):
raise errors.RequireLiteralValue(sz)

size = int(sz.literal_value)
tuple_type = types.UniTuple(dtype=types.intp, count=size)
sig = tuple_type(sz)

def codegen(context, builder, signature, args):
def impl(length, empty_tuple):
out = empty_tuple
for i in range(length):
out = tuple_setitem(out, i, 0)
return out

inner_argtypes = [types.intp, tuple_type]
inner_sig = typing.signature(tuple_type, *inner_argtypes)
ll_idx_type = context.get_value_type(types.intp)
# Allocate an empty tuple
empty_tuple = context.get_constant_undef(tuple_type)
inner_args = [ll_idx_type(size), empty_tuple]

res = context.compile_internal(builder, impl, inner_sig, inner_args)
return res

return sig, codegen


@intrinsic
def build_full_slice_tuple(tyctx, sz):
"""Creates a sz-tuple of full slices."""
Expand Down
47 changes: 46 additions & 1 deletion numba/np/arrayobj.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
intrinsic)
from numba.misc import quicksort, mergesort
from numba.cpython import slicing
from numba.cpython.unsafe.tuple import tuple_setitem, build_full_slice_tuple
from numba.cpython.unsafe.tuple import (build_int_tuple,
tuple_setitem,
build_full_slice_tuple)
from numba.core.overload_glue import glue_lowering
from numba.core.extending import overload_classmethod

Expand Down Expand Up @@ -1382,6 +1384,49 @@ def impl(array, shape):
return impl


@register_jitable
def numpy_broadcast_shapes_list(r, m, shape):
for i in range(len(shape)):
k = m - len(shape) + i
tmp = shape[i]
if tmp == 1:
continue
if r[k] == 1:
r[k] = tmp
elif r[k] != tmp:
raise ValueError("shape mismatch: objects"
" cannot be broadcast"
" to a single shape")


@overload(np.broadcast_arrays)
def numpy_broadcast_arrays(*args):
# number of dimensions
Comment thread
stuartarchibald marked this conversation as resolved.
Resolved
m = max([arr.ndim for arr in args])

def impl(*args):
# find out the output shape
# we can't call np.broadcast_shapes here since args may have arrays
# with different shapes and it is not possible to create a list
# with those shapes dinamically
Comment thread
stuartarchibald marked this conversation as resolved.
Resolved
shape = [1] * m
for array in literal_unroll(args):
numpy_broadcast_shapes_list(shape, m, array.shape)

tup = build_int_tuple(m)
Comment thread
stuartarchibald marked this conversation as resolved.
Resolved

for i in range(m):
tup = tuple_setitem(tup, i, shape[i])

# numpy checks if the input arrays have the same shape as `shape`
outs = []
for array in literal_unroll(args):
outs.append(np.broadcast_to(array, tup))
return outs

return impl


def fancy_setslice(context, builder, sig, args, index_types, indices):
"""
Implement slice assignment for arrays. This implementation works for
Expand Down
Loading