Skip to content

Commit

Permalink
Adding isin and in1d
Browse files Browse the repository at this point in the history
  • Loading branch information
tdegeus committed Apr 17, 2020
1 parent f471b65 commit 0df4cd1
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ set(XTENSOR_HEADERS
${XTENSOR_INCLUDE_DIR}/xtensor/xrepeat.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xscalar.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xsemantic.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xset_operation.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xshape.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xslice.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xsort.hpp
Expand Down
4 changes: 4 additions & 0 deletions docs/source/numpy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ where ``condition`` is falsy, and it does not evaluate ``b`` where ``condition``
+-----------------------------------------------+-----------------------------------------------+
| ``np.all(a)`` | ``xt::all(a)`` |
+-----------------------------------------------+-----------------------------------------------+
| ``np.isin(a, b)`` | ``xt::isin(a, b)`` |
+-----------------------------------------------+-----------------------------------------------+
| ``np.in1d(a, b)`` | ``xt::in1d(a, b)`` |
+-----------------------------------------------+-----------------------------------------------+
| ``np.logical_and(a, b)`` | ``a && b`` |
+-----------------------------------------------+-----------------------------------------------+
| ``np.logical_or(a, b)`` | ``a || b`` |
Expand Down
1 change: 1 addition & 0 deletions include/xtensor/xoperation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,7 @@ namespace xt
{
return detail::make_xfunction<typename detail::cast<R>::functor>(std::forward<E>(e));
}

}

#endif
140 changes: 140 additions & 0 deletions include/xtensor/xset_operation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XTENSOR_XSET_OPERATION_HPP
#define XTENSOR_XSET_OPERATION_HPP

#include <algorithm>
#include <functional>
#include <type_traits>

#include <xtl/xsequence.hpp>

#include "xfunction.hpp"
#include "xutils.hpp"
#include "xscalar.hpp"
#include "xstrides.hpp"
#include "xstrided_view.hpp"
#include "xmath.hpp"

namespace xt
{

/**
* @ingroup logical_operators
* @brief isin
*
* Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
* ``element`` is in ``test_elements`` and ``False`` otherwise.
* @param element an \ref xexpression
* @param test_elements an array
* @return a boolean array
*/
template <class E, class T>
inline auto isin(E&& element, std::initializer_list<T> test_elements) noexcept
{
auto lambda = [test_elements](const auto& t) {
return std::find(test_elements.begin(), test_elements.end(), t) != test_elements.end(); };
return make_lambda_xfunction(std::move(lambda), std::forward<E>(element));
}

/**
* @ingroup logical_operators
* @brief isin
*
* Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
* ``element`` is in ``test_elements`` and ``False`` otherwise.
* @param element an \ref xexpression
* @param test_elements an array
* @return a boolean array
*/
template <class E, class F, class = typename std::enable_if_t<has_iterator_interface<F>::value>>
inline auto isin(E&& element, F&& test_elements) noexcept
{
auto lambda = [&test_elements](const auto& t) {
return std::find(test_elements.begin(), test_elements.end(), t) != test_elements.end(); };
return make_lambda_xfunction(std::move(lambda), std::forward<E>(element));
}

/**
* @ingroup logical_operators
* @brief isin
*
* Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
* ``element`` is in ``test_elements`` and ``False`` otherwise.
* @param element an \ref xexpression
* @param test_elements_begin iterator to the beginning of an array
* @param test_elements_end iterator to the end of an array
* @return a boolean array
*/
template <class E, class I, class = typename std::enable_if_t<is_iterator<I>::value>>
inline auto isin(E&& element, I&& test_elements_begin, I&& test_elements_end) noexcept
{
auto lambda = [&test_elements_begin, &test_elements_end](const auto& t) {
return std::find(test_elements_begin, test_elements_end, t) != test_elements_end; };
return make_lambda_xfunction(std::move(lambda), std::forward<E>(element));
}

/**
* @ingroup logical_operators
* @brief in1d
*
* Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
* ``element`` is in ``test_elements`` and ``False`` otherwise.
* @param element an \ref xexpression
* @param test_elements an array
* @return a boolean array
*/
template <class E, class T>
inline auto in1d(E&& element, std::initializer_list<T> test_elements) noexcept
{
XTENSOR_ASSERT(element.dimension() == 1ul);
return isin(std::forward<E>(element), std::forward<std::initializer_list<T>>(test_elements));
}

/**
* @ingroup logical_operators
* @brief in1d
*
* Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
* ``element`` is in ``test_elements`` and ``False`` otherwise.
* @param element an \ref xexpression
* @param test_elements an array
* @return a boolean array
*/
template <class E, class F, class = typename std::enable_if_t<has_iterator_interface<F>::value>>
inline auto in1d(E&& element, F&& test_elements) noexcept
{
XTENSOR_ASSERT(element.dimension() == 1ul);
XTENSOR_ASSERT(test_elements.dimension() == 1ul);
return isin(std::forward<E>(element), std::forward<F>(test_elements));
}

/**
* @ingroup logical_operators
* @brief in1d
*
* Returns a boolean array of the same shape as ``element`` that is ``true`` where an element of
* ``element`` is in ``test_elements`` and ``False`` otherwise.
* @param element an \ref xexpression
* @param test_elements_begin iterator to the beginning of an array
* @param test_elements_end iterator to the end of an array
* @return a boolean array
*/
template <class E, class I, class = typename std::enable_if_t<is_iterator<I>::value>>
inline auto in1d(E&& element, I&& test_elements_begin, I&& test_elements_end) noexcept
{
XTENSOR_ASSERT(element.dimension() == 1ul);
XTENSOR_ASSERT(test_elements.dimension() == 1ul);
return isin(std::forward<E>(element), std::forward<I>(test_elements_begin), std::forward<I>(test_elements_end));
}

}

#endif
21 changes: 21 additions & 0 deletions include/xtensor/xutils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,27 @@ namespace xt
{
};

/******************************
* is_iterator implementation *
******************************/

template <class E, class = void>
struct is_iterator : std::false_type
{
};

template <class E>
struct is_iterator<E, void_t<decltype(
*std::declval<const E>(),
std::declval<const E>() == std::declval<const E>(),
std::declval<const E>() != std::declval<const E>(),
++ (*std::declval<E*>()),
(*std::declval<E*>()) ++,
std::true_type())>>
: std::true_type
{
};

/********************************************
* xtrivial_default_construct implemenation *
********************************************/
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ set(XTENSOR_TESTS
test_xoptional.cpp
test_xoptional_assembly_adaptor.cpp
test_xoptional_assembly_storage.cpp
test_xset_operation.cpp
test_xrandom.cpp
test_xrepeat.cpp
test_xsort.cpp
Expand Down
1 change: 1 addition & 0 deletions test/test_xoperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -839,4 +839,5 @@ namespace xt
EXPECT_EQ(expected1, res3);
EXPECT_EQ(expected2, res4);
}

}
39 changes: 39 additions & 0 deletions test/test_xset_operation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#include "gtest/gtest.h"

#include <cstddef>

#include "xtensor/xarray.hpp"
#include "xtensor/xtensor.hpp"
#include "xtensor/xset_operation.hpp"

namespace xt
{
TEST(xset_operation, isin)
{
xt::xtensor<int,2> a = {{1, 2, 1}, {0, 3, 1}};
xt::xtensor<int,1> b = {1, 2};
xt::xtensor<bool,2> res = {{true, true, true}, {false, false, true}};
EXPECT_EQ(xt::isin(a, b), res);
EXPECT_EQ(xt::isin(a, b.begin(), b.end()), res);
EXPECT_EQ(xt::isin(a, {1, 2}), res);
}

TEST(xset_operation, in1d)
{
xt::xtensor<int,1> a = {1, 2, 1, 0, 3, 5, 1};
xt::xtensor<int,1> b = {1, 2};
xt::xtensor<bool,1> res = {true, true, true, false, false, false, true};
EXPECT_EQ(xt::in1d(a, b), res);
EXPECT_EQ(xt::in1d(a, b.begin(), b.end()), res);
EXPECT_EQ(xt::in1d(a, {1, 2}), res);
}
}

0 comments on commit 0df4cd1

Please sign in to comment.