nanobind icon indicating copy to clipboard operation
nanobind copied to clipboard

Draft: force buffer protocol in tensor creation for `numpy` to avoid read/write constraints with `dlpack`.

Open brettc opened this issue 3 years ago • 8 comments

This PR overcomes two current limitations with tensors in nanobind when using numpy (it does not affect torch or jax).

  • returning tensors from C++ always results in read-only arrays. See #46.
  • passing read-only arrays from python results in an error. See #42.
  • [x] Allow returning writeable arrays from c++ to python.
  • [x] Allow passing read-only arrays to from python to c++.
  • [x] clean up tests.
  • [ ] Add documentation.

brettc avatar Jul 28 '22 22:07 brettc

@wjakob I've added an nb::writeable flag in tensor creation so far. Let me know if this is on track.

brettc avatar Jul 28 '22 22:07 brettc

I can confirm that nb::writeable works in my simple test cases.

qnzhou avatar Aug 03 '22 02:08 qnzhou

There is now a readonly flag that allows read-only numpy arrays to be passed through. It forces the translation through the buffer protocol, and has a static-assert guard so that it should only be combined with numpy.

Both issues are solved, but I wonder if there is a way of combining the readonly/writeable flags. I could not see how to do it as they really serve in different places. For clarity, maybe they should be accepts_readonly and returns_writeable.

brettc avatar Aug 25 '22 05:08 brettc

Based on the table below, we only need buffer protocal for 2 cases: python readonly to C++ readonly, and C++ readwrite to python readwrite.

C++ Python C++ -> Python Python -> C++
RO RO dlpack Buffer Protocol
RO RW invalid dlpack
RW RO dlpack invalid
RW RW Buffer Protocol dlpack

It will be great to use the same flag for both cases. Having both writable and readonly may leads to inconsistency settings. It may be helpful to consider writable a property of the nb::tensor obj rather than the C++ or python buffer it binds to. This may help resolve your semantic concern.

qnzhou avatar Aug 25 '22 16:08 qnzhou

Sorry, I don't understand the table -- it looks misleading. Currently nanobind throws an exception if you send it a RO buffer from python. So neither RO -> RO or RO -> RW from python -> C++ work.

Any readonly flag in C++ (at least for numpy arrays) is simply a warning to the programmer, unless we force the array to be const. Perhaps that is an option, but my c++ templating skills are already stretched!

Maybe @wjakob has some suggestions?

brettc avatar Aug 25 '22 20:08 brettc

Sorry, I don't understand the table -- it looks misleading. Currently nanobind throws an exception if you send it a RO buffer from python. So neither RO -> RO or RO -> RW from python -> C++ work.

Sorry, I should clarify the table is a summary of the data transfer technologies that (I think) can be used for transferring data under different read/write permissions. (and by python, I meant numpy array.) It is not what nanobind does currently.

In any case, I agree with you that we should combine nb::writable and nb::readonly. However, I don't fully understand your comment that "they really serve in different places". In my view, they are simply describing the read/write permission of the buffer associated with nb::tensor object regardless of whether it is from C++ to python or the other way around.

qnzhou avatar Aug 26 '22 14:08 qnzhou

Sorry for taking a long time to respond -- generally this seems like a reasonable set of changes, though it does seem somewhat specific to NumPy. A similar readonly flag is on the horizon for DLPack (https://github.com/data-apis/array-api/issues/191), so whatever this turns into will have to generalize into passing all kinds of read-only tensors made using different frameworks.

A code style comment: in nanobind, opening braces are generally merged with the previous line -- the PR deviates from this convention.

wjakob avatar Aug 30 '22 08:08 wjakob

Hi @wjakob. Thanks for the comments. I'll have a look at the DLPack changes, to try and see how they would fit.

brettc avatar Sep 08 '22 04:09 brettc

I will close this PR, I don't think it is relevant anymore with recent changes to nanobind. I am happy to reopen it if you disagree.

wjakob avatar Feb 15 '23 11:02 wjakob