ABI: uint8 too small for potential `complex quad` itemsize bits? · Issue #73 · dmlc/dlpack · GitHub
Skip to content

ABI: uint8 too small for potential complex quad itemsize bits? #73

Open

Description

@seberg

If quad-precision takes off, then the current uint8 for the itemsize cannot represent the 128+128 = 256 bits of a complex quad number. Even now that would fail for most long double storage formats (those cannot be represented right now, so I am not sure it matters).

If an ABI break is necessary in the future, maybe this should be bumped to uint16 (maybe some other ones as well)? I guess there will be other ways to work around the limitation, though. And I admit quad-precision complex may well be as bad as it gets and is just at the limit.

Activity

  1. leofang commented on Jun 7, 2021

    @leofang
    Collaborator

    We should list a few items that would be great to do if we plan to break ABI.

  2. hpkfft commented on Sep 11, 2026

    @hpkfft

    🌱 Let me share the basic outline of an idea, which is to add a flag DLPACK_FLAG_BITMASK_COMPLEX_COMPONENTS.
    This means that the data is complex, but the bits member of DLDataType is the size of the real component. The imaginary component is understood to be the same size and to follow the real component contiguously in memory.
    The shape array gives the shape of the complex tensor.
    The strides array gives the strides measured in number of real-valued-sized elements.

    Example A:

    >>> a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.complex128)
    >>> a
    array([[1.+0.j, 2.+0.j, 3.+0.j],
           [4.+0.j, 5.+0.j, 6.+0.j]])
    >>> a.shape
    (2, 3)
    >>> a.strides
    (48, 16)
    

    For DLPack, code=kDLFloat and bits=64 since components are IEEE binary64, shape={2,3}, and strides={6,2}.
    NumPy measures strides in bytes; DLPack measures strides in 8B units because bits is 8B.
    Of course, the flag bit DLPACK_FLAG_BITMASK_COMPLEX_COMPONENTS is set.

    Example B:

    >>> a = np.array([[1, 2, 3, 4, 0], [5, 6, 7, 8, 0]], dtype=np.float64)
    >>> s = a[:, 0:4]  # slice
    >>> b = s.view(np.complex128)
    >>> b
    array([[1.+2.j, 3.+4.j],
           [5.+6.j, 7.+8.j]])
    >>> b.shape
    (2, 2)
    >>> b.strides
    (40, 16)
    

    For DLPack, code=kDLFloat and bits=64 since components are IEEE binary64, shape={2,2}, and strides={5,2}.
    Note that, today, b cannot be dlpacked:

    >>> b.__dlpack__()
    Traceback (most recent call last):
      File "<python-input-38>", line 1, in <module>
        b.__dlpack__()
        ~~~~~~~~~~~~^^
    BufferError: DLPack only supports strides which are a multiple of itemsize.
    

    but with DLPACK_FLAG_BITMASK_COMPLEX_COMPONENTS it can be.
    And it ought to be dlpackable, since alignof(std::complex<double>) == 8.

    Example C:

    >>> c = np.array([1,2,3], dtype=ComplexQuadPrecDType())  # Or whatever it's called
    

    For DLPack, code=kDLFloat and bits=128 since components are IEEE binary128, shape={3}, and strides={2}.
    With DLPACK_FLAG_BITMASK_COMPLEX_COMPONENTS set, uint8_t bits is wide enough.

  3. seberg commented on Sep 11, 2026

    @seberg
    CollaboratorAuthor

    Can't say this strikes me as clearly nice. Sacrificing a bit on the dtype enum to mean "complex version" would make more sense to me. But even then, things like striding suddenly being per component feels at least a bit awkward, if maybe not so awkward to be terrible if there is a need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions