You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ABI: uint8 too small for potential complex quad itemsize bits? #73
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.
🌱 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.
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.
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.
Activity
leofang commentedon Jun 7, 2021
We should list a few items that would be great to do if we plan to break ABI.
hpkfft commentedon Sep 11, 2026
🌱 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
bitsmember ofDLDataTypeis 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
shapearray gives the shape of the complex tensor.The
stridesarray gives the strides measured in number of real-valued-sized elements.Example A:
For DLPack,
code=kDLFloatandbits=64since components are IEEE binary64,shape={2,3}, andstrides={6,2}.NumPy measures strides in bytes; DLPack measures strides in 8B units because
bitsis 8B.Of course, the flag bit
DLPACK_FLAG_BITMASK_COMPLEX_COMPONENTSis set.Example B:
For DLPack,
code=kDLFloatandbits=64since components are IEEE binary64,shape={2,2}, andstrides={5,2}.Note that, today,
bcannot be dlpacked:but with
DLPACK_FLAG_BITMASK_COMPLEX_COMPONENTSit can be.And it ought to be dlpackable, since
alignof(std::complex<double>) == 8.Example C:
For DLPack,
code=kDLFloatandbits=128since components are IEEE binary128,shape={3}, andstrides={2}.With
DLPACK_FLAG_BITMASK_COMPLEX_COMPONENTSset,uint8_t bitsis wide enough.seberg commentedon Sep 11, 2026
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.