-
Notifications
You must be signed in to change notification settings - Fork 2.2k
[QUESTION] Enforce array_t type and ordering #2455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Do you maybe have minimal reproducing example that I can compile, try out, and debug, @PierreMarchand20? |
Sorry, I thought the behavior was expected, so that the answer would be obvious. Here is a MWE:
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
// A=B*C
// A: N1xN2
// B: N1xN3
// C: N3xN2
void matmat_prod(py::array_t<std::complex<double>, py::array::f_style | py::array::forcecast> A, py::array_t<std::complex<double>, py::array::f_style | py::array::forcecast> B, py::array_t<std::complex<double>, py::array::f_style | py::array::forcecast> C){
if ((A.ndim()!=2 || B.ndim()!=2) || C.ndim()!=2){
throw std::invalid_argument("Wrong dimension in input");
}
int N1 = A.shape()[0];
int N2 = A.shape()[1];
int N3 = B.shape()[1];
if ((B.shape()[0]!=N1 || C.shape()[1]!=N2) || C.shape()[0]!=N3){
throw std::invalid_argument("Wrong size in input");
}
for (int i=0;i<N1;i++){
for (int j=0;j<N2;j++){
for (int k=0;k<N3;k++){
A.mutable_at(i,j)=A.at(i,j)+B.at(i,k)*C.at(k,j);
}
}
}
}
PYBIND11_MODULE(MyModule, m) {
m.def("matmat_prod",&matmat_prod);
}
import MyModule
import numpy as np
N1=10
N2=5
N3=50
A=np.zeros((N1,N2))
B=np.random.rand(N1,N3)
C=np.random.rand(N3,N2)
pybind11_openmp.matmat_prod(A,B,C)
print(A)
Atype=np.array(A,dtype="complex128")
pybind11_openmp.matmat_prod(Atype,B,C)
print(Atype)
Aorder=np.array(A,order="F")
pybind11_openmp.matmat_prod(Aorder,B,C)
print(Aorder)
Atypeorder=np.array(A,dtype="complex128",order="F")
pybind11_openmp.matmat_prod(Atypeorder,B,C)
print(Atypeorder)
|
So my question following the previous MWE is, why is there no issue giving a numpy array with the wrong type/ordering ? If I give the wrong argument to a function, usually an error is raised and the python module created using pybind11 shows me
Or, how can I throw an error in this case, to avoid bad surprises for people using this kind of function? |
@YannickJadoul I hope this MWE is "minimal" enough, do not hesitate if you need more information. |
I've just taken a look at this. I can repro, but I don't know numpy a lot. As far as I can tell, all of |
@PierreMarchand20 Sorry for the delay. I now got to testing out the code and found an obscure (probably undocumented) corner of pybind11 that I think solves your problem :-) First of all: the problem is that by passing that array, a copy is made if you're expecting a different type or contiguous data. The undocumented secret to get an error is hidden here: pybind11/include/pybind11/numpy.h Lines 984 to 1000 in cc982ac
I.e., when I write PYBIND11_MODULE(example, m) {
m.def("matmat_prod", &matmat_prod, py::arg("A").noconvert(true), py::arg("B"), py::arg("C"));
} pybind11 gives you a nice error if you don't pass exactly the right type! |
@PierreMarchand20 I've submitted a PR ;-) |
Thank you both for your answers! Happy to see it was not as trivial as I thought. Yes, I did understand that a copy was made if the type/ordering did not match, with and without the forecast option. I just checked the vector in C++ to see that I actually modified it. So once the PR is merged, I am discovering |
I let you close this issue when you want (now or when the PR is merged). Thank you for your amazing work 🙏🙏🙏🙏 I tried to interface my C++ code with ctypes before, and it feels WAY more "natural" to use pybind11 . |
You can also just accept But yes,
:-) It should be closed soon enough by the PR. Meanwhile, if you just accept |
I understand 😄 thankfully, it is pretty clean and well-documented so that I could just go through |
You can also give |
FYI, I do get an error with the wrong ordering, but the output does not explain what is the issue. It just says it expects |
@PierreMarchand20 That's true, yes, or at least what I'd expect. Not sure how that's best fixed |
@YannickJadoul I do not know if/how it should be fixed, I just wanted you to be aware of this ^^ I do not mind personally |
@PierreMarchand20 Yes, thanks! It's indeed confusing (but we'd need to somehow add the ordering to the type annotation?). |
I have a naive question about
array_t
. I have a c++ function that takes a vector and modify it so that I can use it in python thereafter. Reading the documentation, I understood that usingpy::array_t<T, py::array::f_style | py::array::forcecast>
allows converting a numpy array from Python to the typeT
and fortran ordering in c++.But then, as soon as the numpy array does not match exactly what is required (so type
T
and fortran ordering) in my C++ code (with and withoutpy::array::forcecast
), the resulting vector in python is filled with zero.So then, I would like to enforce the type and the ordering, is it possible ? It could throw an error in case the type or the error is not matching T and py::array::f_style.
I have seen some issues about this (#338 or #1305), but I did not find/understand a solution for my problem
The text was updated successfully, but these errors were encountered: