diff --git a/CMakeLists.txt b/CMakeLists.txt index e807f5e..ef1df5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,18 +3,22 @@ project(trigdx LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) option(TRIGDX_USE_MKL "Enable Intel MKL backend" OFF) option(TRIGDX_USE_GPU "Enable GPU backend" OFF) option(TRIGDX_USE_XSIMD "Enable XSIMD backend" OFF) option(TRIGDX_BUILD_TESTS "Build tests" ON) option(TRIGDX_BUILD_BENCHMARKS "Build tests" ON) +option(TRIGDX_BUILD_PYTHON "Build Python interface" ON) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/trigdx_config.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/include/trigdx/trigdx_config.hpp @ONLY) -if(TRIGDX_BUILD_TESTS OR TRIGDX_BUILD_BENCHMARKS) +if(TRIGDX_BUILD_TESTS + OR TRIGDX_BUILD_BENCHMARKS + OR TRIGDX_BUILD_PYTHON) include(FetchContent) endif() @@ -31,3 +35,7 @@ endif() if(TRIGDX_BUILD_BENCHMARKS) add_subdirectory(benchmarks) endif() + +if(TRIGDX_BUILD_PYTHON) + add_subdirectory(python) +endif() diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt new file mode 100644 index 0000000..81e1494 --- /dev/null +++ b/python/CMakeLists.txt @@ -0,0 +1,8 @@ +FetchContent_Declare( + pybind11 + GIT_REPOSITORY https://github.com/pybind/pybind11.git + GIT_TAG v3.0.0) +FetchContent_MakeAvailable(pybind11) + +pybind11_add_module(pytrigdx bindings.cpp) +target_link_libraries(pytrigdx PRIVATE trigdx) diff --git a/python/bindings.cpp b/python/bindings.cpp new file mode 100644 index 0000000..c8153df --- /dev/null +++ b/python/bindings.cpp @@ -0,0 +1,94 @@ +#include + +#include +#include +#include + +namespace py = pybind11; + +template +py::array_t +compute_sin(const Backend &backend, + py::array_t x) { + const size_t n = x.shape(0); + if (x.ndim() != 1) { + throw py::value_error("Input array must be 1-dimensional"); + } + + const T *x_ptr = x.data(); + + py::array_t s(n); + T *s_ptr = s.mutable_data(); + + backend.compute_sinf(n, x_ptr, s_ptr); + + return s; +} + +template +py::array_t +compute_cos(const Backend &backend, + py::array_t x) { + const size_t n = x.shape(0); + if (x.ndim() != 1) { + throw py::value_error("Input array must be 1-dimensional"); + } + + const T *x_ptr = x.data(); + + py::array_t c(n); + T *c_ptr = c.mutable_data(); + + backend.compute_cosf(n, x_ptr, c_ptr); + + return c; +} + +template +std::tuple, py::array_t> +compute_sincos(const Backend &backend, + py::array_t x) { + const size_t n = x.shape(0); + if (x.ndim() != 1) { + throw py::value_error("Input array must be 1-dimensional"); + } + + const T *x_ptr = x.data(); + + py::array_t s(n); + py::array_t c(n); + + backend.compute_sincosf(n, x_ptr, s.mutable_data(), c.mutable_data()); + + return std::make_tuple(s, c); +} + +template +void bind_backend(py::module &m, const char *name) { + py::class_>(m, name) + .def(py::init<>()) + .def("compute_sinf", &compute_sin) + .def("compute_cosf", &compute_cos) + .def("compute_sincosf", &compute_sincos); +} + +PYBIND11_MODULE(pytrigdx, m) { + py::class_>(m, "Backend") + .def("init", &Backend::init); + + bind_backend(m, "Reference"); + bind_backend>(m, "Lookup16K"); + bind_backend>(m, "Lookup32K"); + bind_backend>(m, "LookupAVX16K"); + bind_backend>(m, "LookupAVX32K"); +#if defined(TRIGDX_USE_MKL) + bind_backend(m, "MKL"); +#endif +#if defined(TRIGDX_USE_GPU) + bind_backend(m, "GPU"); +#endif +#if defined(TRIGDX_USE_XSIMD) + bind_backend>(m, "LookupXSIMD16K"); + bind_backend>(m, "LookupXSIMD32K"); +#endif +} \ No newline at end of file