Exemple #1
0
        def typer(ptr, shape, dtype=types.none):
            if ptr is types.voidptr:
                ptr_dtype = None
            elif isinstance(ptr, types.CPointer):
                ptr_dtype = ptr.dtype
            else:
                raise NumbaTypeError(
                    "%s(): pointer argument expected, got '%s'" %
                    (func_name, ptr))

            if dtype is types.none:
                if ptr_dtype is None:
                    raise NumbaTypeError(
                        "%s(): explicit dtype required for void* argument" %
                        (func_name, ))
                dtype = ptr_dtype
            elif isinstance(dtype, types.DTypeSpec):
                dtype = dtype.dtype
                if ptr_dtype is not None and dtype != ptr_dtype:
                    raise NumbaTypeError(
                        "%s(): mismatching dtype '%s' for pointer type '%s'" %
                        (func_name, dtype, ptr))
            else:
                raise NumbaTypeError("%s(): invalid dtype spec '%s'" %
                                     (func_name, dtype))

            ndim = parse_shape(shape)
            if ndim is None:
                raise NumbaTypeError("%s(): invalid shape '%s'" %
                                     (func_name, shape))

            return types.Array(dtype, ndim, self.layout)
Exemple #2
0
def _homogeneous_dims(context, func_name, arrays):
    ndim = arrays[0].ndim
    for a in arrays:
        if a.ndim != ndim:
            msg = (
                f"{func_name}(): all the input arrays must have same number "
                "of dimensions")
            raise NumbaTypeError(msg)
    return ndim
        def dummy_to_float(x):
            if isinstance(x, self.DummyType):

                def codegen(x):
                    return float(x.value)

                return codegen
            else:
                raise NumbaTypeError('cannot type float({})'.format(x))
Exemple #4
0
    def generic(self, args, kws):
        assert not kws
        ary, idx, val = args
        if not isinstance(ary, types.Buffer):
            return
        if not ary.mutable:
            msg = f"Cannot modify readonly array of type: {ary}"
            raise NumbaTypeError(msg)
        out = get_array_index_type(ary, idx)
        if out is None:
            return

        idx = out.index
        res = out.result  # res is the result type of the access ary[idx]
        if isinstance(res, types.Array):
            # Indexing produces an array
            if isinstance(val, types.Array):
                if not self.context.can_convert(val.dtype, res.dtype):
                    # DType conversion not possible
                    return
                else:
                    res = val
            elif isinstance(val, types.Sequence):
                if (res.ndim == 1 and
                    self.context.can_convert(val.dtype, res.dtype)):
                    # Allow assignment of sequence to 1d array
                    res = val
                else:
                    # NOTE: sequence-to-array broadcasting is unsupported
                    return
            else:
                # Allow scalar broadcasting
                if self.context.can_convert(val, res.dtype):
                    res = res.dtype
                else:
                    # Incompatible scalar type
                    return
        elif not isinstance(val, types.Array):
            # Single item assignment
            if not self.context.can_convert(val, res):
                # if the array dtype is not yet defined
                if not res.is_precise():
                    # set the array type to use the dtype of value (RHS)
                    newary = ary.copy(dtype=val)
                    return signature(types.none, newary, idx, res)
                else:
                    return
            res = val
        elif (isinstance(val, types.Array) and val.ndim == 0
              and self.context.can_convert(val.dtype, res)):
            # val is an array(T, 0d, O), where T is the type of res, O is order
            res = val
        else:
            return
        return signature(types.none, ary, idx, res)
Exemple #5
0
    def __init__(self, dtype, ndim, layout, readonly=False, name=None):
        from .misc import unliteral

        if isinstance(dtype, Buffer):
            msg = (
                "The dtype of a Buffer type cannot itself be a Buffer type, "
                "this is unsupported behaviour."
                "\nThe dtype requested for the unsupported Buffer was: {}.")
            raise NumbaTypeError(msg.format(dtype))
        if layout not in self.LAYOUTS:
            raise NumbaValueError("Invalid layout '%s'" % layout)
        self.dtype = unliteral(dtype)
        self.ndim = ndim
        self.layout = layout
        if readonly:
            self.mutable = False
        if name is None:
            type_name = self.__class__.__name__.lower()
            if readonly:
                type_name = "readonly %s" % type_name
            name = "%s(%s, %sd, %s)" % (type_name, dtype, ndim, layout)
        super(Buffer, self).__init__(name)
Exemple #6
0
def ol_isinstance(var, typs):
    def true_impl(var, typs):
        return True

    def false_impl(var, typs):
        return False

    var_ty = as_numba_type(var)

    if isinstance(var_ty, types.Optional):
        msg = f'isinstance cannot handle optional types. Found: "{var_ty}"'
        raise NumbaTypeError(msg)

    # NOTE: The current implementation of `isinstance` restricts the type of the
    # instance variable to types that are well known and in common use. The
    # danger of unrestricted tyoe comparison is that a "default" of `False` is
    # required and this means that if there is a bug in the logic of the
    # comparison tree `isinstance` returns False! It's therefore safer to just
    # reject the compilation as untypable!
    supported_var_ty = (types.Number, types.Bytes, types.RangeType,
                        types.DictType, types.LiteralStrKeyDict, types.List,
                        types.ListType, types.Tuple, types.UniTuple, types.Set,
                        types.Function, types.ClassType, types.UnicodeType,
                        types.ClassInstanceType, types.NoneType, types.Array)
    if not isinstance(var_ty, supported_var_ty):
        msg = f'isinstance() does not support variables of type "{var_ty}".'
        raise NumbaTypeError(msg)

    # Warn about the experimental nature of this feature.
    msg = "Use of isinstance() detected. This is an experimental feature."
    warnings.warn(msg, category=NumbaExperimentalFeatureWarning)

    t_typs = typs

    # Check the types that the var can be an instance of, it'll be a scalar,
    # a unituple or a tuple.
    if isinstance(t_typs, types.UniTuple):
        # corner case - all types in isinstance are the same
        t_typs = (t_typs.key[0])

    if not isinstance(t_typs, types.Tuple):
        t_typs = (t_typs, )

    for typ in t_typs:

        if isinstance(typ, types.Function):
            key = typ.key[0]  # functions like int(..), float(..), str(..)
        elif isinstance(typ, types.ClassType):
            key = typ  # jitclasses
        else:
            key = typ.key

        # corner cases for bytes, range, ...
        # avoid registering those types on `as_numba_type`
        types_not_registered = {
            bytes: types.Bytes,
            range: types.RangeType,
            dict: (types.DictType, types.LiteralStrKeyDict),
            list: types.List,
            tuple: types.BaseTuple,
            set: types.Set,
        }
        if key in types_not_registered:
            if isinstance(var_ty, types_not_registered[key]):
                return true_impl
            continue

        if isinstance(typ, types.TypeRef):
            # Use of Numba type classes is in general not supported as they do
            # not work when the jit is disabled.
            if key not in (types.ListType, types.DictType):
                msg = ("Numba type classes (except numba.typed.* container "
                       "types) are not supported.")
                raise NumbaTypeError(msg)
            # Case for TypeRef (i.e. isinstance(var, typed.List))
            #      var_ty == ListType[int64] (instance)
            #         typ == types.ListType  (class)
            return true_impl if type(var_ty) is key else false_impl
        else:
            numba_typ = as_numba_type(key)
            if var_ty == numba_typ:
                return true_impl
            elif isinstance(numba_typ, types.ClassType) and \
                    isinstance(var_ty, types.ClassInstanceType) and \
                    var_ty.key == numba_typ.instance_type.key:
                # check for jitclasses
                return true_impl
            elif isinstance(numba_typ, types.Container) and \
                    numba_typ.key[0] == types.undefined:
                # check for containers (list, tuple, set, ...)
                if isinstance(var_ty, numba_typ.__class__) or \
                    (isinstance(var_ty, types.BaseTuple) and \
                        isinstance(numba_typ, types.BaseTuple)):
                    return true_impl

    return false_impl
Exemple #7
0
    def generic(self, args, kws):
        # First, strip optional types, ufunc loops are typed on concrete types
        args = [x.type if isinstance(x, types.Optional) else x for x in args]

        ufunc = self.ufunc
        base_types, explicit_outputs, ndims, layout = self._handle_inputs(
            ufunc, args, kws)
        ufunc_loop = ufunc_find_matching_loop(ufunc, base_types)
        if ufunc_loop is None:
            raise TypingError("can't resolve ufunc {0} for types {1}".format(
                ufunc.__name__, args))

        # check if all the types involved in the ufunc loop are supported in this mode
        if not supported_ufunc_loop(ufunc, ufunc_loop):
            msg = "ufunc '{0}' using the loop '{1}' not supported in this mode"
            raise TypingError(
                msg=msg.format(ufunc.__name__, ufunc_loop.ufunc_sig))

        # if there is any explicit output type, check that it is valid
        explicit_outputs_np = [as_dtype(tp.dtype) for tp in explicit_outputs]

        # Numpy will happily use unsafe conversions (although it will actually warn)
        if not all(
                np.can_cast(fromty, toty, 'unsafe')
                for (fromty, toty
                     ) in zip(ufunc_loop.numpy_outputs, explicit_outputs_np)):
            msg = "ufunc '{0}' can't cast result to explicit result type"
            raise TypingError(msg=msg.format(ufunc.__name__))

        # A valid loop was found that is compatible. The result of type inference should
        # be based on the explicit output types, and when not available with the type given
        # by the selected NumPy loop
        out = list(explicit_outputs)
        implicit_output_count = ufunc.nout - len(explicit_outputs)
        if implicit_output_count > 0:
            # XXX this is sometimes wrong for datetime64 and timedelta64,
            # as ufunc_find_matching_loop() doesn't do any type inference
            ret_tys = ufunc_loop.outputs[-implicit_output_count:]
            if ndims > 0:
                assert layout is not None
                # If either of the types involved in the ufunc operation have a
                # __array_ufunc__ method then invoke the first such one to
                # determine the output type of the ufunc.
                array_ufunc_type = None
                for a in args:
                    if hasattr(a, "__array_ufunc__"):
                        array_ufunc_type = a
                        break
                output_type = types.Array
                if array_ufunc_type is not None:
                    output_type = array_ufunc_type.__array_ufunc__(
                        ufunc, "__call__", *args, **kws)
                    if output_type is NotImplemented:
                        msg = (f"unsupported use of ufunc {ufunc} on "
                               f"{array_ufunc_type}")
                        # raise TypeError here because
                        # NumpyRulesArrayOperator.generic is capturing
                        # TypingError
                        raise NumbaTypeError(msg)
                    elif not issubclass(output_type, types.Array):
                        msg = (f"ufunc {ufunc} on {array_ufunc_type}"
                               f"cannot return non-array {output_type}")
                        # raise TypeError here because
                        # NumpyRulesArrayOperator.generic is capturing
                        # TypingError
                        raise TypeError(msg)

                ret_tys = [
                    output_type(dtype=ret_ty, ndim=ndims, layout=layout)
                    for ret_ty in ret_tys
                ]
                ret_tys = [
                    resolve_output_type(self.context, args, ret_ty)
                    for ret_ty in ret_tys
                ]
            out.extend(ret_tys)

        return _ufunc_loop_sig(out, args)
Exemple #8
0
def get_array_index_type(ary, idx):
    """
    Returns None or a tuple-3 for the types of the input array, index, and
    resulting type of ``array[index]``.

    Note: This is shared logic for ndarray getitem and setitem.
    """
    if not isinstance(ary, types.Buffer):
        return

    ndim = ary.ndim

    left_indices = []
    right_indices = []
    ellipsis_met = False
    advanced = False
    has_integer = False

    if not isinstance(idx, types.BaseTuple):
        idx = [idx]

    # Walk indices
    for ty in idx:
        if ty is types.ellipsis:
            if ellipsis_met:
                raise NumbaTypeError("only one ellipsis allowed in array index "
                                     "(got %s)" % (idx,))
            ellipsis_met = True
        elif isinstance(ty, types.SliceType):
            pass
        elif isinstance(ty, types.Integer):
            # Normalize integer index
            ty = types.intp if ty.signed else types.uintp
            # Integer indexing removes the given dimension
            ndim -= 1
            has_integer = True
        elif (isinstance(ty, types.Array) and ty.ndim == 0
              and isinstance(ty.dtype, types.Integer)):
            # 0-d array used as integer index
            ndim -= 1
            has_integer = True
        elif (isinstance(ty, types.Array)
              and ty.ndim == 1
              and isinstance(ty.dtype, (types.Integer, types.Boolean))):
            if advanced or has_integer:
                # We don't support the complicated combination of
                # advanced indices (and integers are considered part
                # of them by Numpy).
                msg = "only one advanced index supported"
                raise NumbaNotImplementedError(msg)
            advanced = True
        else:
            raise NumbaTypeError("unsupported array index type %s in %s"
                                 % (ty, idx))
        (right_indices if ellipsis_met else left_indices).append(ty)

    # Only Numpy arrays support advanced indexing
    if advanced and not isinstance(ary, types.Array):
        return

    # Check indices and result dimensionality
    all_indices = left_indices + right_indices
    if ellipsis_met:
        assert right_indices[0] is types.ellipsis
        del right_indices[0]

    n_indices = len(all_indices) - ellipsis_met
    if n_indices > ary.ndim:
        raise NumbaTypeError("cannot index %s with %d indices: %s"
                             % (ary, n_indices, idx))
    if n_indices == ary.ndim and ndim == 0 and not ellipsis_met:
        # Full integer indexing => scalar result
        # (note if ellipsis is present, a 0-d view is returned instead)
        res = ary.dtype

    elif advanced:
        # Result is a copy
        res = ary.copy(ndim=ndim, layout='C', readonly=False)

    else:
        # Result is a view
        if ary.slice_is_copy:
            # Avoid view semantics when the original type creates a copy
            # when slicing.
            return

        # Infer layout
        layout = ary.layout

        def keeps_contiguity(ty, is_innermost):
            # A slice can only keep an array contiguous if it is the
            # innermost index and it is not strided
            return (ty is types.ellipsis or isinstance(ty, types.Integer)
                    or (is_innermost and isinstance(ty, types.SliceType)
                        and not ty.has_step))

        def check_contiguity(outer_indices):
            """
            Whether indexing with the given indices (from outer to inner in
            physical layout order) can keep an array contiguous.
            """
            for ty in outer_indices[:-1]:
                if not keeps_contiguity(ty, False):
                    return False
            if outer_indices and not keeps_contiguity(outer_indices[-1], True):
                return False
            return True

        if layout == 'C':
            # Integer indexing on the left keeps the array C-contiguous
            if n_indices == ary.ndim:
                # If all indices are there, ellipsis's place is indifferent
                left_indices = left_indices + right_indices
                right_indices = []
            if right_indices:
                layout = 'A'
            elif not check_contiguity(left_indices):
                layout = 'A'
        elif layout == 'F':
            # Integer indexing on the right keeps the array F-contiguous
            if n_indices == ary.ndim:
                # If all indices are there, ellipsis's place is indifferent
                right_indices = left_indices + right_indices
                left_indices = []
            if left_indices:
                layout = 'A'
            elif not check_contiguity(right_indices[::-1]):
                layout = 'A'

        if ndim == 0:
            # Implicitly convert to a scalar if the output ndim==0
            res = ary.dtype
        else:
            res = ary.copy(ndim=ndim, layout=layout)

    # Re-wrap indices
    if isinstance(idx, types.BaseTuple):
        idx = types.BaseTuple.from_types(all_indices)
    else:
        idx, = all_indices

    return Indexing(idx, res, advanced)