Skip to content

Make py::vectorize() ignore non-vectorizable arguments & support member functions #762

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

Merged
merged 4 commits into from
May 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions docs/advanced/pycpp/numpy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -239,27 +239,13 @@ by the compiler. The result is returned as a NumPy array of type
The scalar argument ``z`` is transparently replicated 4 times. The input
arrays ``x`` and ``y`` are automatically converted into the right types (they
are of type ``numpy.dtype.int64`` but need to be ``numpy.dtype.int32`` and
``numpy.dtype.float32``, respectively)
``numpy.dtype.float32``, respectively).

Sometimes we might want to explicitly exclude an argument from the vectorization
because it makes little sense to wrap it in a NumPy array. For instance,
suppose the function signature was
.. note::

.. code-block:: cpp

double my_func(int x, float y, my_custom_type *z);

This can be done with a stateful Lambda closure:

.. code-block:: cpp

// Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization)
m.def("vectorized_func",
[](py::array_t<int> x, py::array_t<float> y, my_custom_type *z) {
auto stateful_closure = [z](int x, float y) { return my_func(x, y, z); };
return py::vectorize(stateful_closure)(x, y);
}
);
Only arithmetic, complex, and POD types passed by value or by ``const &``
reference are vectorized; all other arguments are passed through as-is.
Functions taking rvalue reference arguments cannot be vectorized.

In cases where the computation is too complicated to be reduced to
``vectorize``, it will be necessary to create and access the buffer contents
Expand Down
5 changes: 3 additions & 2 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "descr.h"
#include <array>
#include <limits>
#include <tuple>

NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
Expand Down Expand Up @@ -390,7 +391,7 @@ class type_caster_generic {
*/
template <typename T>
using cast_op_type =
conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
conditional_t<std::is_pointer<remove_reference_t<T>>::value,
typename std::add_pointer<intrinsic_t<T>>::type,
typename std::add_lvalue_reference<intrinsic_t<T>>::type>;

Expand Down Expand Up @@ -883,7 +884,7 @@ template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type
}

static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); }
template <typename _T> using cast_op_type = typename std::remove_reference<pybind11::detail::cast_op_type<_T>>::type;
template <typename _T> using cast_op_type = remove_reference_t<pybind11::detail::cast_op_type<_T>>;
};

template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
Expand Down
16 changes: 16 additions & 0 deletions include/pybind11/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,12 @@ inline internals &get_internals();
using std::enable_if_t;
using std::conditional_t;
using std::remove_cv_t;
using std::remove_reference_t;
#else
template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
template <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
template <typename T> using remove_reference_t = typename std::remove_reference<T>::type;
#endif

/// Index sequences
Expand All @@ -365,6 +367,12 @@ template<size_t ...S> struct make_index_sequence_impl <0, S...> { typedef index_
template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type;
#endif

/// Make an index sequence of the indices of true arguments
template <typename ISeq, size_t, bool...> struct select_indices_impl { using type = ISeq; };
template <size_t... IPrev, size_t I, bool B, bool... Bs> struct select_indices_impl<index_sequence<IPrev...>, I, B, Bs...>
: select_indices_impl<conditional_t<B, index_sequence<IPrev..., I>, index_sequence<IPrev...>>, I + 1, Bs...> {};
template <bool... Bs> using select_indices = typename select_indices_impl<index_sequence<>, 0, Bs...>::type;

/// Backports of std::bool_constant and std::negation to accomodate older compilers
template <bool B> using bool_constant = std::integral_constant<bool, B>;
template <typename T> struct negation : bool_constant<!T::value> { };
Expand Down Expand Up @@ -504,6 +512,14 @@ struct is_input_iterator<T, void_t<decltype(*std::declval<T &>()), decltype(++st
/// Ignore that a variable is unused in compiler warnings
inline void ignore_unused(const int *) { }

/// Apply a function over each element of a parameter pack
#ifdef __cpp_fold_expressions
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea!

#else
using expand_side_effects = bool[];
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) pybind11::detail::expand_side_effects{ ((PATTERN), void(), false)..., false }
#endif

NAMESPACE_END(detail)

/// Returns a named pointer that is shared among all extension modules (using the same
Expand Down
2 changes: 1 addition & 1 deletion include/pybind11/eigen.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
template<typename Type>
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
typedef typename Type::Scalar Scalar;
typedef typename std::remove_reference<decltype(*std::declval<Type>().outerIndexPtr())>::type StorageIndex;
typedef remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())> StorageIndex;
typedef typename Type::Index Index;
static constexpr bool rowMajor = Type::IsRowMajor;

Expand Down
Loading