[Numpy-discussion] Fast clip for native types, 2d version

David Cournapeau david at ar.media.kyoto-u.ac.jp
Sun Jan 14 05:30:40 EST 2007


Hi,

   First, I wanted to thank everybody who helped me to clarify many 
points concerning memory layout of numpy arrays; I think I have a much 
clearer idea of the way numpy arrays behave at the C level.
   I've used all those informations to correct my initial implementation 
of clip to improve the clip function for common cases: it speeds up 
things only for native endianness, and scalar min and max (both 
contiguous and non contiguous cases).
  
    I've attached the new version code (only for one type to avoid too 
big emails; you have to dl the archive to actually compile the 
implementation); the whole package with tests + profiling script is there:

    http://www.ar.media.kyoto-u.ac.jp/members/david/archives/fastclip.tgz

    If this looks Ok, I will prepare a patch against current numpy, with 
the C sources being generated by numpy.distutils instead of the tool I 
am using now (autogen)

    Now, to improve other cases (mainly implementing an in-place clip 
function + non scalar min/max), there are some clarifications needed, 
mainly related to broadcast rules the current clip implementation which 
seems to break numpy conventions:

   1: the old implementation returns an array which has the same 
endianness than the input array. This is a bit odd, because when the 
input is byte swapped, the returned array is still byte swapped, which 
seems to be against numpy convention. Here is some code which seem odd 
to me (code assumes little endian machine)

a = numpy.random.randn(3, 2)
b = a.astype(a.dtype.newbyteorder('>'))
c = b.copy()
assert a.dtype.isnative
assert not b.dtype.isnative
assert not c.dtype.isnative
# Endianness behaviour of basic operation with numpy arrays
print (a + b).dtype.isnative #one arg is non native -> returns native
print (b + c).dtype.isnative # both args not native -> returns native
# Now, what's happening endian-wise with clip:
print numpy.clip(a, -0.5, 0.5).dtype.isnative # everything native -> 
returns native
print numpy.clip(b, -0.5, 0.5).dtype.isnative # input array non native 
-> returns non native
print numpy.clip(b, a, 0.5).dtype.isnative    # input array non native, 
native array min -> returns native

    The fact that the output's endianness depends on min/max arguments 
being arrays or not does not seem really coherent ?

   2: the old implementation does not upcast the input array. If the 
input is int32, and min/max are float32, the function fails; if input is 
float32, and min/max float64, the output is still float32. Again, this 
seems against the expected numpy behaviour ?
   3: the old implementation supports clipping with complex arrays. I 
don't see any obvious meaningful implementation of clipping in those 
cases (using the module to compare them ?)

   If breaking those oddities is allowed, this would make the 
improvements much simpler to code,

   cheers,

   David
-------------- next part --------------
A non-text attachment was scrubbed...
Name: fast_clip.c
Type: text/x-csrc
Size: 8695 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20070114/08505f05/attachment.c>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: clip_imp.c
Type: text/x-csrc
Size: 3509 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20070114/08505f05/attachment-0001.c>


More information about the NumPy-Discussion mailing list