Skip to content

Commit

Permalink
Add gtest testing
Browse files Browse the repository at this point in the history
  • Loading branch information
SylvainCorlay committed Mar 31, 2017
1 parent 7ea59cc commit a95cde3
Show file tree
Hide file tree
Showing 18 changed files with 1,348 additions and 130 deletions.
3 changes: 1 addition & 2 deletions .appveyor.yml
Expand Up @@ -23,9 +23,8 @@ install:
- conda update -q conda
- conda info -a
- conda install pytest -c conda-forge
- cd test
- conda install xtensor==0.8.0 pytest numpy pybind11==2.1.0 -c conda-forge
- xcopy /S %APPVEYOR_BUILD_FOLDER%\include %MINICONDA%\include

build_script:
- py.test .
- py.test -s
10 changes: 10 additions & 0 deletions .gitignore
Expand Up @@ -30,6 +30,16 @@
# Vim tmp files
*.swp

# Build directory
build/

# Test build artefacts
test/test_xtensor_python
test/CMakeCache.txt
test/Makefile
test/CMakeFiles/
test/cmake_install.cmake

# Documentation build artefacts
docs/CMakeCache.txt
docs/xml/
Expand Down
4 changes: 2 additions & 2 deletions .travis.yml
Expand Up @@ -67,7 +67,6 @@ install:
- conda update -q conda
# Useful for debugging any issues with conda
- conda info -a
- cd test
- conda install xtensor==0.8.0 pytest numpy pybind11==2.1.0 -c conda-forge
- cp -r $TRAVIS_BUILD_DIR/include/* $HOME/miniconda/include/

Expand All @@ -84,4 +83,5 @@ script:
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
export CXX=clang++ CC=clang;
fi
- py.test .
- py.test -s

19 changes: 8 additions & 11 deletions CMakeLists.txt
Expand Up @@ -43,25 +43,22 @@ set(XTENSOR_PYTHON_HEADERS
)

if(BUILD_TESTS)

include_directories(${XTENSOR_PYTHON_INCLUDE_DIR})
find_package(xtensor REQUIRED)
include_directories(${xtensor_INCLUDE_DIR})
find_package(NumPy REQUIRED)
include_directories(${NUMPY_INCLUDE_DIRS})

#TODO replace this with a find_package(pybind11 REQUIRED)
# in parent CMakeLists when pybind11 CMakeLists has been fixed.
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
find_package(pybind11 REQUIRED)
include_directories(${pybind11_INCLUDE_DIRS})

if(MSVC)
set(PYTHON_MODULE_EXTENSION ".pyd")
else()
set(PYTHON_MODULE_EXTENSION ".so")
endif()
if(MSVC)
set(PYTHON_MODULE_EXTENSION ".pyd")
else()
set(PYTHON_MODULE_EXTENSION ".so")
endif()

#add_subdirectory(test)
add_subdirectory(test)
add_subdirectory(benchmark)
endif()

Expand Down
49 changes: 22 additions & 27 deletions benchmark/main.cpp
Expand Up @@ -23,42 +23,37 @@ PYBIND11_PLUGIN(benchmark_xtensor_python)
py::module m("benchmark_xtensor_python", "Benchmark module for xtensor python bindings");

m.def("sum_array", [](xt::pyarray<double> const& x) {
double sum = 0;
for(auto e : x)
sum += e;
return sum;
}
);
double sum = 0;
for(auto e : x)
sum += e;
return sum;
});

m.def("sum_tensor", [](xt::pytensor<double, 1> const& x) {
double sum = 0;
for(auto e : x)
sum += e;
return sum;
}
);
double sum = 0;
for(auto e : x)
sum += e;
return sum;
});

m.def("pybind_sum_array", [](py::array_t<double> const& x) {
double sum = 0;
size_t size = x.size();
const double* data = x.data(0);
for(size_t i = 0; i < size; ++i)
sum += data[i];
return sum;
}
);
double sum = 0;
size_t size = x.size();
const double* data = x.data(0);
for(size_t i = 0; i < size; ++i)
sum += data[i];
return sum;
});

m.def("rect_to_polar", [](xt::pyarray<complex_t> const& a) {
return py::make_tuple(xt::pyvectorize([](complex_t x) { return std::abs(x); })(a),
xt::pyvectorize([](complex_t x) { return std::arg(x); })(a));
return py::vectorize([](complex_t x) { return std::abs(x); })(a);
});

m.def("pybind_rect_to_polar", [](py::array a) {
if (py::isinstance<py::array_t<complex_t>>(a))
return py::make_tuple(py::vectorize([](complex_t x) { return std::abs(x); })(a),
py::vectorize([](complex_t x) { return std::arg(x); })(a));
else
throw py::type_error("rect_to_polar unhandled type");
if (py::isinstance<py::array_t<complex_t>>(a))
return py::vectorize([](complex_t x) { return std::abs(x); })(a);
else
throw py::type_error("rect_to_polar unhandled type");
});

return m.ptr();
Expand Down
57 changes: 50 additions & 7 deletions include/xtensor-python/pyarray.hpp
Expand Up @@ -76,6 +76,8 @@ namespace xt

value_type operator[](size_type i) const;

size_type size() const;

private:

const array_type* p_a;
Expand Down Expand Up @@ -108,14 +110,15 @@ namespace xt
class pyarray : public pycontainer<pyarray<T>>,
public xcontainer_semantic<pyarray<T>>
{

public:

using self_type = pyarray<T>;
using semantic_base = xcontainer_semantic<self_type>;
using base_type = pycontainer<self_type>;
using container_type = typename base_type::container_type;
using value_type = typename base_type::value_type;
using reference = typename base_type::reference;
using const_reference = typename base_type::const_reference;
using pointer = typename base_type::pointer;
using size_type = typename base_type::size_type;
using shape_type = typename base_type::shape_type;
Expand All @@ -125,7 +128,9 @@ namespace xt
using inner_strides_type = typename base_type::inner_strides_type;
using inner_backstrides_type = typename base_type::inner_backstrides_type;

pyarray() = default;
pyarray();
pyarray(const self_type&) = default;
pyarray(self_type&&) = default;
pyarray(const value_type& t);
pyarray(nested_initializer_list_t<T, 1> t);
pyarray(nested_initializer_list_t<T, 2> t);
Expand All @@ -138,11 +143,16 @@ namespace xt
pyarray(const pybind11::object &o);

explicit pyarray(const shape_type& shape, layout l = layout::row_major);
pyarray(const shape_type& shape, const strides_type& strides);
explicit pyarray(const shape_type& shape, const_reference value, layout l = layout::row_major);
explicit pyarray(const shape_type& shape, const strides_type& strides, const_reference value);
explicit pyarray(const shape_type& shape, const strides_type& strides);

template <class E>
pyarray(const xexpression<E>& e);

self_type& operator=(const self_type& e) = default;
self_type& operator=(self_type&& e) = default;

template <class E>
self_type& operator=(const xexpression<E>& e);

Expand Down Expand Up @@ -182,6 +192,12 @@ namespace xt
{
}

template <class A>
inline auto pyarray_backstrides<A>::size() const -> size_type
{
return p_a->dimension();
}

template <class A>
inline auto pyarray_backstrides<A>::operator[](size_type i) const -> value_type
{
Expand All @@ -194,6 +210,16 @@ namespace xt
* pyarray implementation *
**************************/

template <class T>
inline pyarray<T>::pyarray()
{
// TODO: avoid allocation
shape_type shape = make_sequence<shape_type>(0, size_type(1));
strides_type strides = make_sequence<strides_type>(0, size_type(0));
init_array(shape, strides);
m_data[0] = T();
}

template <class T>
inline pyarray<T>::pyarray(const value_type& t)
{
Expand Down Expand Up @@ -260,9 +286,25 @@ namespace xt
template <class T>
inline pyarray<T>::pyarray(const shape_type& shape, layout l)
{
strides_type strides;
strides_type strides(shape.size());
compute_strides(shape, l, strides);
init_array(shape, strides);
}

template <class T>
inline pyarray<T>::pyarray(const shape_type& shape, const_reference value, layout l)
{
strides_type strides(shape.size());
compute_strides(shape, l, strides);
init_array(shape, strides);
std::fill(m_data.begin(), m_data.end(), value);
}

template <class T>
inline pyarray<T>::pyarray(const shape_type& shape, const strides_type& strides, const_reference value)
{
init_array(shape, strides);
std::fill(m_data.begin(), m_data.end(), value);
}

template <class T>
Expand Down Expand Up @@ -306,7 +348,7 @@ namespace xt
[](auto v) { return sizeof(T) * v; });

int flags = NPY_ARRAY_ALIGNED;
if(!std::is_const<T>::value)
if (!std::is_const<T>::value)
{
flags |= NPY_ARRAY_WRITEABLE;
}
Expand All @@ -319,8 +361,10 @@ namespace xt
nullptr, static_cast<int>(sizeof(T)), flags, nullptr)
);

if(!tmp)
if (!tmp)
{
throw std::runtime_error("NumPy: unable to create ndarray");
}

this->m_ptr = tmp.release().ptr();
init_from_python();
Expand Down Expand Up @@ -370,7 +414,6 @@ namespace xt
{
return m_data;
}

}

#endif
Expand Down
51 changes: 43 additions & 8 deletions include/xtensor-python/pycontainer.hpp
Expand Up @@ -17,16 +17,39 @@
#include "pybind11/common.h"
#include "pybind11/complex.h"

#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "numpy/arrayobject.h"

#include "xtensor/xcontainer.hpp"

namespace xt
{
static bool is_numpy_imported = false;

class numpy_import
{
protected:

inline numpy_import()
{
if (!is_numpy_imported)
{
_import_array();
is_numpy_imported = true;
}
}

numpy_import(const numpy_import&) = default;
numpy_import(numpy_import&&) = default;
numpy_import& operator=(const numpy_import&) = default;
numpy_import& operator=(numpy_import&&) = default;
};

template <class D>
class pycontainer : public pybind11::object,
public xcontainer<D>
public xcontainer<D>,
private numpy_import
{

public:

using derived_type = D;
Expand Down Expand Up @@ -64,12 +87,13 @@ namespace xt
void reshape(const shape_type& shape, const strides_type& strides);

using base_type::operator();
using base_type::operator[];
using base_type::begin;
using base_type::end;

protected:

pycontainer() = default;
pycontainer();
~pycontainer() = default;

pycontainer(pybind11::handle h, borrowed_t);
Expand Down Expand Up @@ -116,6 +140,12 @@ namespace xt
* pycontainer implementation *
******************************/

template <class D>
inline pycontainer<D>::pycontainer()
: pybind11::object()
{
}

template <class D>
inline pycontainer<D>::pycontainer(pybind11::handle h, borrowed_t)
: pybind11::object(h, borrowed)
Expand All @@ -132,16 +162,20 @@ namespace xt
inline pycontainer<D>::pycontainer(const pybind11::object& o)
: pybind11::object(raw_array_t(o.ptr()), pybind11::object::stolen)
{
if(!this->m_ptr)
if (!this->m_ptr)
{
throw pybind11::error_already_set();
}
}

template <class D>
inline auto pycontainer<D>::ensure(pybind11::handle h) -> derived_type
{
auto result = pybind11::reinterpret_steal<derived_type>(raw_array_t(h.ptr()));
if(result.ptr() == nullptr)
if (result.ptr() == nullptr)
{
PyErr_Clear();
}
return result;
}

Expand All @@ -156,9 +190,10 @@ namespace xt
template <class D>
inline PyObject* pycontainer<D>::raw_array_t(PyObject* ptr)
{
if(ptr == nullptr)
if (ptr == nullptr)
{
return nullptr;

}
int type_num = detail::numpy_traits<value_type>::type_num;
auto res = PyArray_FromAny(ptr, PyArray_DescrFromType(type_num), 0, 0,
NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_FORCECAST, nullptr);
Expand All @@ -174,7 +209,7 @@ namespace xt
template <class D>
inline void pycontainer<D>::reshape(const shape_type& shape)
{
if(shape.size() != this->dimension() || !std::equal(shape.begin(), shape.end(), this->shape().begin()))
if (shape.size() != this->dimension() || !std::equal(shape.begin(), shape.end(), this->shape().begin()))
{
reshape(shape, layout::row_major);
}
Expand Down

0 comments on commit a95cde3

Please sign in to comment.