Present:

Note: a table of contents can be found in the lower left corner

Nomenclature

Based on Matti's suggestion, if something is confusing maybe use these?:

  • dtype: A class (type or not)
  • descriptor (or a dtype): object tagged onto the array (an instance of dtype)
  • scalar type: A type which, when instanciated, provides the scalar class
  • a scalar: instance of scalar type.

API Brainstorming

Python API code


class mytype(dtype):
    pass

Sebastian's take/start

class dtype(object):
    def __promote__(self, other):
        """Used by np.promote_types, identical to result_type
        but without scalar logic.
        """
        if isinstance(other, self):
            # make sure to give priority to subclasses:
            self, other = other, self

        if self.__can_cast__(other):
            return other
        if other.__can_cast__(self):
            return self
        
        raise TypeError("cannot promote to common type.")


class unit(dtype):
    itemsize = 8
    type = pyunit

    def __new__(self):
        # what is specfically needed here?
        pass
    
    def __item_unpack__(self, val):
        """How to do this as low level loops?"""
        return self.type.from_bytes(val)

    def __item_pack__(self, obj):
        if not isinstance(obj, self.type):
            raise ValueError
        return obj.to_bytes()

    @classmethod  # not sure?
    def __promote__(cls, dt1, dt2):
        """By default, checks can_cast(self, other)"""
        return np.result_type(self, other)

    @classmethod
    def __can_cast__(cls, dt1, dt2, casting="safe"):
        return True or False  # or unit["m"], loop?

    @classmethod
    def __get_loop__(self, ufunc, in_types, out_types):
        """
        Alternatively, register loops and:
            * check exact loops → promote → check loops again
            * (loop could still refuse)
        """
        if not_possible:
            return NotImplemented
        return UfuncLoop


class UfuncLoop:
    # probably largely C-slots, but could fill from python
    inner_loop
    setup_loop = None     # i.e. FloatClearErr
    teardown_loop = None  # i.e. FloatCheckErr
    needs_api  # Flag (or allow setup to set/override?)
    identity = NotImplemented
    # more flags to add
    
    # Other or even extendable things?:
    masked_inner_loop = None  # already auto-wrapped if not there
    specialized_inner_loops = None  # contiguous (copy code), AVX?    

Decisions and Discussion

Scalars are dtype instances?

Decisions:

ArrFuncs and Subclassing

Decisions:

Casting

  • Slot such as __can_cast__?
  • Registration based system such as no?

Decisions:

Promotion

Common type normally found with safe casting semantics (if a can safe cast to b, then promote(a, b) is a).

  • np.floating may be tricky?
  • Custom rules necessary?
  • Promote scalars in np.array

Decisions:

UFuncs

Need:

  • flexible dtype specialization
  • setup/teardown
  • Inner-loop metadata

Should thi

Decisions:

Compatibility issues?

  • How far can we go without creating compatibility issues e.g. for numba?
numba usage of ufunc struct
  • iterates ufunc->functions to find its own and
    edit ufunc->data for that function.
  • Does manual loop adding modifying:
    • ntypes
    • functions
    • data
    • ptr (used also by from_pyfunc, is freed on dealloc)
      • From numba code: ptr == |<- functions ->|<- data ->|<- types ->|

Random Notes

Room for random notes/thoughts so they do not get lost?

  • Remember ufunc-inner-loops should have a return value.
  • Ufuncs could have default args or parameter kwargs?
Select a repo