// https://www.boost.org/doc/libs/1_92_0/libs/python/doc/html/numpy/tutorial/simple.html

#include <boost/python/numpy.hpp>

#include <cassert>
#include <iostream>

namespace p = boost::python;
namespace np = boost::python::numpy;

int main()
{
    Py_Initialize();
    np::initialize();

    // Create an array from C++ and inspect it through the Boost.Numpy API
    p::tuple shape = p::make_tuple(3, 4);
    np::dtype dt = np::dtype::get_builtin<float>();
    np::ndarray a = np::zeros(shape, dt);

    std::cout << "ndim   = " << a.get_nd() << std::endl;
    std::cout << "shape  = " << a.shape(0) << "x" << a.shape(1) << std::endl;
    std::cout << "dtype  = " << p::extract<const char *>(p::str(a.get_dtype()))() << std::endl;

    assert(a.get_nd() == 2);
    assert(a.shape(0) == 3);
    assert(a.shape(1) == 4);
    assert(a.get_dtype() == dt);

    // Wrap an existing C++ buffer without copying it
    double data[] = { 1.0, 2.0, 3.0, 4.0 };
    np::ndarray wrapped = np::from_data(data, np::dtype::get_builtin<double>(),
                                        p::make_tuple(4), p::make_tuple(sizeof(double)),
                                        p::object());

    std::cout << "wrapped = " << p::extract<const char *>(p::str(wrapped))() << std::endl;

    assert(wrapped.shape(0) == 4);
    assert(p::extract<double>(wrapped[2]) == 3.0);

    // Changes made in C++ are visible through the array view
    data[2] = 30.0;
    assert(p::extract<double>(wrapped[2]) == 30.0);

    return 0;
}
