NumPy BufferError – memoryview: underlying buffer is not C-contiguous

Updated: January 23, 2024 By: Guest Contributor Post a comment

Understanding the BufferError in NumPy

When working with NumPy, you may encounter a BufferError that indicates the underlying buffer of an ndarray is not C-contiguous. This usually happens when a function expects an input array to have a certain memory layout, specifically C-contiguity, which means that the multi-dimensional array is stored in an unbroken block of memory in the order of the last index changing fastest (C-style).

This issue can arise when working with functions from the Python Standard Library that require a buffer, like memoryview, or other libraries that interface with C or Fortran code.

Solution 1: Use NumPy’s numpy.ascontiguousarray

This function converts an input array to a contiguous array in memory, if it’s not already. This is a simple and convenient way to resolve the BufferError caused by non-contiguous memory blocks.

  • Create a contiguous version of the array using ascontiguousarray.
  • Use the contiguous array as input for operations that require C-contiguous memory.

Example:

import numpy as np

# Non-contiguous array
demo_array = np.arange(10)[::2]  # Slicing creates a non-contiguous array

# Make the array C-contiguous
contiguous_array = np.ascontiguousarray(demo_array)

# The memoryview should now work without issues data_view = memoryview(contiguous_array)

Notes: This solution is quick and works for most cases. However, it does involve creating a new copy of the array in memory, which might be an issue for very large arrays due to increased memory usage.

Solution 2: Reshape the array to be contiguous

Reshaping an array can also make it C-contiguous, as a reshape operation returns a new array with a new shape but the same data laid out contiguously in memory if possible.

  • If the array can be reshaped without copying data, reshape it.
  • If not, use copy() to explicitly create a contiguous copy.
import numpy as np

demo_array = np.arange(15).reshape(3, 5)[::2, :]
try:
    contiguous_array = demo_array.reshape(-1)  # Attempt to reshape
except ValueError:
    contiguous_array = demo_array.copy()  # Fallback to copying

data_view = memoryview(contiguous_array)

Notes: Reshape is efficient but may not always be possible without copying data. The fallback copy increases the memory footprint.

Solution 3: Utilize array’s order parameter

While creating an array, you can use the order='C' parameter to ensure C-contiguity upfront if you know the operation will require it later on.

When creating a new array using functions like np.array(), include the order='C' argument:

import numpy as np

# Creating a C-contiguous array from a list
list_of_lists = [list(range(5)), list(range(5, 10))]
contiguous_array = np.array(list_of_lists, order='C')
 memoryview(contiguous_array)

Notes: This practice optimizes array creation from the start and avoids having to fix the issue later. However, it is only applicable when creating new arrays and not when working with existing ones.