12#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
13static_assert(__GNUC__ > 5,
"Eigen Tensor support in pybind11 requires GCC > 5.0");
20#if defined(__MINGW32__)
24#include <unsupported/Eigen/CXX11/Tensor>
28static_assert(EIGEN_VERSION_AT_LEAST(3, 3, 0),
29 "Eigen Tensor support in pybind11 requires Eigen >= 3.3.0");
38 return (
reinterpret_cast<std::size_t
>(
data) % EIGEN_DEFAULT_ALIGN_BYTES) == 0;
43 static_assert((
static_cast<int>(T::Layout) ==
static_cast<int>(Eigen::RowMajor))
44 || (
static_cast<int>(T::Layout) ==
static_cast<int>(Eigen::ColMajor)),
45 "Layout must be row or column major");
46 return (
static_cast<int>(T::Layout) ==
static_cast<int>(Eigen::RowMajor)) ?
array::c_style
53template <
typename Scalar_,
int NumIndices_,
int Options_,
typename IndexType>
55 using Type = Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>;
58 static Eigen::DSizes<typename Type::Index, Type::NumIndices>
get_shape(
const Type &f) {
59 return f.dimensions();
70 template <
size_t... Is>
75 static constexpr auto dimensions_descriptor
76 = helper<decltype(make_index_sequence<Type::NumIndices>())>::value;
78 template <
typename... Args>
80 return new Type(std::forward<Args>(
args)...);
83 static void free(
Type *tensor) {
delete tensor; }
86template <
typename Scalar_,
typename std::ptrdiff_t... Indices,
int Options_,
typename IndexType>
88 Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>> {
89 using Type = Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>;
92 static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices>
97 static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices>
get_shape() {
98 return Eigen::DSizes<typename Type::Index, Type::NumIndices>(Indices...);
103 return get_shape() == shape;
106 static constexpr auto dimensions_descriptor =
concat(const_name<Indices>()...);
108 template <
typename... Args>
110 Eigen::aligned_allocator<Type> allocator;
111 return ::new (allocator.allocate(1))
Type(std::forward<Args>(
args)...);
115 Eigen::aligned_allocator<Type> allocator;
117 allocator.deallocate(tensor, 1);
121template <
typename Type,
bool ShowDetails,
bool NeedsWriteable = false>
124 = const_name<NeedsWriteable>(
", flags.writeable",
"")
125 + const_name<static_cast<int>(Type::Layout) ==
static_cast<int>(Eigen::RowMajor)>(
126 ", flags.c_contiguous",
", flags.f_contiguous");
141template <typename T,
int size>
143 std::vector<T> result(size);
145 for (
size_t i = 0; i < size; i++) {
152template <
typename T,
int size>
154 Eigen::DSizes<T, size> result;
155 const T *shape =
arr.shape();
156 for (
size_t i = 0; i < size; i++) {
157 result[i] = shape[i];
165template <
typename Type>
173 if (!isinstance<array>(src)) {
181 if (!temp.
dtype().is(dtype::of<typename Type::Scalar>())) {
187 reinterpret_borrow<object>(src));
189 if (
arr.ndim() != Type::NumIndices) {
192 auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(
arr);
194 if (!Helper::is_correct_shape(shape)) {
198#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
199 auto data_pointer =
arr.data();
202 auto data_pointer =
const_cast<typename Type::Scalar *
>(
arr.data());
206 value = Eigen::TensorMap<const Type, Eigen::Aligned>(data_pointer, shape);
208 value = Eigen::TensorMap<const Type>(data_pointer, shape);
215 if (policy == return_value_policy::reference
216 || policy == return_value_policy::reference_internal) {
217 pybind11_fail(
"Cannot use a reference return value policy for an rvalue");
219 return cast_impl(&src, return_value_policy::move, parent);
223 if (policy == return_value_policy::reference
224 || policy == return_value_policy::reference_internal) {
225 pybind11_fail(
"Cannot use a reference return value policy for an rvalue");
227 return cast_impl(&src, return_value_policy::move, parent);
231 if (policy == return_value_policy::automatic
232 || policy == return_value_policy::automatic_reference) {
233 policy = return_value_policy::copy;
235 return cast_impl(&src, policy, parent);
239 if (policy == return_value_policy::automatic
240 || policy == return_value_policy::automatic_reference) {
241 policy = return_value_policy::copy;
243 return cast(&src, policy, parent);
247 if (policy == return_value_policy::automatic) {
248 policy = return_value_policy::take_ownership;
249 }
else if (policy == return_value_policy::automatic_reference) {
250 policy = return_value_policy::reference;
252 return cast_impl(src, policy, parent);
256 if (policy == return_value_policy::automatic) {
257 policy = return_value_policy::take_ownership;
258 }
else if (policy == return_value_policy::automatic_reference) {
259 policy = return_value_policy::reference;
261 return cast_impl(src, policy, parent);
264 template <
typename C>
266 object parent_object;
267 bool writeable =
false;
269 case return_value_policy::move:
270 if (std::is_const<C>::value) {
274 src = Helper::alloc(std::move(*src));
277 =
capsule(src, [](
void *ptr) { Helper::free(
reinterpret_cast<Type *
>(ptr)); });
281 case return_value_policy::take_ownership:
282 if (std::is_const<C>::value) {
285 Helper::free(
const_cast<Type *
>(src));
290 =
capsule(src, [](
void *ptr) { Helper::free(
reinterpret_cast<Type *
>(ptr)); });
294 case return_value_policy::copy:
298 case return_value_policy::reference:
299 parent_object =
none();
300 writeable = !std::is_const<C>::value;
303 case return_value_policy::reference_internal:
306 pybind11_fail(
"Cannot use reference internal when there is no parent");
308 parent_object = reinterpret_borrow<object>(parent);
309 writeable = !std::is_const<C>::value;
313 pybind11_fail(
"pybind11 bug in eigen.h, please file a bug report");
323 return result.release();
327template <
typename StoragePointerType,
328 bool needs_writeable,
331#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
332 return reinterpret_cast<StoragePointerType
>(
arr.data());
335 return reinterpret_cast<StoragePointerType
>(
const_cast<void *
>(
arr.data()));
339template <
typename StoragePointerType,
340 bool needs_writeable,
343 return reinterpret_cast<StoragePointerType
>(
arr.mutable_data());
346template <
typename T,
typename =
void>
349template <
typename MapType>
351 using SPT =
typename MapType::StoragePointerType;
354template <
typename MapType>
356 using SPT =
typename MapType::PointerArgType;
359template <
typename Type,
int Options>
362 using MapType = Eigen::TensorMap<Type, Options>;
367 if (!isinstance<array>(src)) {
370 auto arr = reinterpret_borrow<array>(src);
371 if ((
arr.flags() & compute_array_flag_from_tensor<Type>()) == 0) {
375 if (!
arr.dtype().is(dtype::of<typename Type::Scalar>())) {
379 if (
arr.ndim() != Type::NumIndices) {
383 constexpr bool is_aligned = (Options & Eigen::Aligned) != 0;
389 auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(
arr);
391 if (!Helper::is_correct_shape(shape)) {
395 if (needs_writeable && !
arr.writeable()) {
399 auto result = get_array_data_for_type<typename get_storage_pointer_type<MapType>::SPT,
400 needs_writeable>(
arr);
402 value.reset(
new MapType(std::move(result), std::move(shape)));
408 return cast_impl(&src, policy, parent);
412 return cast_impl(&src, policy, parent);
416 if (policy == return_value_policy::automatic
417 || policy == return_value_policy::automatic_reference) {
418 policy = return_value_policy::copy;
420 return cast_impl(&src, policy, parent);
424 if (policy == return_value_policy::automatic
425 || policy == return_value_policy::automatic_reference) {
426 policy = return_value_policy::copy;
428 return cast(&src, policy, parent);
432 if (policy == return_value_policy::automatic) {
433 policy = return_value_policy::take_ownership;
434 }
else if (policy == return_value_policy::automatic_reference) {
435 policy = return_value_policy::reference;
437 return cast_impl(src, policy, parent);
441 if (policy == return_value_policy::automatic) {
442 policy = return_value_policy::take_ownership;
443 }
else if (policy == return_value_policy::automatic_reference) {
444 policy = return_value_policy::reference;
446 return cast_impl(src, policy, parent);
449 template <
typename C>
451 object parent_object;
452 constexpr bool writeable = !std::is_const<C>::value;
454 case return_value_policy::reference:
455 parent_object =
none();
458 case return_value_policy::reference_internal:
461 pybind11_fail(
"Cannot use reference internal when there is no parent");
463 parent_object = reinterpret_borrow<object>(parent);
466 case return_value_policy::take_ownership:
471 pybind11_fail(
"Invalid return_value_policy for Eigen Map type, must be either "
472 "reference or reference_internal");
478 std::move(parent_object));
484 return result.release();
487#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
489 static constexpr bool needs_writeable = !std::is_const<
typename std::remove_pointer<
493 static constexpr bool needs_writeable = !std::is_const<Type>::value;
506 template <
typename T_>
pybind11::dtype dtype() const
Array descriptor (dtype)
static array ensure(handle h, int ExtraFlags=0)
Ensure that the argument is a NumPy array In case of an error, nullptr is returned and the Python err...
\rst Holds a reference to a Python object (no reference counting)
static handle cast(const itype &src, return_value_policy policy, handle parent)
typename std::enable_if< B, T >::type enable_if_t
from cpp_future import (convenient aliases from C++14/17)
PYBIND11_NOINLINE void pybind11_fail(const char *reason)
Thrown when pybind11::cast or.
#define PYBIND11_NAMESPACE_END(name)
#define PYBIND11_NAMESPACE_BEGIN(name)
typename void_t_impl< Ts... >::type void_t
return_value_policy
Approach used to cast a previously unknown C++ instance into a Python object.
constexpr descr< N - 1 > const_name(char const (&text)[N])
constexpr descr< 0 > concat()
PyArray_Proxy * array_proxy(void *ptr)
arr data(const arr &a, Ix... index)
#define PYBIND11_WARNING_DISABLE_GCC(name)
#define PYBIND11_WARNING_DISABLE_MSVC(name)
static void free(Type *tensor)
Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType > Type
static Eigen::DSizes< typename Type::Index, Type::NumIndices > get_shape(const Type &f)
static constexpr bool is_correct_shape(const Eigen::DSizes< typename Type::Index, Type::NumIndices > &)
static Type * alloc(Args &&...args)
static constexpr Eigen::DSizes< typename Type::Index, Type::NumIndices > get_shape()
static void free(Type *tensor)
static bool is_correct_shape(const Eigen::DSizes< typename Type::Index, Type::NumIndices > &shape)
Eigen::TensorFixedSize< Scalar_, Eigen::Sizes< Indices... >, Options_, IndexType > Type
static Type * alloc(Args &&...args)
static constexpr Eigen::DSizes< typename Type::Index, Type::NumIndices > get_shape(const Type &)
typename MapType::PointerArgType SPT
typename MapType::StoragePointerType SPT
static constexpr auto details
static constexpr auto value
Annotation for function names.
static handle cast_impl(C *src, return_value_policy policy, handle parent)
static handle cast(const MapType *src, return_value_policy policy, handle parent)
static handle cast(MapType &src, return_value_policy policy, handle parent)
static handle cast(const MapType &&src, return_value_policy policy, handle parent)
::pybind11::detail::movable_cast_op_type< T_ > cast_op_type
static handle cast(MapType *src, return_value_policy policy, handle parent)
static handle cast(MapType &&src, return_value_policy policy, handle parent)
std::unique_ptr< MapType > value
bool load(handle src, bool)
Eigen::TensorMap< Type, Options > MapType
static handle cast(const MapType &src, return_value_policy policy, handle parent)
static handle cast(Type &src, return_value_policy policy, handle parent)
static handle cast(Type *src, return_value_policy policy, handle parent)
bool load(handle src, bool convert)
static handle cast(Type &&src, return_value_policy policy, handle parent)
static handle cast(const Type &src, return_value_policy policy, handle parent)
static handle cast(const Type *src, return_value_policy policy, handle parent)
PYBIND11_TYPE_CASTER(Type, temp_name)
static handle cast_impl(C *src, return_value_policy policy, handle parent)
static handle cast(const Type &&src, return_value_policy policy, handle parent)
StoragePointerType get_array_data_for_type(array &arr)
bool is_tensor_aligned(const void *data)
Eigen::DSizes< T, size > get_shape_for_array(const array &arr)
PYBIND11_WARNING_PUSH std::vector< T > convert_dsizes_to_vector(const Eigen::DSizes< T, size > &arr)
constexpr int compute_array_flag_from_tensor()
PYBIND11_WARNING_PUSH PYBIND11_WARNING_POP