summaryrefslogtreecommitdiff
path: root/ext/pybind11/tests/test_numpy_array.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pybind11/tests/test_numpy_array.cpp')
-rw-r--r--ext/pybind11/tests/test_numpy_array.cpp114
1 files changed, 114 insertions, 0 deletions
diff --git a/ext/pybind11/tests/test_numpy_array.cpp b/ext/pybind11/tests/test_numpy_array.cpp
index 14c4c2999..cd6487249 100644
--- a/ext/pybind11/tests/test_numpy_array.cpp
+++ b/ext/pybind11/tests/test_numpy_array.cpp
@@ -17,6 +17,7 @@
using arr = py::array;
using arr_t = py::array_t<uint16_t, 0>;
+static_assert(std::is_same<arr_t::value_type, uint16_t>::value, "");
template<typename... Ix> arr data(const arr& a, Ix... index) {
return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...));
@@ -67,6 +68,21 @@ template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(
sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \
sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); });
+template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
+ if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
+ py::list l;
+ l.append(*r.data(0, 0));
+ l.append(*r2.mutable_data(0, 0));
+ l.append(r.data(0, 1) == r2.mutable_data(0, 1));
+ l.append(r.ndim());
+ l.append(r.itemsize());
+ l.append(r.shape(0));
+ l.append(r.shape(1));
+ l.append(r.size());
+ l.append(r.nbytes());
+ return l.release();
+}
+
test_initializer numpy_array([](py::module &m) {
auto sm = m.def_submodule("array");
@@ -150,4 +166,102 @@ test_initializer numpy_array([](py::module &m) {
"array_t<double>"_a=py::array_t<double>(o)
);
});
+
+ // Overload resolution tests:
+ sm.def("overloaded", [](py::array_t<double>) { return "double"; });
+ sm.def("overloaded", [](py::array_t<float>) { return "float"; });
+ sm.def("overloaded", [](py::array_t<int>) { return "int"; });
+ sm.def("overloaded", [](py::array_t<unsigned short>) { return "unsigned short"; });
+ sm.def("overloaded", [](py::array_t<long long>) { return "long long"; });
+ sm.def("overloaded", [](py::array_t<std::complex<double>>) { return "double complex"; });
+ sm.def("overloaded", [](py::array_t<std::complex<float>>) { return "float complex"; });
+
+ sm.def("overloaded2", [](py::array_t<std::complex<double>>) { return "double complex"; });
+ sm.def("overloaded2", [](py::array_t<double>) { return "double"; });
+ sm.def("overloaded2", [](py::array_t<std::complex<float>>) { return "float complex"; });
+ sm.def("overloaded2", [](py::array_t<float>) { return "float"; });
+
+ // Only accept the exact types:
+ sm.def("overloaded3", [](py::array_t<int>) { return "int"; }, py::arg().noconvert());
+ sm.def("overloaded3", [](py::array_t<double>) { return "double"; }, py::arg().noconvert());
+
+ // Make sure we don't do unsafe coercion (e.g. float to int) when not using forcecast, but
+ // rather that float gets converted via the safe (conversion to double) overload:
+ sm.def("overloaded4", [](py::array_t<long long, 0>) { return "long long"; });
+ sm.def("overloaded4", [](py::array_t<double, 0>) { return "double"; });
+
+ // But we do allow conversion to int if forcecast is enabled (but only if no overload matches
+ // without conversion)
+ sm.def("overloaded5", [](py::array_t<unsigned int>) { return "unsigned int"; });
+ sm.def("overloaded5", [](py::array_t<double>) { return "double"; });
+
+ // Issue 685: ndarray shouldn't go to std::string overload
+ sm.def("issue685", [](std::string) { return "string"; });
+ sm.def("issue685", [](py::array) { return "array"; });
+ sm.def("issue685", [](py::object) { return "other"; });
+
+ sm.def("proxy_add2", [](py::array_t<double> a, double v) {
+ auto r = a.mutable_unchecked<2>();
+ for (size_t i = 0; i < r.shape(0); i++)
+ for (size_t j = 0; j < r.shape(1); j++)
+ r(i, j) += v;
+ }, py::arg().noconvert(), py::arg());
+
+ sm.def("proxy_init3", [](double start) {
+ py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
+ auto r = a.mutable_unchecked<3>();
+ for (size_t i = 0; i < r.shape(0); i++)
+ for (size_t j = 0; j < r.shape(1); j++)
+ for (size_t k = 0; k < r.shape(2); k++)
+ r(i, j, k) = start++;
+ return a;
+ });
+ sm.def("proxy_init3F", [](double start) {
+ py::array_t<double, py::array::f_style> a({ 3, 3, 3 });
+ auto r = a.mutable_unchecked<3>();
+ for (size_t k = 0; k < r.shape(2); k++)
+ for (size_t j = 0; j < r.shape(1); j++)
+ for (size_t i = 0; i < r.shape(0); i++)
+ r(i, j, k) = start++;
+ return a;
+ });
+ sm.def("proxy_squared_L2_norm", [](py::array_t<double> a) {
+ auto r = a.unchecked<1>();
+ double sumsq = 0;
+ for (size_t i = 0; i < r.shape(0); i++)
+ sumsq += r[i] * r(i); // Either notation works for a 1D array
+ return sumsq;
+ });
+
+ sm.def("proxy_auxiliaries2", [](py::array_t<double> a) {
+ auto r = a.unchecked<2>();
+ auto r2 = a.mutable_unchecked<2>();
+ return auxiliaries(r, r2);
+ });
+
+ // Same as the above, but without a compile-time dimensions specification:
+ sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
+ auto r = a.mutable_unchecked();
+ if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
+ for (size_t i = 0; i < r.shape(0); i++)
+ for (size_t j = 0; j < r.shape(1); j++)
+ r(i, j) += v;
+ }, py::arg().noconvert(), py::arg());
+ sm.def("proxy_init3_dyn", [](double start) {
+ py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
+ auto r = a.mutable_unchecked();
+ if (r.ndim() != 3) throw std::domain_error("error: ndim != 3");
+ for (size_t i = 0; i < r.shape(0); i++)
+ for (size_t j = 0; j < r.shape(1); j++)
+ for (size_t k = 0; k < r.shape(2); k++)
+ r(i, j, k) = start++;
+ return a;
+ });
+ sm.def("proxy_auxiliaries2_dyn", [](py::array_t<double> a) {
+ return auxiliaries(a.unchecked(), a.mutable_unchecked());
+ });
+
+ sm.def("array_auxiliaries2", [](py::array_t<double> a) {
+ return auxiliaries(a, a);
+ });
});