v923z/micropython-ulab

[BUG] Operations on uint8 don't respect upcasting rules

s-ol opened this issue · 1 comments

s-ol commented

The documentation clearly states:

ulab observes the following upcasting rules:

  1. Operations on two ndarrays of the same dtype preserve their dtype, even when the results overflow.
  2. ...

However the implementation does not respect this rule for uint8 types, which are upcast to uint16 regardless:

To Reproduce

>>> import ulab.numpy as np
>>> x = np.array([1, 2], dtype=np.uint8)
>>> x + x
array([2, 4], dtype=uint16)

Expected behavior
The result should have a uint8 dtype.

Additional context
Since this problem only regards the uint8 dtype and seems to be implemented rather consistently in this way it seems likely that this was an intentional choice at some point. However it is completely undocumented and I don't understand the rationale behind it.

The current behaviour means if the user wants to remain in "uint8-space", that is not possible at all, even using explicit casting. If the implementation were changed to match the docs however, users could explicitly cast one argument to uint16 to obtain the wanted result if needed, without breaking the other use case.

This is related to but separate from #396, which was partially solved by changing the 'downcasting' implementation for scalar arguments in #398. However adding a small integer constant to an u8 array still results in an u16 result due to this upcasting exception.

s-ol commented

Note that numpy implements upcasting as per current ulab docs as well:

>>> import numpy as np
>>> np.array([1,2,3], dtype=np.uint8)
array([1, 2, 3], dtype=uint8)
>>> x = np.array([1,2,3], dtype=np.uint8)
>>> x + x
array([2, 4, 6], dtype=uint8)