Skip to content
Snippets Groups Projects
conversion_utils.hpp 5.52 KiB
/** @file python/conversion_utils.hpp
 *  @brief A set of functions to convert std::vectors to and from python objects
 *
 *  @author Thomas A. R. Purcell (tpurcell)
 *  @bug No known bugs.
 */
#ifndef UTILS_CONVERSION
#define UTILS_CONVERSION

#include <algorithm>
#include <array>
#include <vector>
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>

#include <iostream>

namespace python_conv_utils
{
    namespace py = boost::python;
    namespace np = boost::python::numpy;

    /**
     * @brief Convert a python list object to a std::vector
     *
     * @param lst python list to convert to a std::vector
     * @tparam T type of objects inside the list
     * @return A vector of the python list
     */
    template<typename T>
    std::vector<T> from_list(py::list lst)
    {
        std::vector<T> vec(py::len(lst));
        for(int ll = 0; ll < vec.size(); ++ll)
            vec[ll] = py::extract<T>(lst[ll]);
        return vec;
    }

    /**
     * @brief Convert a numpy array object to a std::vector
     *
     * @param lst numpy array to convert to a std::vector
     * @tparam T type of objects inside the numpy array
     * @return A vector of the numpy array
     */
    template<typename T>
    std::vector<T> from_ndarray(np::ndarray arr)
    {
        if(arr.get_dtype() != np::dtype::get_builtin<T>())
            throw std::logic_error("arr is not of the correct type.");

        std::vector<T> vec(arr.shape(0));
        for(int ii = 0; ii < arr.shape(0); ++ii)
            vec[ii] = py::extract<T>(arr[ii]);

        return vec;
    }

    /**
     * @brief Convert a python list object to a std::array
     *
     * @param lst python list to convert to a std::vector
     * @tparam T type of objects inside the list
     * @tparam N the size of the array
     * @return An array from the python list of the python list
     */
    template<typename T, size_t N>
    std::array<T, N> arr_from_list(py::list lst)
    {
        if(N != py::len(lst))
            throw std::logic_error("N parameter is not the same size as the list");

        std::array<T, N> arr;
        for(int ll = 0; ll < N; ++ll)
            arr[ll] = py::extract<T>(lst[ll]);
        return arr;
    }

    /**
     * @brief Convert a numpy array object to a std::vector
     *
     * @param lst numpy array to convert to a std::array
     * @tparam T type of objects inside the numpy array
     * @tparam N the size of the array
     * @return An array of the numpy array
     */
    template<typename T, size_t N>
    std::array<T, N> arr_from_ndarray(np::ndarray ndarr)
    {
        if(ndarr.get_dtype() != np::dtype::get_builtin<T>())
            throw std::logic_error("arr is not of the correct type.");

        if(N != ndarr)
            throw std::logic_error("N parameter is not the same size as the ndarray");

        std::array<T, N> arr;
        for(int ii = 0; ii < N; ++ii)
            arr[ii] = py::extract<T>(ndarr[ii]);

        return arr;
    }

    /**
     * @brief Convert a python list into a vector of std::shared_ptrs to the object
     *
     * @param lst list to convert
     * @tparam T_ptr the shared_ptr type after the conversion
     * @tparam T_base The base type of the objects in the list
     * @return The vector of the shared_ptrs that represent the objects in the list
     */
    template<typename T_ptr, typename T_base>
    std::vector<std::shared_ptr<T_ptr>> shared_ptr_vec_from_list(py::list lst)
    {
        std::vector<std::shared_ptr<T_ptr>> vec(py::len(lst));
        for(int ll = 0; ll < vec.size(); ++ll)
            vec[ll] = std::make_shared<T_base>(py::extract<T_base>(lst[ll]));
        return vec;
    }

    /**
     * @brief Converts a std::vector to a python list
     *
     * @param vec vector to convert
     * @tparam T Type of the objects inside the vector
     * @return The python list
     */
    template<typename T>
    py::list to_list(std::vector<T> vec)
    {
        py::list lst;
        for(auto& item : vec)
            lst.append<T>(item);
        return lst;
    }

    /**
     * @brief Converts a std::vector to a numpy array
     *
     * @param vec vector to convert
     * @tparam T Type of the objects inside the vector
     * @return The numpy array
     */
    template<typename T>
    np::ndarray to_ndarray(std::vector<T> vec)
    {
        np::ndarray arr = np::zeros(py::make_tuple(vec.size()), np::dtype::get_builtin<T>());
        std::copy_n(vec.data(), vec.size(), reinterpret_cast<T*>(arr.get_data()));
        return arr;
    }

    /**
     * @brief Converts a std::vector to a python list
     *
     * @param vec vector to convert
     * @tparam T Type of the objects inside the vector
     * @return The python list
     */
    template<typename T, int N>
    py::list to_list(std::array<T, N> arr)
    {
        py::list lst;
        for(auto& item : arr)
            lst.append<T>(item);
        return lst;
    }

    /**
     * @brief Converts a std::vector to a numpy array
     *
     * @param vec vector to convert
     * @tparam T Type of the objects inside the vector
     * @return The numpy array
     */
    template<typename T, int N>
    np::ndarray to_ndarray(std::array<T, N> arr)
    {
        np::ndarray np_arr = np::zeros(py::make_tuple(arr.size()), np::dtype::get_builtin<T>());
        std::copy_n(arr.data(), arr.size(), reinterpret_cast<T*>(np_arr.get_data()));
        return np_arr;
    }

    template<typename key, typename val>
    py::dict to_dict(std::map<key, val> map)
    {
        py::dict dct;
        for(auto& iter : map)
            dct[iter.first] = iter.second;

        return dct;
    }
}

#endif