mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
Now shape
, size
, ndims
and itemsize
are also signed integers.
This commit is contained in:
parent
b68959e822
commit
30d43c4992
@ -57,10 +57,10 @@ specification.
|
|||||||
|
|
||||||
struct buffer_info {
|
struct buffer_info {
|
||||||
void *ptr;
|
void *ptr;
|
||||||
size_t itemsize;
|
ssize_t itemsize;
|
||||||
std::string format;
|
std::string format;
|
||||||
int ndim;
|
ssize_t ndim;
|
||||||
std::vector<size_t> shape;
|
std::vector<ssize_t> shape;
|
||||||
std::vector<ssize_t> strides;
|
std::vector<ssize_t> strides;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,8 +95,8 @@ buffer objects (e.g. a NumPy matrix).
|
|||||||
throw std::runtime_error("Incompatible buffer dimension!");
|
throw std::runtime_error("Incompatible buffer dimension!");
|
||||||
|
|
||||||
auto strides = Strides(
|
auto strides = Strides(
|
||||||
info.strides[rowMajor ? 0 : 1] / sizeof(Scalar),
|
info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar),
|
||||||
info.strides[rowMajor ? 1 : 0] / sizeof(Scalar));
|
info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar));
|
||||||
|
|
||||||
auto map = Eigen::Map<Matrix, 0, Strides>(
|
auto map = Eigen::Map<Matrix, 0, Strides>(
|
||||||
static_cat<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides);
|
static_cat<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides);
|
||||||
@ -111,17 +111,14 @@ as follows:
|
|||||||
|
|
||||||
.def_buffer([](Matrix &m) -> py::buffer_info {
|
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||||
return py::buffer_info(
|
return py::buffer_info(
|
||||||
m.data(), /* Pointer to buffer */
|
m.data(), /* Pointer to buffer */
|
||||||
sizeof(Scalar), /* Size of one scalar */
|
sizeof(Scalar), /* Size of one scalar */
|
||||||
/* Python struct-style format descriptor */
|
py::format_descriptor<Scalar>::format(), /* Python struct-style format descriptor */
|
||||||
py::format_descriptor<Scalar>::format(),
|
2, /* Number of dimensions */
|
||||||
/* Number of dimensions */
|
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||||
2,
|
|
||||||
/* Buffer dimensions */
|
|
||||||
{ m.rows(), m.cols() },
|
|
||||||
/* Strides (in bytes) for each index */
|
|
||||||
{ sizeof(Scalar) * (rowMajor ? m.cols() : 1),
|
{ sizeof(Scalar) * (rowMajor ? m.cols() : 1),
|
||||||
sizeof(Scalar) * (rowMajor ? 1 : m.rows()) }
|
sizeof(Scalar) * (rowMajor ? 1 : m.rows()) }
|
||||||
|
/* Strides (in bytes) for each index */
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -321,17 +318,17 @@ where ``N`` gives the required dimensionality of the array:
|
|||||||
m.def("sum_3d", [](py::array_t<double> x) {
|
m.def("sum_3d", [](py::array_t<double> x) {
|
||||||
auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable
|
auto r = x.unchecked<3>(); // x must have ndim = 3; can be non-writeable
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
for (size_t k = 0; k < r.shape(2); k++)
|
for (ssize_t k = 0; k < r.shape(2); k++)
|
||||||
sum += r(i, j, k);
|
sum += r(i, j, k);
|
||||||
return sum;
|
return sum;
|
||||||
});
|
});
|
||||||
m.def("increment_3d", [](py::array_t<double> x) {
|
m.def("increment_3d", [](py::array_t<double> x) {
|
||||||
auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false
|
auto r = x.mutable_unchecked<3>(); // Will throw if ndim != 3 or flags.writeable is false
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
for (size_t k = 0; k < r.shape(2); k++)
|
for (ssize_t k = 0; k < r.shape(2); k++)
|
||||||
r(i, j, k) += 1.0;
|
r(i, j, k) += 1.0;
|
||||||
}, py::arg().noconvert());
|
}, py::arg().noconvert());
|
||||||
|
|
||||||
|
@ -15,31 +15,31 @@ NAMESPACE_BEGIN(pybind11)
|
|||||||
|
|
||||||
/// Information record describing a Python buffer object
|
/// Information record describing a Python buffer object
|
||||||
struct buffer_info {
|
struct buffer_info {
|
||||||
void *ptr = nullptr; // Pointer to the underlying storage
|
void *ptr = nullptr; // Pointer to the underlying storage
|
||||||
size_t itemsize = 0; // Size of individual items in bytes
|
ssize_t itemsize = 0; // Size of individual items in bytes
|
||||||
size_t size = 0; // Total number of entries
|
ssize_t size = 0; // Total number of entries
|
||||||
std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::format()
|
std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::format()
|
||||||
size_t ndim = 0; // Number of dimensions
|
ssize_t ndim = 0; // Number of dimensions
|
||||||
std::vector<size_t> shape; // Shape of the tensor (1 entry per dimension)
|
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
||||||
std::vector<ssize_t> strides; // Number of entries between adjacent entries (for each per dimension)
|
std::vector<ssize_t> strides; // Number of entries between adjacent entries (for each per dimension)
|
||||||
|
|
||||||
buffer_info() { }
|
buffer_info() { }
|
||||||
|
|
||||||
buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t ndim,
|
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
||||||
detail::any_container<size_t> shape_in, detail::any_container<ssize_t> strides_in)
|
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
|
||||||
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
||||||
shape(std::move(shape_in)), strides(std::move(strides_in)) {
|
shape(std::move(shape_in)), strides(std::move(strides_in)) {
|
||||||
if (ndim != shape.size() || ndim != strides.size())
|
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size())
|
||||||
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
||||||
for (size_t i = 0; i < ndim; ++i)
|
for (size_t i = 0; i < (size_t) ndim; ++i)
|
||||||
size *= shape[i];
|
size *= shape[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_info(void *ptr, size_t itemsize, const std::string &format, size_t size)
|
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size)
|
||||||
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { }
|
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { }
|
||||||
|
|
||||||
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
||||||
: buffer_info(view->buf, (size_t) view->itemsize, view->format, (size_t) view->ndim,
|
: buffer_info(view->buf, view->itemsize, view->format, view->ndim,
|
||||||
{view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) {
|
{view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) {
|
||||||
this->view = view;
|
this->view = view;
|
||||||
this->ownview = ownview;
|
this->ownview = ownview;
|
||||||
@ -78,13 +78,13 @@ NAMESPACE_BEGIN(detail)
|
|||||||
|
|
||||||
template <typename T, typename SFINAE = void> struct compare_buffer_info {
|
template <typename T, typename SFINAE = void> struct compare_buffer_info {
|
||||||
static bool compare(const buffer_info& b) {
|
static bool compare(const buffer_info& b) {
|
||||||
return b.format == format_descriptor<T>::format() && b.itemsize == sizeof(T);
|
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
||||||
static bool compare(const buffer_info& b) {
|
static bool compare(const buffer_info& b) {
|
||||||
return b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
|
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
|
||||||
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
|
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
|
||||||
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
||||||
}
|
}
|
||||||
|
@ -433,7 +433,7 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
|||||||
#endif
|
#endif
|
||||||
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||||
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
||||||
type->tp_basicsize += (Py_ssize_t)sizeof(PyObject *); // and allocate enough space for it
|
type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it
|
||||||
type->tp_traverse = pybind11_traverse;
|
type->tp_traverse = pybind11_traverse;
|
||||||
type->tp_clear = pybind11_clear;
|
type->tp_clear = pybind11_clear;
|
||||||
|
|
||||||
@ -459,18 +459,16 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
|
|||||||
view->ndim = 1;
|
view->ndim = 1;
|
||||||
view->internal = info;
|
view->internal = info;
|
||||||
view->buf = info->ptr;
|
view->buf = info->ptr;
|
||||||
view->itemsize = (Py_ssize_t) info->itemsize;
|
view->itemsize = info->itemsize;
|
||||||
view->len = view->itemsize;
|
view->len = view->itemsize;
|
||||||
for (auto s : info->shape)
|
for (auto s : info->shape)
|
||||||
view->len *= (Py_ssize_t) s;
|
view->len *= s;
|
||||||
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
||||||
view->format = const_cast<char *>(info->format.c_str());
|
view->format = const_cast<char *>(info->format.c_str());
|
||||||
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
|
||||||
view->ndim = (int) info->ndim;
|
view->ndim = (int) info->ndim;
|
||||||
view->strides = &info->strides[0];
|
view->strides = &info->strides[0];
|
||||||
// Next is a pointer cast, let's make sure it's safe.
|
view->shape = &info->shape[0];
|
||||||
static_assert(sizeof(Py_ssize_t)==sizeof(info->shape[0]), "sizeof(Py_ssize_t) != sizeof(size_t)");
|
|
||||||
view->shape = (Py_ssize_t *) &info->shape[0];
|
|
||||||
}
|
}
|
||||||
Py_INCREF(view->obj);
|
Py_INCREF(view->obj);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -68,7 +68,7 @@ template <typename T> using is_eigen_other = all_of<
|
|||||||
template <bool EigenRowMajor> struct EigenConformable {
|
template <bool EigenRowMajor> struct EigenConformable {
|
||||||
bool conformable = false;
|
bool conformable = false;
|
||||||
EigenIndex rows = 0, cols = 0;
|
EigenIndex rows = 0, cols = 0;
|
||||||
EigenDStride stride{0, 0}; // Only valid if negativestridees is false!
|
EigenDStride stride{0, 0}; // Only valid if negativestrides is false!
|
||||||
bool negativestrides = false; // If true, do not use stride!
|
bool negativestrides = false; // If true, do not use stride!
|
||||||
|
|
||||||
EigenConformable(bool fits = false) : conformable{fits} {}
|
EigenConformable(bool fits = false) : conformable{fits} {}
|
||||||
@ -207,7 +207,7 @@ template <typename Type_> struct EigenProps {
|
|||||||
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
|
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
|
||||||
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
|
// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
|
||||||
template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
|
template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
|
||||||
constexpr size_t elem_size = sizeof(typename props::Scalar);
|
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
|
||||||
array a;
|
array a;
|
||||||
if (props::vector)
|
if (props::vector)
|
||||||
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
|
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
|
||||||
@ -581,9 +581,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||||||
object matrix_type = module::import("scipy.sparse").attr(
|
object matrix_type = module::import("scipy.sparse").attr(
|
||||||
rowMajor ? "csr_matrix" : "csc_matrix");
|
rowMajor ? "csr_matrix" : "csc_matrix");
|
||||||
|
|
||||||
array data((size_t) src.nonZeros(), src.valuePtr());
|
array data(src.nonZeros(), src.valuePtr());
|
||||||
array outerIndices((size_t) (rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
|
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
|
||||||
array innerIndices((size_t) src.nonZeros(), src.innerIndexPtr());
|
array innerIndices(src.nonZeros(), src.innerIndexPtr());
|
||||||
|
|
||||||
return matrix_type(
|
return matrix_type(
|
||||||
std::make_tuple(data, innerIndices, outerIndices),
|
std::make_tuple(data, innerIndices, outerIndices),
|
||||||
|
@ -251,10 +251,10 @@ template <typename T> using is_pod_struct = all_of<
|
|||||||
satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
|
satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
template <size_t Dim = 0, typename Strides> ssize_t byte_offset_unsafe(const Strides &) { return 0; }
|
template <ssize_t Dim = 0, typename Strides> ssize_t byte_offset_unsafe(const Strides &) { return 0; }
|
||||||
template <size_t Dim = 0, typename Strides, typename... Ix>
|
template <ssize_t Dim = 0, typename Strides, typename... Ix>
|
||||||
ssize_t byte_offset_unsafe(const Strides &strides, size_t i, Ix... index) {
|
ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) {
|
||||||
return static_cast<ssize_t>(i) * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
|
return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Proxy class providing unsafe, unchecked const access to array data. This is constructed through
|
/** Proxy class providing unsafe, unchecked const access to array data. This is constructed through
|
||||||
@ -268,23 +268,23 @@ protected:
|
|||||||
const unsigned char *data_;
|
const unsigned char *data_;
|
||||||
// Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
|
// Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
|
||||||
// make large performance gains on big, nested loops, but requires compile-time dimensions
|
// make large performance gains on big, nested loops, but requires compile-time dimensions
|
||||||
conditional_t<Dynamic, const size_t *, std::array<size_t, (size_t) Dims>> shape_;
|
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>>
|
||||||
conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>> strides_;
|
shape_, strides_;
|
||||||
const size_t dims_;
|
const ssize_t dims_;
|
||||||
|
|
||||||
friend class pybind11::array;
|
friend class pybind11::array;
|
||||||
// Constructor for compile-time dimensions:
|
// Constructor for compile-time dimensions:
|
||||||
template <bool Dyn = Dynamic>
|
template <bool Dyn = Dynamic>
|
||||||
unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t<!Dyn, size_t>)
|
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<!Dyn, ssize_t>)
|
||||||
: data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
|
: data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
|
||||||
for (size_t i = 0; i < dims_; i++) {
|
for (size_t i = 0; i < (size_t) dims_; i++) {
|
||||||
shape_[i] = shape[i];
|
shape_[i] = shape[i];
|
||||||
strides_[i] = strides[i];
|
strides_[i] = strides[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Constructor for runtime dimensions:
|
// Constructor for runtime dimensions:
|
||||||
template <bool Dyn = Dynamic>
|
template <bool Dyn = Dynamic>
|
||||||
unchecked_reference(const void *data, const size_t *shape, const ssize_t *strides, enable_if_t<Dyn, size_t> dims)
|
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<Dyn, ssize_t> dims)
|
||||||
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
|
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -295,39 +295,39 @@ public:
|
|||||||
template <typename... Ix> const T &operator()(Ix... index) const {
|
template <typename... Ix> const T &operator()(Ix... index) const {
|
||||||
static_assert(sizeof...(Ix) == Dims || Dynamic,
|
static_assert(sizeof...(Ix) == Dims || Dynamic,
|
||||||
"Invalid number of indices for unchecked array reference");
|
"Invalid number of indices for unchecked array reference");
|
||||||
return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, size_t(index)...));
|
return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, ssize_t(index)...));
|
||||||
}
|
}
|
||||||
/** Unchecked const reference access to data; this operator only participates if the reference
|
/** Unchecked const reference access to data; this operator only participates if the reference
|
||||||
* is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
|
* is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
|
||||||
*/
|
*/
|
||||||
template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
||||||
const T &operator[](size_t index) const { return operator()(index); }
|
const T &operator[](ssize_t index) const { return operator()(index); }
|
||||||
|
|
||||||
/// Pointer access to the data at the given indices.
|
/// Pointer access to the data at the given indices.
|
||||||
template <typename... Ix> const T *data(Ix... ix) const { return &operator()(size_t(ix)...); }
|
template <typename... Ix> const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); }
|
||||||
|
|
||||||
/// Returns the item size, i.e. sizeof(T)
|
/// Returns the item size, i.e. sizeof(T)
|
||||||
constexpr static size_t itemsize() { return sizeof(T); }
|
constexpr static ssize_t itemsize() { return sizeof(T); }
|
||||||
|
|
||||||
/// Returns the shape (i.e. size) of dimension `dim`
|
/// Returns the shape (i.e. size) of dimension `dim`
|
||||||
size_t shape(size_t dim) const { return shape_[dim]; }
|
ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; }
|
||||||
|
|
||||||
/// Returns the number of dimensions of the array
|
/// Returns the number of dimensions of the array
|
||||||
size_t ndim() const { return dims_; }
|
ssize_t ndim() const { return dims_; }
|
||||||
|
|
||||||
/// Returns the total number of elements in the referenced array, i.e. the product of the shapes
|
/// Returns the total number of elements in the referenced array, i.e. the product of the shapes
|
||||||
template <bool Dyn = Dynamic>
|
template <bool Dyn = Dynamic>
|
||||||
enable_if_t<!Dyn, size_t> size() const {
|
enable_if_t<!Dyn, ssize_t> size() const {
|
||||||
return std::accumulate(shape_.begin(), shape_.end(), (size_t) 1, std::multiplies<size_t>());
|
return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());
|
||||||
}
|
}
|
||||||
template <bool Dyn = Dynamic>
|
template <bool Dyn = Dynamic>
|
||||||
enable_if_t<Dyn, size_t> size() const {
|
enable_if_t<Dyn, ssize_t> size() const {
|
||||||
return std::accumulate(shape_, shape_ + ndim(), (size_t) 1, std::multiplies<size_t>());
|
return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the total number of bytes used by the referenced data. Note that the actual span in
|
/// Returns the total number of bytes used by the referenced data. Note that the actual span in
|
||||||
/// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice).
|
/// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice).
|
||||||
size_t nbytes() const {
|
ssize_t nbytes() const {
|
||||||
return size() * itemsize();
|
return size() * itemsize();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -349,11 +349,11 @@ public:
|
|||||||
* reference is to a 1-dimensional array (or has runtime dimensions). When present, this is
|
* reference is to a 1-dimensional array (or has runtime dimensions). When present, this is
|
||||||
* exactly equivalent to `obj(index)`.
|
* exactly equivalent to `obj(index)`.
|
||||||
*/
|
*/
|
||||||
template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
||||||
T &operator[](size_t index) { return operator()(index); }
|
T &operator[](ssize_t index) { return operator()(index); }
|
||||||
|
|
||||||
/// Mutable pointer access to the data at the given indices.
|
/// Mutable pointer access to the data at the given indices.
|
||||||
template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(size_t(ix)...); }
|
template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, ssize_t Dim>
|
template <typename T, ssize_t Dim>
|
||||||
@ -381,7 +381,7 @@ public:
|
|||||||
|
|
||||||
dtype(const char *format) : dtype(std::string(format)) { }
|
dtype(const char *format) : dtype(std::string(format)) { }
|
||||||
|
|
||||||
dtype(list names, list formats, list offsets, size_t itemsize) {
|
dtype(list names, list formats, list offsets, ssize_t itemsize) {
|
||||||
dict args;
|
dict args;
|
||||||
args["names"] = names;
|
args["names"] = names;
|
||||||
args["formats"] = formats;
|
args["formats"] = formats;
|
||||||
@ -404,8 +404,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Size of the data type in bytes.
|
/// Size of the data type in bytes.
|
||||||
size_t itemsize() const {
|
ssize_t itemsize() const {
|
||||||
return (size_t) detail::array_descriptor_proxy(m_ptr)->elsize;
|
return detail::array_descriptor_proxy(m_ptr)->elsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true for structured data types.
|
/// Returns true for structured data types.
|
||||||
@ -425,7 +425,7 @@ private:
|
|||||||
return reinterpret_borrow<object>(obj);
|
return reinterpret_borrow<object>(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
dtype strip_padding(size_t itemsize) {
|
dtype strip_padding(ssize_t itemsize) {
|
||||||
// Recursively strip all void fields with empty names that are generated for
|
// Recursively strip all void fields with empty names that are generated for
|
||||||
// padding fields (as of NumPy v1.11).
|
// padding fields (as of NumPy v1.11).
|
||||||
if (!has_fields())
|
if (!has_fields())
|
||||||
@ -501,7 +501,7 @@ public:
|
|||||||
api.PyArray_Type_, descr.release().ptr(), (int) ndim, shape->data(), strides->data(),
|
api.PyArray_Type_, descr.release().ptr(), (int) ndim, shape->data(), strides->data(),
|
||||||
const_cast<void *>(ptr), flags, nullptr));
|
const_cast<void *>(ptr), flags, nullptr));
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
pybind11_fail("NumPy: unable to create array!");
|
throw error_already_set();
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
if (base) {
|
if (base) {
|
||||||
api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
|
api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
|
||||||
@ -528,7 +528,7 @@ public:
|
|||||||
: array(std::move(shape), {}, ptr, base) { }
|
: array(std::move(shape), {}, ptr, base) { }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
explicit array(size_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { }
|
explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { }
|
||||||
|
|
||||||
explicit array(const buffer_info &info)
|
explicit array(const buffer_info &info)
|
||||||
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { }
|
: array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { }
|
||||||
@ -539,23 +539,23 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Total number of elements
|
/// Total number of elements
|
||||||
size_t size() const {
|
ssize_t size() const {
|
||||||
return std::accumulate(shape(), shape() + ndim(), (size_t) 1, std::multiplies<size_t>());
|
return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Byte size of a single element
|
/// Byte size of a single element
|
||||||
size_t itemsize() const {
|
ssize_t itemsize() const {
|
||||||
return (size_t) detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
|
return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Total number of bytes
|
/// Total number of bytes
|
||||||
size_t nbytes() const {
|
ssize_t nbytes() const {
|
||||||
return size() * itemsize();
|
return size() * itemsize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of dimensions
|
/// Number of dimensions
|
||||||
size_t ndim() const {
|
ssize_t ndim() const {
|
||||||
return (size_t) detail::array_proxy(m_ptr)->nd;
|
return detail::array_proxy(m_ptr)->nd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Base object
|
/// Base object
|
||||||
@ -564,12 +564,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dimensions of the array
|
/// Dimensions of the array
|
||||||
const size_t* shape() const {
|
const ssize_t* shape() const {
|
||||||
return reinterpret_cast<const size_t *>(detail::array_proxy(m_ptr)->dimensions);
|
return detail::array_proxy(m_ptr)->dimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dimension along a given axis
|
/// Dimension along a given axis
|
||||||
size_t shape(size_t dim) const {
|
ssize_t shape(ssize_t dim) const {
|
||||||
if (dim >= ndim())
|
if (dim >= ndim())
|
||||||
fail_dim_check(dim, "invalid axis");
|
fail_dim_check(dim, "invalid axis");
|
||||||
return shape()[dim];
|
return shape()[dim];
|
||||||
@ -577,11 +577,11 @@ public:
|
|||||||
|
|
||||||
/// Strides of the array
|
/// Strides of the array
|
||||||
const ssize_t* strides() const {
|
const ssize_t* strides() const {
|
||||||
return reinterpret_cast<const ssize_t *>(detail::array_proxy(m_ptr)->strides);
|
return detail::array_proxy(m_ptr)->strides;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stride along a given axis
|
/// Stride along a given axis
|
||||||
ssize_t strides(size_t dim) const {
|
ssize_t strides(ssize_t dim) const {
|
||||||
if (dim >= ndim())
|
if (dim >= ndim())
|
||||||
fail_dim_check(dim, "invalid axis");
|
fail_dim_check(dim, "invalid axis");
|
||||||
return strides()[dim];
|
return strides()[dim];
|
||||||
@ -619,9 +619,9 @@ public:
|
|||||||
/// Byte offset from beginning of the array to a given index (full or partial).
|
/// Byte offset from beginning of the array to a given index (full or partial).
|
||||||
/// May throw if the index would lead to out of bounds access.
|
/// May throw if the index would lead to out of bounds access.
|
||||||
template<typename... Ix> ssize_t offset_at(Ix... index) const {
|
template<typename... Ix> ssize_t offset_at(Ix... index) const {
|
||||||
if (sizeof...(index) > ndim())
|
if ((ssize_t) sizeof...(index) > ndim())
|
||||||
fail_dim_check(sizeof...(index), "too many indices for an array");
|
fail_dim_check(sizeof...(index), "too many indices for an array");
|
||||||
return byte_offset(size_t(index)...);
|
return byte_offset(ssize_t(index)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t offset_at() const { return 0; }
|
ssize_t offset_at() const { return 0; }
|
||||||
@ -629,7 +629,7 @@ public:
|
|||||||
/// Item count from beginning of the array to a given index (full or partial).
|
/// Item count from beginning of the array to a given index (full or partial).
|
||||||
/// May throw if the index would lead to out of bounds access.
|
/// May throw if the index would lead to out of bounds access.
|
||||||
template<typename... Ix> ssize_t index_at(Ix... index) const {
|
template<typename... Ix> ssize_t index_at(Ix... index) const {
|
||||||
return offset_at(index...) / static_cast<ssize_t>(itemsize());
|
return offset_at(index...) / itemsize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a proxy object that provides access to the array's data without bounds or
|
/** Returns a proxy object that provides access to the array's data without bounds or
|
||||||
@ -638,7 +638,7 @@ public:
|
|||||||
* and the caller must take care not to access invalid dimensions or dimension indices.
|
* and the caller must take care not to access invalid dimensions or dimension indices.
|
||||||
*/
|
*/
|
||||||
template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
|
template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
|
||||||
if (Dims >= 0 && ndim() != (size_t) Dims)
|
if (Dims >= 0 && ndim() != Dims)
|
||||||
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
||||||
"; expected " + std::to_string(Dims));
|
"; expected " + std::to_string(Dims));
|
||||||
return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
|
return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
|
||||||
@ -651,7 +651,7 @@ public:
|
|||||||
* invalid dimensions or dimension indices.
|
* invalid dimensions or dimension indices.
|
||||||
*/
|
*/
|
||||||
template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const {
|
template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const {
|
||||||
if (Dims >= 0 && ndim() != (size_t) Dims)
|
if (Dims >= 0 && ndim() != Dims)
|
||||||
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
||||||
"; expected " + std::to_string(Dims));
|
"; expected " + std::to_string(Dims));
|
||||||
return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
|
return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
|
||||||
@ -690,14 +690,14 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
template<typename, typename> friend struct detail::npy_format_descriptor;
|
template<typename, typename> friend struct detail::npy_format_descriptor;
|
||||||
|
|
||||||
void fail_dim_check(size_t dim, const std::string& msg) const {
|
void fail_dim_check(ssize_t dim, const std::string& msg) const {
|
||||||
throw index_error(msg + ": " + std::to_string(dim) +
|
throw index_error(msg + ": " + std::to_string(dim) +
|
||||||
" (ndim = " + std::to_string(ndim()) + ")");
|
" (ndim = " + std::to_string(ndim()) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> ssize_t byte_offset(Ix... index) const {
|
template<typename... Ix> ssize_t byte_offset(Ix... index) const {
|
||||||
check_dimensions(index...);
|
check_dimensions(index...);
|
||||||
return detail::byte_offset_unsafe(strides(), size_t(index)...);
|
return detail::byte_offset_unsafe(strides(), ssize_t(index)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_writeable() const {
|
void check_writeable() const {
|
||||||
@ -705,7 +705,7 @@ protected:
|
|||||||
throw std::domain_error("array is not writeable");
|
throw std::domain_error("array is not writeable");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<ssize_t> default_strides(const std::vector<size_t>& shape, size_t itemsize) {
|
static std::vector<Py_intptr_t> default_strides(const std::vector<Py_intptr_t>& shape, ssize_t itemsize) {
|
||||||
auto ndim = shape.size();
|
auto ndim = shape.size();
|
||||||
std::vector<ssize_t> strides(ndim);
|
std::vector<ssize_t> strides(ndim);
|
||||||
if (ndim) {
|
if (ndim) {
|
||||||
@ -718,12 +718,12 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> void check_dimensions(Ix... index) const {
|
template<typename... Ix> void check_dimensions(Ix... index) const {
|
||||||
check_dimensions_impl(size_t(0), shape(), size_t(index)...);
|
check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_dimensions_impl(size_t, const size_t*) const { }
|
void check_dimensions_impl(ssize_t, const ssize_t*) const { }
|
||||||
|
|
||||||
template<typename... Ix> void check_dimensions_impl(size_t axis, const size_t* shape, size_t i, Ix... index) const {
|
template<typename... Ix> void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_t i, Ix... index) const {
|
||||||
if (i >= *shape) {
|
if (i >= *shape) {
|
||||||
throw index_error(std::string("index ") + std::to_string(i) +
|
throw index_error(std::string("index ") + std::to_string(i) +
|
||||||
" is out of bounds for axis " + std::to_string(axis) +
|
" is out of bounds for axis " + std::to_string(axis) +
|
||||||
@ -772,12 +772,12 @@ public:
|
|||||||
explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle())
|
explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle())
|
||||||
: array({count}, {}, ptr, base) { }
|
: array({count}, {}, ptr, base) { }
|
||||||
|
|
||||||
constexpr size_t itemsize() const {
|
constexpr ssize_t itemsize() const {
|
||||||
return sizeof(T);
|
return sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> ssize_t index_at(Ix... index) const {
|
template<typename... Ix> ssize_t index_at(Ix... index) const {
|
||||||
return offset_at(index...) / static_cast<ssize_t>(itemsize());
|
return offset_at(index...) / itemsize();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> const T* data(Ix... index) const {
|
template<typename... Ix> const T* data(Ix... index) const {
|
||||||
@ -792,14 +792,14 @@ public:
|
|||||||
template<typename... Ix> const T& at(Ix... index) const {
|
template<typename... Ix> const T& at(Ix... index) const {
|
||||||
if (sizeof...(index) != ndim())
|
if (sizeof...(index) != ndim())
|
||||||
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
||||||
return *(static_cast<const T*>(array::data()) + byte_offset(size_t(index)...) / static_cast<ssize_t>(itemsize()));
|
return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutable reference to element at a given index
|
// Mutable reference to element at a given index
|
||||||
template<typename... Ix> T& mutable_at(Ix... index) {
|
template<typename... Ix> T& mutable_at(Ix... index) {
|
||||||
if (sizeof...(index) != ndim())
|
if (sizeof...(index) != ndim())
|
||||||
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
fail_dim_check(sizeof...(index), "index dimension mismatch");
|
||||||
return *(static_cast<T*>(array::mutable_data()) + byte_offset(size_t(index)...) / static_cast<ssize_t>(itemsize()));
|
return *(static_cast<T*>(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a proxy object that provides access to the array's data without bounds or
|
/** Returns a proxy object that provides access to the array's data without bounds or
|
||||||
@ -949,16 +949,16 @@ public:
|
|||||||
|
|
||||||
struct field_descriptor {
|
struct field_descriptor {
|
||||||
const char *name;
|
const char *name;
|
||||||
size_t offset;
|
ssize_t offset;
|
||||||
size_t size;
|
ssize_t size;
|
||||||
size_t alignment;
|
ssize_t alignment;
|
||||||
std::string format;
|
std::string format;
|
||||||
dtype descr;
|
dtype descr;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline PYBIND11_NOINLINE void register_structured_dtype(
|
inline PYBIND11_NOINLINE void register_structured_dtype(
|
||||||
const std::initializer_list<field_descriptor>& fields,
|
const std::initializer_list<field_descriptor>& fields,
|
||||||
const std::type_info& tinfo, size_t itemsize,
|
const std::type_info& tinfo, ssize_t itemsize,
|
||||||
bool (*direct_converter)(PyObject *, void *&)) {
|
bool (*direct_converter)(PyObject *, void *&)) {
|
||||||
|
|
||||||
auto& numpy_internals = get_numpy_internals();
|
auto& numpy_internals = get_numpy_internals();
|
||||||
@ -986,7 +986,7 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
|
|||||||
std::vector<field_descriptor> ordered_fields(fields);
|
std::vector<field_descriptor> ordered_fields(fields);
|
||||||
std::sort(ordered_fields.begin(), ordered_fields.end(),
|
std::sort(ordered_fields.begin(), ordered_fields.end(),
|
||||||
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
|
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
|
||||||
size_t offset = 0;
|
ssize_t offset = 0;
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "T{";
|
oss << "T{";
|
||||||
for (auto& field : ordered_fields) {
|
for (auto& field : ordered_fields) {
|
||||||
@ -1142,7 +1142,7 @@ public:
|
|||||||
|
|
||||||
common_iterator() : p_ptr(0), m_strides() {}
|
common_iterator() : p_ptr(0), m_strides() {}
|
||||||
|
|
||||||
common_iterator(void* ptr, const container_type& strides, const std::vector<size_t>& shape)
|
common_iterator(void* ptr, const container_type& strides, const container_type& shape)
|
||||||
: p_ptr(reinterpret_cast<char*>(ptr)), m_strides(strides.size()) {
|
: p_ptr(reinterpret_cast<char*>(ptr)), m_strides(strides.size()) {
|
||||||
m_strides.back() = static_cast<value_type>(strides.back());
|
m_strides.back() = static_cast<value_type>(strides.back());
|
||||||
for (size_type i = m_strides.size() - 1; i != 0; --i) {
|
for (size_type i = m_strides.size() - 1; i != 0; --i) {
|
||||||
@ -1167,18 +1167,18 @@ private:
|
|||||||
|
|
||||||
template <size_t N> class multi_array_iterator {
|
template <size_t N> class multi_array_iterator {
|
||||||
public:
|
public:
|
||||||
using container_type = std::vector<size_t>;
|
using container_type = std::vector<ssize_t>;
|
||||||
|
|
||||||
multi_array_iterator(const std::array<buffer_info, N> &buffers,
|
multi_array_iterator(const std::array<buffer_info, N> &buffers,
|
||||||
const std::vector<size_t> &shape)
|
const container_type &shape)
|
||||||
: m_shape(shape.size()), m_index(shape.size(), 0),
|
: m_shape(shape.size()), m_index(shape.size(), 0),
|
||||||
m_common_iterator() {
|
m_common_iterator() {
|
||||||
|
|
||||||
// Manual copy to avoid conversion warning if using std::copy
|
// Manual copy to avoid conversion warning if using std::copy
|
||||||
for (size_t i = 0; i < shape.size(); ++i)
|
for (size_t i = 0; i < shape.size(); ++i)
|
||||||
m_shape[i] = static_cast<container_type::value_type>(shape[i]);
|
m_shape[i] = shape[i];
|
||||||
|
|
||||||
std::vector<ssize_t> strides(shape.size());
|
container_type strides(shape.size());
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
init_common_iterator(buffers[i], shape, m_common_iterator[i], strides);
|
init_common_iterator(buffers[i], shape, m_common_iterator[i], strides);
|
||||||
}
|
}
|
||||||
@ -1205,8 +1205,9 @@ private:
|
|||||||
using common_iter = common_iterator;
|
using common_iter = common_iterator;
|
||||||
|
|
||||||
void init_common_iterator(const buffer_info &buffer,
|
void init_common_iterator(const buffer_info &buffer,
|
||||||
const std::vector<size_t> &shape,
|
const container_type &shape,
|
||||||
common_iter &iterator, std::vector<ssize_t> &strides) {
|
common_iter &iterator,
|
||||||
|
container_type &strides) {
|
||||||
auto buffer_shape_iter = buffer.shape.rbegin();
|
auto buffer_shape_iter = buffer.shape.rbegin();
|
||||||
auto buffer_strides_iter = buffer.strides.rbegin();
|
auto buffer_strides_iter = buffer.strides.rbegin();
|
||||||
auto shape_iter = shape.rbegin();
|
auto shape_iter = shape.rbegin();
|
||||||
@ -1245,13 +1246,13 @@ enum class broadcast_trivial { non_trivial, c_trivial, f_trivial };
|
|||||||
// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage
|
// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage
|
||||||
// buffer; returns `non_trivial` otherwise.
|
// buffer; returns `non_trivial` otherwise.
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, size_t &ndim, std::vector<size_t> &shape) {
|
broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &shape) {
|
||||||
ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) {
|
ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info& buf) {
|
||||||
return std::max(res, buf.ndim);
|
return std::max(res, buf.ndim);
|
||||||
});
|
});
|
||||||
|
|
||||||
shape.clear();
|
shape.clear();
|
||||||
shape.resize(ndim, 1);
|
shape.resize((size_t) ndim, 1);
|
||||||
|
|
||||||
// Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or
|
// Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or
|
||||||
// the full size).
|
// the full size).
|
||||||
@ -1286,11 +1287,10 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, size_t &n
|
|||||||
|
|
||||||
// Check for C contiguity (but only if previous inputs were also C contiguous)
|
// Check for C contiguity (but only if previous inputs were also C contiguous)
|
||||||
if (trivial_broadcast_c) {
|
if (trivial_broadcast_c) {
|
||||||
ssize_t expect_stride = static_cast<ssize_t>(buffers[i].itemsize);
|
ssize_t expect_stride = buffers[i].itemsize;
|
||||||
auto end = buffers[i].shape.crend();
|
auto end = buffers[i].shape.crend();
|
||||||
auto shape_iter = buffers[i].shape.crbegin();
|
for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin();
|
||||||
auto stride_iter = buffers[i].strides.crbegin();
|
trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) {
|
||||||
for (; trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) {
|
|
||||||
if (expect_stride == *stride_iter)
|
if (expect_stride == *stride_iter)
|
||||||
expect_stride *= *shape_iter;
|
expect_stride *= *shape_iter;
|
||||||
else
|
else
|
||||||
@ -1300,11 +1300,10 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, size_t &n
|
|||||||
|
|
||||||
// Check for Fortran contiguity (if previous inputs were also F contiguous)
|
// Check for Fortran contiguity (if previous inputs were also F contiguous)
|
||||||
if (trivial_broadcast_f) {
|
if (trivial_broadcast_f) {
|
||||||
ssize_t expect_stride = static_cast<ssize_t>(buffers[i].itemsize);
|
ssize_t expect_stride = buffers[i].itemsize;
|
||||||
auto end = buffers[i].shape.cend();
|
auto end = buffers[i].shape.cend();
|
||||||
auto shape_iter = buffers[i].shape.cbegin();
|
for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin();
|
||||||
auto stride_iter = buffers[i].strides.cbegin();
|
trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) {
|
||||||
for (; trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) {
|
|
||||||
if (expect_stride == *stride_iter)
|
if (expect_stride == *stride_iter)
|
||||||
expect_stride *= *shape_iter;
|
expect_stride *= *shape_iter;
|
||||||
else
|
else
|
||||||
@ -1336,25 +1335,26 @@ struct vectorize_helper {
|
|||||||
std::array<buffer_info, N> buffers {{ args.request()... }};
|
std::array<buffer_info, N> buffers {{ args.request()... }};
|
||||||
|
|
||||||
/* Determine dimensions parameters of output array */
|
/* Determine dimensions parameters of output array */
|
||||||
size_t ndim = 0;
|
ssize_t nd = 0;
|
||||||
std::vector<size_t> shape(0);
|
std::vector<ssize_t> shape(0);
|
||||||
auto trivial = broadcast(buffers, ndim, shape);
|
auto trivial = broadcast(buffers, nd, shape);
|
||||||
|
size_t ndim = (size_t) nd;
|
||||||
|
|
||||||
size_t size = 1;
|
ssize_t size = 1;
|
||||||
std::vector<ssize_t> strides(ndim);
|
std::vector<ssize_t> strides(ndim);
|
||||||
if (ndim > 0) {
|
if (ndim > 0) {
|
||||||
if (trivial == broadcast_trivial::f_trivial) {
|
if (trivial == broadcast_trivial::f_trivial) {
|
||||||
strides[0] = static_cast<ssize_t>(sizeof(Return));
|
strides[0] = sizeof(Return);
|
||||||
for (size_t i = 1; i < ndim; ++i) {
|
for (size_t i = 1; i < ndim; ++i) {
|
||||||
strides[i] = strides[i - 1] * static_cast<ssize_t>(shape[i - 1]);
|
strides[i] = strides[i - 1] * shape[i - 1];
|
||||||
size *= shape[i - 1];
|
size *= shape[i - 1];
|
||||||
}
|
}
|
||||||
size *= shape[ndim - 1];
|
size *= shape[ndim - 1];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
strides[ndim-1] = static_cast<ssize_t>(sizeof(Return));
|
strides[ndim-1] = sizeof(Return);
|
||||||
for (size_t i = ndim - 1; i > 0; --i) {
|
for (size_t i = ndim - 1; i > 0; --i) {
|
||||||
strides[i - 1] = strides[i] * static_cast<ssize_t>(shape[i]);
|
strides[i - 1] = strides[i] * shape[i];
|
||||||
size *= shape[i];
|
size *= shape[i];
|
||||||
}
|
}
|
||||||
size *= shape[0];
|
size *= shape[0];
|
||||||
@ -1372,7 +1372,7 @@ struct vectorize_helper {
|
|||||||
if (trivial == broadcast_trivial::non_trivial) {
|
if (trivial == broadcast_trivial::non_trivial) {
|
||||||
apply_broadcast<Index...>(buffers, buf, index);
|
apply_broadcast<Index...>(buffers, buf, index);
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < size; ++i)
|
for (ssize_t i = 0; i < size; ++i)
|
||||||
output[i] = f((reinterpret_cast<Args *>(buffers[Index].ptr)[buffers[Index].size == 1 ? 0 : i])...);
|
output[i] = f((reinterpret_cast<Args *>(buffers[Index].ptr)[buffers[Index].size == 1 ? 0 : i])...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1165,15 +1165,15 @@ public:
|
|||||||
static std::vector<Py_ssize_t> py_strides { };
|
static std::vector<Py_ssize_t> py_strides { };
|
||||||
static std::vector<Py_ssize_t> py_shape { };
|
static std::vector<Py_ssize_t> py_shape { };
|
||||||
buf.buf = info.ptr;
|
buf.buf = info.ptr;
|
||||||
buf.itemsize = (Py_ssize_t) info.itemsize;
|
buf.itemsize = info.itemsize;
|
||||||
buf.format = const_cast<char *>(info.format.c_str());
|
buf.format = const_cast<char *>(info.format.c_str());
|
||||||
buf.ndim = (int) info.ndim;
|
buf.ndim = (int) info.ndim;
|
||||||
buf.len = (Py_ssize_t) info.size;
|
buf.len = info.size;
|
||||||
py_strides.clear();
|
py_strides.clear();
|
||||||
py_shape.clear();
|
py_shape.clear();
|
||||||
for (size_t i = 0; i < info.ndim; ++i) {
|
for (size_t i = 0; i < (size_t) info.ndim; ++i) {
|
||||||
py_strides.push_back((Py_ssize_t) info.strides[i]);
|
py_strides.push_back(info.strides[i]);
|
||||||
py_shape.push_back((Py_ssize_t) info.shape[i]);
|
py_shape.push_back(info.shape[i]);
|
||||||
}
|
}
|
||||||
buf.strides = py_strides.data();
|
buf.strides = py_strides.data();
|
||||||
buf.shape = py_shape.data();
|
buf.shape = py_shape.data();
|
||||||
|
@ -345,21 +345,21 @@ vector_buffer(Class_& cl) {
|
|||||||
format_descriptor<T>::format();
|
format_descriptor<T>::format();
|
||||||
|
|
||||||
cl.def_buffer([](Vector& v) -> buffer_info {
|
cl.def_buffer([](Vector& v) -> buffer_info {
|
||||||
return buffer_info(v.data(), sizeof(T), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
|
return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
|
||||||
});
|
});
|
||||||
|
|
||||||
cl.def("__init__", [](Vector& vec, buffer buf) {
|
cl.def("__init__", [](Vector& vec, buffer buf) {
|
||||||
auto info = buf.request();
|
auto info = buf.request();
|
||||||
if (info.ndim != 1 || info.strides[0] <= 0 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
|
if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
|
||||||
throw type_error("Only valid 1D buffers can be copied to a vector");
|
throw type_error("Only valid 1D buffers can be copied to a vector");
|
||||||
if (!detail::compare_buffer_info<T>::compare(info) || sizeof(T) != info.itemsize)
|
if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize)
|
||||||
throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
|
throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
|
||||||
new (&vec) Vector();
|
new (&vec) Vector();
|
||||||
vec.reserve(info.shape[0]);
|
vec.reserve((size_t) info.shape[0]);
|
||||||
T *p = static_cast<T*>(info.ptr);
|
T *p = static_cast<T*>(info.ptr);
|
||||||
auto step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
|
||||||
T *end = p + static_cast<ssize_t>(info.shape[0]) * step;
|
T *end = p + info.shape[0] * step;
|
||||||
for (; p < end; p += step)
|
for (; p != end; p += step)
|
||||||
vec.push_back(*p);
|
vec.push_back(*p);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -12,16 +12,16 @@
|
|||||||
|
|
||||||
class Matrix {
|
class Matrix {
|
||||||
public:
|
public:
|
||||||
Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
|
Matrix(ssize_t rows, ssize_t cols) : m_rows(rows), m_cols(cols) {
|
||||||
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
m_data = new float[rows*cols];
|
m_data = new float[(size_t) (rows*cols)];
|
||||||
memset(m_data, 0, sizeof(float) * rows * cols);
|
memset(m_data, 0, sizeof(float) * (size_t) (rows * cols));
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
|
||||||
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
|
||||||
m_data = new float[m_rows * m_cols];
|
m_data = new float[(size_t) (m_rows * m_cols)];
|
||||||
memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
|
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
|
||||||
@ -41,8 +41,8 @@ public:
|
|||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
m_rows = s.m_rows;
|
m_rows = s.m_rows;
|
||||||
m_cols = s.m_cols;
|
m_cols = s.m_cols;
|
||||||
m_data = new float[m_rows * m_cols];
|
m_data = new float[(size_t) (m_rows * m_cols)];
|
||||||
memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
|
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,47 +56,47 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
float operator()(size_t i, size_t j) const {
|
float operator()(ssize_t i, ssize_t j) const {
|
||||||
return m_data[i*m_cols + j];
|
return m_data[(size_t) (i*m_cols + j)];
|
||||||
}
|
}
|
||||||
|
|
||||||
float &operator()(size_t i, size_t j) {
|
float &operator()(ssize_t i, ssize_t j) {
|
||||||
return m_data[i*m_cols + j];
|
return m_data[(size_t) (i*m_cols + j)];
|
||||||
}
|
}
|
||||||
|
|
||||||
float *data() { return m_data; }
|
float *data() { return m_data; }
|
||||||
|
|
||||||
size_t rows() const { return m_rows; }
|
ssize_t rows() const { return m_rows; }
|
||||||
size_t cols() const { return m_cols; }
|
ssize_t cols() const { return m_cols; }
|
||||||
private:
|
private:
|
||||||
size_t m_rows;
|
ssize_t m_rows;
|
||||||
size_t m_cols;
|
ssize_t m_cols;
|
||||||
float *m_data;
|
float *m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
test_initializer buffers([](py::module &m) {
|
test_initializer buffers([](py::module &m) {
|
||||||
py::class_<Matrix> mtx(m, "Matrix", py::buffer_protocol());
|
py::class_<Matrix> mtx(m, "Matrix", py::buffer_protocol());
|
||||||
|
|
||||||
mtx.def(py::init<size_t, size_t>())
|
mtx.def(py::init<ssize_t, ssize_t>())
|
||||||
/// Construct from a buffer
|
/// Construct from a buffer
|
||||||
.def("__init__", [](Matrix &v, py::buffer b) {
|
.def("__init__", [](Matrix &v, py::buffer b) {
|
||||||
py::buffer_info info = b.request();
|
py::buffer_info info = b.request();
|
||||||
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
|
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
|
||||||
throw std::runtime_error("Incompatible buffer format!");
|
throw std::runtime_error("Incompatible buffer format!");
|
||||||
new (&v) Matrix(info.shape[0], info.shape[1]);
|
new (&v) Matrix(info.shape[0], info.shape[1]);
|
||||||
memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols());
|
memcpy(v.data(), info.ptr, sizeof(float) * (size_t) (v.rows() * v.cols()));
|
||||||
})
|
})
|
||||||
|
|
||||||
.def("rows", &Matrix::rows)
|
.def("rows", &Matrix::rows)
|
||||||
.def("cols", &Matrix::cols)
|
.def("cols", &Matrix::cols)
|
||||||
|
|
||||||
/// Bare bones interface
|
/// Bare bones interface
|
||||||
.def("__getitem__", [](const Matrix &m, std::pair<size_t, size_t> i) {
|
.def("__getitem__", [](const Matrix &m, std::pair<ssize_t, ssize_t> i) {
|
||||||
if (i.first >= m.rows() || i.second >= m.cols())
|
if (i.first >= m.rows() || i.second >= m.cols())
|
||||||
throw py::index_error();
|
throw py::index_error();
|
||||||
return m(i.first, i.second);
|
return m(i.first, i.second);
|
||||||
})
|
})
|
||||||
.def("__setitem__", [](Matrix &m, std::pair<size_t, size_t> i, float v) {
|
.def("__setitem__", [](Matrix &m, std::pair<ssize_t, ssize_t> i, float v) {
|
||||||
if (i.first >= m.rows() || i.second >= m.cols())
|
if (i.first >= m.rows() || i.second >= m.cols())
|
||||||
throw py::index_error();
|
throw py::index_error();
|
||||||
m(i.first, i.second) = v;
|
m(i.first, i.second) = v;
|
||||||
@ -109,8 +109,8 @@ test_initializer buffers([](py::module &m) {
|
|||||||
py::format_descriptor<float>::format(), /* Python struct-style format descriptor */
|
py::format_descriptor<float>::format(), /* Python struct-style format descriptor */
|
||||||
2, /* Number of dimensions */
|
2, /* Number of dimensions */
|
||||||
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||||
{ static_cast<ssize_t>(sizeof(float) * m.rows()), /* Strides (in bytes) for each index */
|
{ sizeof(float) * size_t(m.rows()), /* Strides (in bytes) for each index */
|
||||||
static_cast<ssize_t>(sizeof(float)) }
|
sizeof(float) }
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
@ -186,7 +186,7 @@ def test_negative_stride_from_python(msg):
|
|||||||
double_threer(second_row)
|
double_threer(second_row)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
double_threer(): incompatible function arguments. The following argument types are supported:
|
double_threer(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (numpy.ndarray[float32[1, 3], flags.writeable]) -> arg0: None
|
1. (arg0: numpy.ndarray[float32[1, 3], flags.writeable]) -> None
|
||||||
|
|
||||||
Invoked with: array([ 5., 4., 3.], dtype=float32)
|
Invoked with: array([ 5., 4., 3.], dtype=float32)
|
||||||
"""
|
"""
|
||||||
@ -195,7 +195,7 @@ def test_negative_stride_from_python(msg):
|
|||||||
double_threec(second_col)
|
double_threec(second_col)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
double_threec(): incompatible function arguments. The following argument types are supported:
|
double_threec(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (numpy.ndarray[float32[3, 1], flags.writeable]) -> arg0: None
|
1. (arg0: numpy.ndarray[float32[3, 1], flags.writeable]) -> None
|
||||||
|
|
||||||
Invoked with: array([ 7., 4., 1.], dtype=float32)
|
Invoked with: array([ 7., 4., 1.], dtype=float32)
|
||||||
"""
|
"""
|
||||||
|
@ -13,53 +13,52 @@
|
|||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using arr = py::array;
|
using arr = py::array;
|
||||||
using arr_t = py::array_t<uint16_t, 0>;
|
using arr_t = py::array_t<uint16_t, 0>;
|
||||||
static_assert(std::is_same<arr_t::value_type, uint16_t>::value, "");
|
static_assert(std::is_same<arr_t::value_type, uint16_t>::value, "");
|
||||||
|
|
||||||
template<typename... Ix> arr data(const arr& a, Ix... index) {
|
template<typename... Ix> arr data(const arr& a, Ix... index) {
|
||||||
return arr(a.nbytes() - size_t(a.offset_at(index...)), (const uint8_t *) a.data(index...));
|
return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {
|
template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {
|
||||||
return arr(a.size() - size_t(a.index_at(index...)), a.data(index...));
|
return arr(a.size() - a.index_at(index...), a.data(index...));
|
||||||
}
|
}
|
||||||
|
|
||||||
arr& mutate_data(arr& a) {
|
arr& mutate_data(arr& a) {
|
||||||
auto ptr = (uint8_t *) a.mutable_data();
|
auto ptr = (uint8_t *) a.mutable_data();
|
||||||
for (size_t i = 0; i < a.nbytes(); i++)
|
for (ssize_t i = 0; i < a.nbytes(); i++)
|
||||||
ptr[i] = (uint8_t) (ptr[i] * 2);
|
ptr[i] = (uint8_t) (ptr[i] * 2);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
arr_t& mutate_data_t(arr_t& a) {
|
arr_t& mutate_data_t(arr_t& a) {
|
||||||
auto ptr = a.mutable_data();
|
auto ptr = a.mutable_data();
|
||||||
for (size_t i = 0; i < a.size(); i++)
|
for (ssize_t i = 0; i < a.size(); i++)
|
||||||
ptr[i]++;
|
ptr[i]++;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {
|
template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {
|
||||||
auto ptr = (uint8_t *) a.mutable_data(index...);
|
auto ptr = (uint8_t *) a.mutable_data(index...);
|
||||||
for (size_t i = 0; i < a.nbytes() - size_t(a.offset_at(index...)); i++)
|
for (ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++)
|
||||||
ptr[i] = (uint8_t) (ptr[i] * 2);
|
ptr[i] = (uint8_t) (ptr[i] * 2);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> arr_t& mutate_data_t(arr_t& a, Ix... index) {
|
template<typename... Ix> arr_t& mutate_data_t(arr_t& a, Ix... index) {
|
||||||
auto ptr = a.mutable_data(index...);
|
auto ptr = a.mutable_data(index...);
|
||||||
for (size_t i = 0; i < a.size() - size_t(a.index_at(index...)); i++)
|
for (ssize_t i = 0; i < a.size() - a.index_at(index...); i++)
|
||||||
ptr[i]++;
|
ptr[i]++;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ix> py::ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); }
|
template<typename... Ix> ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); }
|
||||||
template<typename... Ix> py::ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); }
|
template<typename... Ix> ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); }
|
||||||
template<typename... Ix> py::ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); }
|
template<typename... Ix> ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); }
|
||||||
template<typename... Ix> py::ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); }
|
template<typename... Ix> ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); }
|
||||||
template<typename... Ix> py::ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); }
|
template<typename... Ix> ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); }
|
||||||
template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; }
|
template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; }
|
||||||
|
|
||||||
#define def_index_fn(name, type) \
|
#define def_index_fn(name, type) \
|
||||||
@ -88,9 +87,9 @@ test_initializer numpy_array([](py::module &m) {
|
|||||||
|
|
||||||
sm.def("ndim", [](const arr& a) { return a.ndim(); });
|
sm.def("ndim", [](const arr& a) { return a.ndim(); });
|
||||||
sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); });
|
sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); });
|
||||||
sm.def("shape", [](const arr& a, size_t dim) { return a.shape(dim); });
|
sm.def("shape", [](const arr& a, ssize_t dim) { return a.shape(dim); });
|
||||||
sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); });
|
sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); });
|
||||||
sm.def("strides", [](const arr& a, size_t dim) { return a.strides(dim); });
|
sm.def("strides", [](const arr& a, ssize_t dim) { return a.strides(dim); });
|
||||||
sm.def("writeable", [](const arr& a) { return a.writeable(); });
|
sm.def("writeable", [](const arr& a) { return a.writeable(); });
|
||||||
sm.def("size", [](const arr& a) { return a.size(); });
|
sm.def("size", [](const arr& a) { return a.size(); });
|
||||||
sm.def("itemsize", [](const arr& a) { return a.itemsize(); });
|
sm.def("itemsize", [](const arr& a) { return a.itemsize(); });
|
||||||
@ -202,33 +201,33 @@ test_initializer numpy_array([](py::module &m) {
|
|||||||
|
|
||||||
sm.def("proxy_add2", [](py::array_t<double> a, double v) {
|
sm.def("proxy_add2", [](py::array_t<double> a, double v) {
|
||||||
auto r = a.mutable_unchecked<2>();
|
auto r = a.mutable_unchecked<2>();
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
r(i, j) += v;
|
r(i, j) += v;
|
||||||
}, py::arg().noconvert(), py::arg());
|
}, py::arg().noconvert(), py::arg());
|
||||||
|
|
||||||
sm.def("proxy_init3", [](double start) {
|
sm.def("proxy_init3", [](double start) {
|
||||||
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
||||||
auto r = a.mutable_unchecked<3>();
|
auto r = a.mutable_unchecked<3>();
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
for (size_t k = 0; k < r.shape(2); k++)
|
for (ssize_t k = 0; k < r.shape(2); k++)
|
||||||
r(i, j, k) = start++;
|
r(i, j, k) = start++;
|
||||||
return a;
|
return a;
|
||||||
});
|
});
|
||||||
sm.def("proxy_init3F", [](double start) {
|
sm.def("proxy_init3F", [](double start) {
|
||||||
py::array_t<double, py::array::f_style> a({ 3, 3, 3 });
|
py::array_t<double, py::array::f_style> a({ 3, 3, 3 });
|
||||||
auto r = a.mutable_unchecked<3>();
|
auto r = a.mutable_unchecked<3>();
|
||||||
for (size_t k = 0; k < r.shape(2); k++)
|
for (ssize_t k = 0; k < r.shape(2); k++)
|
||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
r(i, j, k) = start++;
|
r(i, j, k) = start++;
|
||||||
return a;
|
return a;
|
||||||
});
|
});
|
||||||
sm.def("proxy_squared_L2_norm", [](py::array_t<double> a) {
|
sm.def("proxy_squared_L2_norm", [](py::array_t<double> a) {
|
||||||
auto r = a.unchecked<1>();
|
auto r = a.unchecked<1>();
|
||||||
double sumsq = 0;
|
double sumsq = 0;
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
sumsq += r[i] * r(i); // Either notation works for a 1D array
|
sumsq += r[i] * r(i); // Either notation works for a 1D array
|
||||||
return sumsq;
|
return sumsq;
|
||||||
});
|
});
|
||||||
@ -243,17 +242,17 @@ test_initializer numpy_array([](py::module &m) {
|
|||||||
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
|
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
|
||||||
auto r = a.mutable_unchecked();
|
auto r = a.mutable_unchecked();
|
||||||
if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
|
if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
r(i, j) += v;
|
r(i, j) += v;
|
||||||
}, py::arg().noconvert(), py::arg());
|
}, py::arg().noconvert(), py::arg());
|
||||||
sm.def("proxy_init3_dyn", [](double start) {
|
sm.def("proxy_init3_dyn", [](double start) {
|
||||||
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
||||||
auto r = a.mutable_unchecked();
|
auto r = a.mutable_unchecked();
|
||||||
if (r.ndim() != 3) throw std::domain_error("error: ndim != 3");
|
if (r.ndim() != 3) throw std::domain_error("error: ndim != 3");
|
||||||
for (size_t i = 0; i < r.shape(0); i++)
|
for (ssize_t i = 0; i < r.shape(0); i++)
|
||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (ssize_t j = 0; j < r.shape(1); j++)
|
||||||
for (size_t k = 0; k < r.shape(2); k++)
|
for (ssize_t k = 0; k < r.shape(2); k++)
|
||||||
r(i, j, k) = start++;
|
r(i, j, k) = start++;
|
||||||
return a;
|
return a;
|
||||||
});
|
});
|
||||||
@ -269,6 +268,9 @@ test_initializer numpy_array([](py::module &m) {
|
|||||||
sm.def("array_fail_test", []() { return py::array(py::object()); });
|
sm.def("array_fail_test", []() { return py::array(py::object()); });
|
||||||
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
|
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
|
||||||
|
|
||||||
|
// Make sure the error from numpy is being passed through:
|
||||||
|
sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); });
|
||||||
|
|
||||||
// Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
|
// Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
|
||||||
sm.def("array_initializer_list", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
|
sm.def("array_initializer_list", []() { return py::array_t<float>(1); }); // { 1 } also works, but clang warns about it
|
||||||
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2 }); });
|
sm.def("array_initializer_list", []() { return py::array_t<float>({ 1, 2 }); });
|
||||||
@ -277,7 +279,7 @@ test_initializer numpy_array([](py::module &m) {
|
|||||||
|
|
||||||
// reshape array to 2D without changing size
|
// reshape array to 2D without changing size
|
||||||
sm.def("array_reshape2", [](py::array_t<double> a) {
|
sm.def("array_reshape2", [](py::array_t<double> a) {
|
||||||
const size_t dim_sz = (size_t)std::sqrt(a.size());
|
const ssize_t dim_sz = (ssize_t)std::sqrt(a.size());
|
||||||
if (dim_sz * dim_sz != a.size())
|
if (dim_sz * dim_sz != a.size())
|
||||||
throw std::domain_error("array_reshape2: input array total size is not a squared integer");
|
throw std::domain_error("array_reshape2: input array total size is not a squared integer");
|
||||||
a.resize({dim_sz, dim_sz});
|
a.resize({dim_sz, dim_sz});
|
||||||
|
@ -384,7 +384,8 @@ def test_array_unchecked_dyn_dims(msg):
|
|||||||
|
|
||||||
|
|
||||||
def test_array_failure():
|
def test_array_failure():
|
||||||
from pybind11_tests.array import array_fail_test, array_t_fail_test
|
from pybind11_tests.array import (array_fail_test, array_t_fail_test,
|
||||||
|
array_fail_test_negative_size)
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(ValueError) as excinfo:
|
||||||
array_fail_test()
|
array_fail_test()
|
||||||
@ -394,6 +395,10 @@ def test_array_failure():
|
|||||||
array_t_fail_test()
|
array_t_fail_test()
|
||||||
assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'
|
assert str(excinfo.value) == 'cannot create a pybind11::array_t from a nullptr'
|
||||||
|
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
array_fail_test_negative_size()
|
||||||
|
assert str(excinfo.value) == 'negative dimensions are not allowed'
|
||||||
|
|
||||||
|
|
||||||
def test_array_resize(msg):
|
def test_array_resize(msg):
|
||||||
from pybind11_tests.array import (array_reshape2, array_resize3)
|
from pybind11_tests.array import (array_reshape2, array_resize3)
|
||||||
|
@ -149,7 +149,7 @@ py::array_t<StringStruct, 0> create_string_array(bool non_empty) {
|
|||||||
if (non_empty) {
|
if (non_empty) {
|
||||||
auto req = arr.request();
|
auto req = arr.request();
|
||||||
auto ptr = static_cast<StringStruct*>(req.ptr);
|
auto ptr = static_cast<StringStruct*>(req.ptr);
|
||||||
for (size_t i = 0; i < req.size * req.itemsize; i++)
|
for (ssize_t i = 0; i < req.size * req.itemsize; i++)
|
||||||
static_cast<char*>(req.ptr)[i] = 0;
|
static_cast<char*>(req.ptr)[i] = 0;
|
||||||
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
|
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
|
||||||
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
|
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
|
||||||
@ -178,7 +178,7 @@ py::list print_recarray(py::array_t<S, 0> arr) {
|
|||||||
const auto req = arr.request();
|
const auto req = arr.request();
|
||||||
const auto ptr = static_cast<S*>(req.ptr);
|
const auto ptr = static_cast<S*>(req.ptr);
|
||||||
auto l = py::list();
|
auto l = py::list();
|
||||||
for (size_t i = 0; i < req.size; i++) {
|
for (ssize_t i = 0; i < req.size; i++) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << ptr[i];
|
ss << ptr[i];
|
||||||
l.append(py::str(ss.str()));
|
l.append(py::str(ss.str()));
|
||||||
@ -225,7 +225,7 @@ py::array_t<int32_t, 0> test_array_ctors(int i) {
|
|||||||
using arr_t = py::array_t<int32_t, 0>;
|
using arr_t = py::array_t<int32_t, 0>;
|
||||||
|
|
||||||
std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 };
|
std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 };
|
||||||
std::vector<size_t> shape { 3, 2 };
|
std::vector<ssize_t> shape { 3, 2 };
|
||||||
std::vector<ssize_t> strides { 8, 4 };
|
std::vector<ssize_t> strides { 8, 4 };
|
||||||
|
|
||||||
auto ptr = data.data();
|
auto ptr = data.data();
|
||||||
|
@ -50,8 +50,8 @@ test_initializer numpy_vectorize([](py::module &m) {
|
|||||||
py::array_t<float, py::array::forcecast> arg2,
|
py::array_t<float, py::array::forcecast> arg2,
|
||||||
py::array_t<double, py::array::forcecast> arg3
|
py::array_t<double, py::array::forcecast> arg3
|
||||||
) {
|
) {
|
||||||
size_t ndim;
|
ssize_t ndim;
|
||||||
std::vector<size_t> shape;
|
std::vector<ssize_t> shape;
|
||||||
std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
|
std::array<py::buffer_info, 3> buffers {{ arg1.request(), arg2.request(), arg3.request() }};
|
||||||
return py::detail::broadcast(buffers, ndim, shape);
|
return py::detail::broadcast(buffers, ndim, shape);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user