2

This question has info on using an input as an output to compute something in place with a numpy.ufunc:

Is it possible to avoid allocating space for an unwanted output of a numpy.ufunc? For example, say I only want one of the two outputs from modf. Can I ensure that the other, unwanted array is never allocated at all?

I thought passing _ to out might do it, but it throws an error:

import numpy as np
ar = np.arange(6)/3
np.modf(ar, out=(ar, _))    

TypeError: return arrays must be of ArrayType

As it says in the docs, passing None means that the output array is allocated in the function and returned. I can ignore the returned values, but it still has to be allocated and populated inside the function.

Paul T.
  • 326
  • 1
  • 2
  • 11
  • 1
    Why worry about this? There aren't many `ufunc` that return more than one array. How about using `np.remainder(arr, 1)` instead? – hpaulj Nov 15 '18 at 23:21
  • This was more of a question about the limits of `ufunc` than a particular use case. My additional reading is making me pretty sure it cannot be done. – Paul T. Nov 16 '18 at 00:29

1 Answers1

4

You can minimize allocation by passing a "fake" array:

ar = np.arange(6) / 3
np.modf(ar, ar, np.broadcast_arrays(ar.dtype.type(0), ar)[0])

This dummy array is as big as a single double, and modf will not do allocation internally.

EDIT According to suggestions from @Eric and @hpaulj, a more general and long-term solution would be

np.lib.stride_tricks._broadcast_to(np.empty(1, ar.dtype), ar.shape, False, False)
ZisIsNotZis
  • 1,570
  • 1
  • 13
  • 30
  • 1
    `np.broadcast_to(np.empty((), dtype), shape)` is a more general pattern, which works on non-numeric arrays too. – Eric Nov 16 '18 at 06:56
  • `np.modf(ar, out=(ar, np.broadcast_to(np.empty((), ar.dtype), ar.shape)))` does not work because the second output is read only – Paul T. Nov 16 '18 at 15:48
  • This is neat! The second output is still an array of the right length, but all elements point to the same location in memory. – Paul T. Nov 16 '18 at 15:57
  • 2
    Both `broadcast_to` and `broadcast_arrays` use `np.lib.stride_tricks._broadcast_to`. One uses a `readonly=True` parameter, the other sets it to `False`. But there's a TODO comment in the code about changing it to `readonly`, so in the long term this answer may need modification. It's interesting that the underlying tool in all of this is `nditer`. – hpaulj Nov 17 '18 at 05:35