Cheapest way to get a numpy array into C-contiguous order?

前端 未结 3 1979
孤街浪徒
孤街浪徒 2021-01-01 19:09

The following produces a C-contiguous numpy array:

import numpy

a = numpy.ones((1024,1024,5))

Now if I slice it, the result may not longer

相关标签:
3条回答
  • 2021-01-01 19:50

    To force a numpy array x to be C-contiguous, without making unnecessary copies when it's already that way to begin with, you should use,

     x = numpy.asarray(x, order='C')
    

    Note, that if this array was not C-contiguous, it would probably be similar in terms of efficiency to x.copy(order='C'). I don't think there is a way around it. You can't reorganize the alignment of an array in memory otherwise than by making a copy of the data to a new location.

    Rewriting your code so it uses the sliced index first, as in numpy.ones((5,1024,1024)) seems to be the only reasonable way of optimizing this.

    0 讨论(0)
  • 2021-01-01 20:11

    As things stand, any attempt to coerce the slice bn to C contiguous order is going to create a copy.

    If you don't want to change the shapes you're starting with (and don't need a itself in C order), one possible solution is to start with the array a in Fortran order:

    >>> a = numpy.ones((1024, 1024, 5), order='f')
    

    The slices are also then F-contiguous:

    >>> bn = a[:, :, 0]
    >>> bn.flags
      C_CONTIGUOUS : False
      F_CONTIGUOUS : True
      OWNDATA : False
      ...
    

    This means that the transpose of the slice bn will be in C order and transposing does not create a copy:

    >>> bn.T.flags
      C_CONTIGUOUS : True
      F_CONTIGUOUS : False
      OWNDATA : False
      ...
    

    And you can then hash the slice:

    >>> hashlib.sha1(bn.T).hexdigest()
    '01dfa447dafe16b9a2972ce05c79410e6a96840e'
    
    0 讨论(0)
  • 2021-01-01 20:12

    This is a standard operation when interfacing numpy with C. Have a look at numpy.ascontiguousarray

    x=numpy.ascontiguousarray(x)

    is the proper way of dealing with it.

    Use numpy.asfortranarray if you need fortran order.

    As mentioned the function will copy if necessary. So there is no way around it. You can try rollaxis before your operation, such that the short axis is the first axis. This gives you a view on the array

    In [2]: A=np.random.rand(1024,1024,5)
    In [3]: B=np.rollaxis(A,2)
    In [4]: B.shape
    Out[4]: (5, 1024, 1024)
    In [5]: B.flags
    Out[5]:
      C_CONTIGUOUS : False
      F_CONTIGUOUS : False
      OWNDATA : False
      WRITEABLE : True
      ALIGNED : True
      UPDATEIFCOPY : False
    
    In [6]: A.flags
    Out[6]:
      C_CONTIGUOUS : True
      F_CONTIGUOUS : False
      OWNDATA : True
      WRITEABLE : True
      ALIGNED : True
      UPDATEIFCOPY : False
    

    So rollaxis does not solve this either.

    0 讨论(0)
提交回复
热议问题