diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..2eb83d4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,81 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**pocket_numpy** (repo: xtensor-numpy) is a C++ project that integrates the pocketpy lightweight Python interpreter with numpy-like array functionality powered by xtensor and Eigen. It produces: +- A native CLI (`pocketpy.exe`) that runs Python scripts with numpy support +- Python wheels via pybind11 (package name: `pocket_numpy`) +- A WebAssembly build for browser deployment + +## Build & Test Commands + +```bash +# Build (installs in editable mode with scikit-build-core) +make build + +# Run numpy tests via pocketpy CLI +make test # runs: build/pocketpy.exe tests/test_numpy.py + +# Run a single test file +build/pocketpy.exe tests/test_numpy.py + +# Run tests via pytest (after pip install) +python3 -m pytest tests/ + +# Install as pip package +make python_install + +# Build WASM +make build_wasm + +# Serve WASM demo locally +make serve_wasm +``` + +## Architecture + +### Core Type System (`include/numpy.hpp`) + +Defines C++ type aliases (int8–64, uint8–64, float32, float64, bool_, complex64/128) and `dtype_traits` template for runtime dtype identification. Contains the `ndarray` template backed by `xt::xarray`. + +### Polymorphic ndarray (`include/ndarray_binding.hpp`) + +`ndarray_base` is an abstract base class with ~80+ virtual methods (shape, reductions, slicing, arithmetic, sorting, etc.). `ndarray` is the concrete template implementation. This virtual dispatch pattern enables a single Python-facing interface that works across all numeric types via `std::unique_ptr`. + +### Module Bindings (`src/numpy.cpp`) + +Registers the `numpy` module into pocketpy's runtime. Binds all ndarray methods, array creation functions (ones, zeros, full, arange, linspace, identity), random number generation, and dtype attributes. This is the largest source file. + +### RDP Bindings (`src/pybind.cpp` + `src/rdp.hpp`) + +Ramer-Douglas-Peucker polyline simplification exposed via pybind11 as the `_core` module. Supports 2D and 3D point arrays using Eigen matrix types. + +### CLI Entry Point (`src/main.cpp`) + +Initializes pocketpy, registers the numpy module via `py_module_initialize()`, then executes a Python script or enters REPL mode. + +### Dependencies + +- **pocketpy** — git submodule at `pocketpy/` +- **xtensor, xtl, Eigen** — vendored headers in `include/` +- **pybind11** — required via pip/CMake for Python wheel builds + +### Build Targets (CMake) + +- `numpy` — static library (numpy.cpp + pocketpy) +- `pocketpy_cli` — CLI executable linked against numpy +- `_core` — pybind11 module for RDP bindings + +## Git Policy + +- **NEVER use `git commit --amend`**. Always create a new commit instead. Amending rewrites history and can destroy previous work, especially after a failed pre-commit hook where `--amend` would silently modify the wrong commit. + +## Key Conventions + +- C++17 required; C11 for pocketpy C sources +- Default build type is Release with `-O3`; debug uses `-O0 -ggdb` +- xtensor warnings are suppressed by default (`SHOW_XTENSOR_WARNINGS=OFF`) +- Tests are standalone Python scripts (not pytest-based) so they can also run under pocketpy and WASM +- macOS deployment target is 10.14+ (required for `std::visit`) diff --git a/README.md b/README.md index 36ab717..beaaf2b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ python3 -m pocket_numpy --help python3 -m pocket_numpy tests/test_numpy.py ``` +# Try is online + + + --- # How to build (for dev) diff --git a/docs/lib/pocketpy.wasm b/docs/lib/pocketpy.wasm index 4942050..05c751c 100755 Binary files a/docs/lib/pocketpy.wasm and b/docs/lib/pocketpy.wasm differ diff --git a/include/ndarray_binding.hpp b/include/ndarray_binding.hpp new file mode 100644 index 0000000..cc1bcac --- /dev/null +++ b/include/ndarray_binding.hpp @@ -0,0 +1,2709 @@ +#pragma once + +#include +#include +#include +#include + +namespace py = pybind11; + +using bool_ = pkpy::bool_; +using int8 = pkpy::int8; +using int16 = pkpy::int16; +using int32 = pkpy::int32; +using int64 = pkpy::int64; +using int_ = pkpy::int_; +using float32 = pkpy::float32; +using float64 = pkpy::float64; +using float_ = pkpy::float_; + +// Function to parse attributes +inline int parseAttr(const py::object& obj) { + if(py::isinstance(obj)) { + return INT_MAX; + } else if(py::isinstance(obj)) { + return obj.cast(); + } else { + throw std::runtime_error("Unsupported type"); + } +}; + +class ndarray_base { +public: + virtual ~ndarray_base() = default; + + virtual int ndim() const = 0; + + virtual int size() const = 0; + + virtual std::string dtype() const = 0; + + virtual py::tuple shape() const = 0; + + virtual bool all() const = 0; + + virtual bool any() const = 0; + + virtual py::object sum() const = 0; + + virtual py::object sum_axis(int axis) const = 0; + + virtual py::object sum_axes(py::tuple axes) const = 0; + + virtual py::object prod() const = 0; + + virtual py::object prod_axis(int axis) const = 0; + + virtual py::object prod_axes(py::tuple axes) const = 0; + + virtual py::object min() const = 0; + + virtual py::object min_axis(int axis) const = 0; + + virtual py::object min_axes(py::tuple axes) const = 0; + + virtual py::object max() const = 0; + + virtual py::object max_axis(int axis) const = 0; + + virtual py::object max_axes(py::tuple axes) const = 0; + + virtual py::object mean() const = 0; + + virtual py::object mean_axis(int axis) const = 0; + + virtual py::object mean_axes(py::tuple axes) const = 0; + + virtual py::object std() const = 0; + + virtual py::object std_axis(int axis) const = 0; + + virtual py::object std_axes(py::tuple axes) const = 0; + + virtual py::object var() const = 0; + + virtual py::object var_axis(int axis) const = 0; + + virtual py::object var_axes(py::tuple axes) const = 0; + + virtual py::object argmin() const = 0; + + virtual ndarray_base* argmin_axis(int axis) const = 0; + + virtual py::object argmax() const = 0; + + virtual ndarray_base* argmax_axis(int axis) const = 0; + + virtual ndarray_base* argsort() const = 0; + + virtual ndarray_base* argsort_axis(int axis) const = 0; + + virtual void sort() = 0; + + virtual void sort_axis(int axis) = 0; + + virtual ndarray_base* reshape(const std::vector& shape) const = 0; + + virtual void resize(const std::vector& shape) = 0; + + virtual ndarray_base* squeeze() const = 0; + + virtual ndarray_base* squeeze_axis(int axis) const = 0; + + virtual ndarray_base* transpose() const = 0; + + virtual ndarray_base* transpose_tuple(py::tuple permutations) const = 0; + + virtual ndarray_base* transpose_args(py::args args) const = 0; + + virtual ndarray_base* repeat(int repeats, int axis) const = 0; + + virtual ndarray_base* repeat_axis(const std::vector& repeats, int axis) const = 0; + + virtual ndarray_base* round() const = 0; + + virtual ndarray_base* flatten() const = 0; + + virtual ndarray_base* copy() const = 0; + + virtual ndarray_base* astype(const std::string& dtype) const = 0; + + virtual py::list tolist() const = 0; + + virtual ndarray_base* eq(const ndarray_base& other) const = 0; + + virtual ndarray_base* ne(const ndarray_base& other) const = 0; + + virtual ndarray_base* add(const ndarray_base& other) const = 0; + + virtual ndarray_base* add_bool(bool_ other) const = 0; + + virtual ndarray_base* add_int(int_ other) const = 0; + + virtual ndarray_base* add_float(float64 other) const = 0; + + virtual ndarray_base* sub(const ndarray_base& other) const = 0; + + virtual ndarray_base* sub_int(int_ other) const = 0; + + virtual ndarray_base* sub_float(float64 other) const = 0; + + virtual ndarray_base* rsub_int(int_ other) const = 0; + + virtual ndarray_base* rsub_float(float64 other) const = 0; + + virtual ndarray_base* mul(const ndarray_base& other) const = 0; + + virtual ndarray_base* mul_bool(bool_ other) const = 0; + + virtual ndarray_base* mul_int(int_ other) const = 0; + + virtual ndarray_base* mul_float(float64 other) const = 0; + + virtual ndarray_base* div(const ndarray_base& other) const = 0; + + virtual ndarray_base* div_bool(bool_ other) const = 0; + + virtual ndarray_base* div_int(int_ other) const = 0; + + virtual ndarray_base* div_float(float64 other) const = 0; + + virtual ndarray_base* rdiv_bool(bool_ other) const = 0; + + virtual ndarray_base* rdiv_int(int_ other) const = 0; + + virtual ndarray_base* rdiv_float(float64 other) const = 0; + + virtual ndarray_base* matmul(const ndarray_base& other) const = 0; + + virtual ndarray_base* pow(const ndarray_base& other) const = 0; + + virtual ndarray_base* pow_int(int_ other) const = 0; + + virtual ndarray_base* pow_float(float64 other) const = 0; + + virtual ndarray_base* rpow_int(int_ other) const = 0; + + virtual ndarray_base* rpow_float(float64 other) const = 0; + + virtual ndarray_base* and_array(const ndarray_base& other) const = 0; + + virtual ndarray_base* and_bool(bool_ other) const = 0; + + virtual ndarray_base* and_int(int_ other) const = 0; + + virtual ndarray_base* or_array(const ndarray_base& other) const = 0; + + virtual ndarray_base* or_bool(bool_ other) const = 0; + + virtual ndarray_base* or_int(int_ other) const = 0; + + virtual ndarray_base* xor_array(const ndarray_base& other) const = 0; + + virtual ndarray_base* xor_bool(bool_ other) const = 0; + + virtual ndarray_base* xor_int(int_ other) const = 0; + + virtual ndarray_base* invert() const = 0; + + virtual py::object get_item_int(int index) const = 0; + + virtual py::object get_item_tuple(py::tuple indices) const = 0; + + virtual ndarray_base* get_item_vector(const std::vector& indices) const = 0; + + virtual ndarray_base* get_item_slice(py::slice slice) const = 0; + + virtual void set_item_int(int index, int_ value) = 0; + + virtual void set_item_index_int(int index, const std::vector& value) = 0; + + virtual void set_item_index_int_2d(int index, const std::vector>& value) = 0; + + virtual void set_item_index_int_3d(int index, const std::vector>>& value) = 0; + + virtual void set_item_index_int_4d(int index, const std::vector>>>& value) = 0; + + virtual void set_item_float(int index, float64 value) = 0; + + virtual void set_item_index_float(int index, const std::vector& value) = 0; + + virtual void set_item_index_float_2d(int index, const std::vector>& value) = 0; + + virtual void set_item_index_float_3d(int index, const std::vector>>& value) = 0; + + virtual void set_item_index_float_4d(int index, const std::vector>>>& value) = 0; + + virtual void set_item_tuple_int1(py::tuple args, int_ value) = 0; + + virtual void set_item_tuple_int2(py::tuple args, const std::vector& value) = 0; + + virtual void set_item_tuple_int3(py::tuple args, const std::vector>& value) = 0; + + virtual void set_item_tuple_int4(py::tuple args, const std::vector>>& value) = 0; + + virtual void set_item_tuple_int5(py::tuple args, const std::vector>>>& value) = 0; + + virtual void set_item_tuple_float1(py::tuple args, float64 value) = 0; + + virtual void set_item_tuple_float2(py::tuple args, const std::vector& value) = 0; + + virtual void set_item_tuple_float3(py::tuple args, const std::vector>& value) = 0; + + virtual void set_item_tuple_float4(py::tuple args, const std::vector>>& value) = 0; + + virtual void set_item_tuple_float5(py::tuple args, const std::vector>>>& value) = 0; + + virtual void set_item_vector_int1(const std::vector& indices, int_ value) = 0; + + virtual void set_item_vector_int2(const std::vector& indices, const std::vector& value) = 0; + + virtual void set_item_vector_int3(const std::vector& indices, const std::vector>& value) = 0; + + virtual void set_item_vector_int4(const std::vector& indices, const std::vector>>& value) = 0; + + virtual void set_item_vector_int5(const std::vector& indices, const std::vector>>>& value) = 0; + + virtual void set_item_vector_float1(const std::vector& indices, float64 value) = 0; + + virtual void set_item_vector_float2(const std::vector& indices, const std::vector& value) = 0; + + virtual void set_item_vector_float3(const std::vector& indices, const std::vector>& value) = 0; + + virtual void set_item_vector_float4(const std::vector& indices, const std::vector>>& value) = 0; + + virtual void set_item_vector_float5(const std::vector& indices, const std::vector>>>& value) = 0; + + virtual void set_item_slice_int1(py::slice slice, int_ value) = 0; + + virtual void set_item_slice_int2(py::slice slice, const std::vector& value) = 0; + + virtual void set_item_slice_int3(py::slice slice, const std::vector>& value) = 0; + + virtual void set_item_slice_int4(py::slice slice, const std::vector>>& value) = 0; + + virtual void set_item_slice_int5(py::slice slice, const std::vector>>>& value) = 0; + + virtual void set_item_slice_float1(py::slice slice, float64 value) = 0; + + virtual void set_item_slice_float2(py::slice slice, const std::vector& value) = 0; + + virtual void set_item_slice_float3(py::slice slice, const std::vector>& value) = 0; + + virtual void set_item_slice_float4(py::slice slice, const std::vector>>& value) = 0; + + virtual void set_item_slice_float5(py::slice slice, const std::vector>>>& value) = 0; + + virtual int len() const = 0; + + virtual std::string to_string() const = 0; +}; + +template +class ndarray : public ndarray_base { +public: + pkpy::numpy::ndarray data; + // Constructors + ndarray() = default; + + ndarray(const bool_ value) : data(value) {} + + ndarray(const int8 value) : data(value) {} + + ndarray(const int16 value) : data(value) {} + + ndarray(const int32 value) : data(value) {} + + ndarray(const int_ value) : data(static_cast(value)) {} + + ndarray(const float32 value) : data(value) {} + + ndarray(const float64 value) : data(static_cast(value)) {} + + ndarray(const pkpy::numpy::ndarray& _arr) : data(_arr) {} + + ndarray(const std::vector& init_list) : data(pkpy::numpy::adapt(init_list)) {} + + ndarray(const std::vector>& init_list) : data(pkpy::numpy::adapt(init_list)) {} + + ndarray(const std::vector>>& init_list) : data(pkpy::numpy::adapt(init_list)) {} + + ndarray(const std::vector>>>& init_list) : + data(pkpy::numpy::adapt(init_list)) {} + + ndarray(const std::vector>>>>& init_list) : + data(pkpy::numpy::adapt(init_list)) {} + + // Properties + int ndim() const override { return data.ndim(); } + + int size() const override { return data.size(); } + + std::string dtype() const override { return data.dtype(); } + + py::tuple shape() const override { return py::cast(data.shape()); } + + // Boolean Functions + bool all() const override { return data.all(); } + + bool any() const override { return data.any(); } + + // Aggregation Functions + py::object sum() const override { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v) { + return py::int_(data.sum()); + } else if constexpr(std::is_same_v || std::is_same_v) { + return py::float_(data.sum()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + py::object sum_axis(int axis) const override { + if ((data.sum(axis)).ndim() == 0) { + return py::cast((data.sum(axis))()); + } else { + return py::cast(ndarray(data.sum(axis))); + } + } + + py::object sum_axes(py::tuple axes) const override { + std::vector axes_; + for(auto item: axes) { + axes_.push_back(py::cast(item)); + } + if ((data.sum(axes_)).ndim() == 0) { + return py::cast((data.sum(axes_))()); + } else { + return py::cast(ndarray(data.sum(axes_))); + } + } + + py::object prod() const override { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v) { + return py::int_(data.prod()); + } else if constexpr(std::is_same_v || std::is_same_v) { + return py::float_(data.prod()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + py::object prod_axis(int axis) const override { + if ((data.prod(axis)).ndim() == 0) { + return py::cast((data.prod(axis))()); + } else { + return py::cast(ndarray(data.prod(axis))); + } + } + + py::object prod_axes(py::tuple axes) const override { + std::vector axes_; + for(auto item: axes) { + axes_.push_back(py::cast(item)); + } + if ((data.prod(axes_)).ndim() == 0) { + return py::cast((data.prod(axes_))()); + } else { + return py::cast(ndarray(data.prod(axes_))); + } + } + + py::object min() const override { + if constexpr (std::is_same_v) { + return py::bool_(data.min()); + } else if constexpr (std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v) { + return py::int_(data.min()); + } else if constexpr(std::is_same_v || std::is_same_v) { + return py::float_(data.min()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + py::object min_axis(int axis) const override { + if ((data.min(axis)).ndim() == 0) { + return py::cast((data.min(axis))()); + } else { + return py::cast(ndarray(data.min(axis))); + } + + } + + py::object min_axes(py::tuple axes) const override { + std::vector axes_; + for(auto item: axes) { + axes_.push_back(py::cast(item)); + } + if ((data.min(axes_)).ndim() == 0) { + return py::cast((data.min(axes_))()); + } else { + return py::cast(ndarray(data.min(axes_))); + } + } + + py::object max() const override { + if constexpr (std::is_same_v) { + return py::bool_(data.max()); + } else if constexpr (std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v) { + return py::int_(data.max()); + } else if constexpr(std::is_same_v || std::is_same_v) { + return py::float_(data.max()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + py::object max_axis(int axis) const override { + if ((data.max(axis)).ndim() == 0) { + return py::cast((data.max(axis))()); + } else { + return py::cast(ndarray(data.max(axis))); + } + } + + py::object max_axes(py::tuple axes) const override { + std::vector axes_; + for(auto item: axes) { + axes_.push_back(py::cast(item)); + } + if ((data.max(axes_)).ndim() == 0) { + return py::cast((data.max(axes_))()); + } else { + return py::cast(ndarray(data.max(axes_))); + } + } + + py::object mean() const override { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v) { + return py::float_(data.mean()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + py::object mean_axis(int axis) const override { + if ((data.mean(axis)).ndim() == 0) { + return py::cast((data.mean(axis))()); + } else { + return py::cast(ndarray(data.mean(axis))); + } + } + + py::object mean_axes(py::tuple axes) const override { + std::vector axes_; + for(auto item: axes) + axes_.push_back(py::cast(item)); + if ((data.mean(axes_)).ndim() == 0) { + return py::cast((data.mean(axes_))()); + } else { + return py::cast(ndarray(data.mean(axes_))); + } + } + + py::object std() const override { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v) { + return py::float_(data.std()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + py::object std_axis(int axis) const override { + if ((data.std(axis)).ndim() == 0) { + return py::cast((data.std(axis))()); + } else { + return py::cast(ndarray(data.std(axis))); + } + } + + py::object std_axes(py::tuple axes) const override { + std::vector axes_; + for(auto item: axes) + axes_.push_back(py::cast(item)); + if ((data.std(axes_)).ndim() == 0) { + return py::cast((data.std(axes_))()); + } else { + return py::cast(ndarray(data.std(axes_))); + } + } + + py::object var() const override { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v) { + return py::float_(data.var()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + py::object var_axis(int axis) const override { + if ((data.var(axis)).ndim() == 0) { + return py::cast((data.var(axis))()); + } else { + return py::cast(ndarray(data.var(axis))); + } + } + + py::object var_axes(py::tuple axes) const override { + std::vector axes_; + for(auto item: axes) + axes_.push_back(py::cast(item)); + if ((data.var(axes_)).ndim() == 0) { + return py::cast((data.var(axes_))()); + } else { + return py::cast(ndarray(data.var(axes_))); + } + } + + py::object argmin() const override { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v) { + return py::int_(data.argmin()); + } else if constexpr(std::is_same_v || std::is_same_v) { + return py::int_(data.argmin()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + ndarray_base* argmin_axis(int axis) const override { return new ndarray(data.argmin(axis)); } + + py::object argmax() const override { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v) { + return py::int_(data.argmax()); + } else if constexpr(std::is_same_v || std::is_same_v) { + return py::int_(data.argmax()); + } else { + throw std::runtime_error("Unsupported type"); + } + } + + ndarray_base* argmax_axis(int axis) const override { return new ndarray(data.argmax(axis)); } + + ndarray_base* argsort() const override { return new ndarray(data.argsort()); } + + ndarray_base* argsort_axis(int axis) const override { return new ndarray(data.argsort(axis)); } + + void sort() override { data = data.sort(); } + + void sort_axis(int axis) override { data = data.sort(axis); } + + ndarray_base* reshape(const std::vector& shape) const override { return new ndarray(data.reshape(shape)); } + + void resize(const std::vector& shape) override { data = data.resize(shape); } + + ndarray_base* squeeze() const override { return new ndarray(data.squeeze()); } + + ndarray_base* squeeze_axis(int axis) const override { return new ndarray(data.squeeze(axis)); } + + ndarray_base* transpose() const override { return new ndarray(data.transpose()); } + + ndarray_base* transpose_tuple(py::tuple permutations) const override { + std::vector perm; + for(auto item: permutations) + perm.push_back(py::cast(item)); + return new ndarray(data.transpose(perm)); + } + + ndarray_base* transpose_args(py::args args) const override { + std::vector perm; + for(auto item: args) + perm.push_back(py::cast(item)); + return new ndarray(data.transpose(perm)); + } + + ndarray_base* repeat(int repeats, int axis) const override { + if (axis == INT_MAX) { + return new ndarray(data.repeat(repeats, data.ndim() - 1)); + } + return new ndarray(data.repeat(repeats, axis)); + } + + ndarray_base* repeat_axis(const std::vector& repeats, int axis) const override { + return new ndarray(data.repeat(repeats, axis)); + } + + ndarray_base* round() const override { return new ndarray(data.round()); } + + ndarray_base* flatten() const override { return new ndarray(data.flatten()); } + + ndarray_base* copy() const override { return new ndarray(data.copy()); } + + ndarray_base* astype(const std::string& dtype) const override { + if(dtype == "bool_") { + return new ndarray(data.template astype()); + } else if(dtype == "int8") { + return new ndarray(data.template astype()); + } else if(dtype == "int16") { + return new ndarray(data.template astype()); + } else if(dtype == "int32") { + return new ndarray(data.template astype()); + } else if(dtype == "int_") { + return new ndarray(data.template astype()); + } else if(dtype == "float32") { + return new ndarray(data.template astype()); + } else if(dtype == "float64") { + return new ndarray(data.template astype()); + } else { + throw std::invalid_argument("Invalid dtype"); + } + } + + py::list tolist() const override { + py::list list; + if(data.ndim() == 1) { + return py::cast(data.to_list()); + } else { + for(int i = 0; i < data.shape()[0]; i++) { + list.append(ndarray(data[i]).tolist()); + } + } + return list; + } + + // Dunder Methods + ndarray_base* eq(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 == int8 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 == int16 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 == int32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 == int64 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 == float32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 == float64 */ + return new ndarray(data == p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 == int8 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 == int16 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 == int32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 == int64 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 == float32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 == float64 */ + return new ndarray(data == p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 == int8 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 == int16 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 == int32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 == int64 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 == float32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 == float64 */ + return new ndarray(data == p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int64 == int8 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 == int16 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 == int32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 == int64 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 == float32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 == float64 */ + return new ndarray(data == p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* float32 == int8 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 == int16 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 == int32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 == int64 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 == float32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 == float64 */ + return new ndarray(data == p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* float64 == int8 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 == int16 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 == int32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 == int64 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 == float32 */ + return new ndarray(data == p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 == float64 */ + return new ndarray(data == p->data); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(data == other_.data); + } + + ndarray_base* ne(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 != int8 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 != int16 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 != int32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 != int64 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 != float32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 != float64 */ + return new ndarray(data != p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 != int8 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 != int16 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 != int32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 != int64 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 != float32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 != float64 */ + return new ndarray(data != p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 != int8 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 != int16 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 != int32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 != int64 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 != float32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 != float64 */ + return new ndarray(data != p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int64 != int8 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 != int16 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 != int32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 != int64 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 != float32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int64 != float64 */ + return new ndarray(data != p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* float32 != int8 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 != int16 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 != int32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 != int64 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 != float32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float32 != float64 */ + return new ndarray(data != p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* float64 != int8 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 != int16 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 != int32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 != int64 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 != float32 */ + return new ndarray(data != p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* float64 != float64 */ + return new ndarray(data != p->data); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(data != other_.data); + } + + ndarray_base* add(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 + int8 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 + int16 */ + return new ndarray((data + p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 + int32 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 + int64 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 + float32 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 + float64 */ + return new ndarray(data + p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 + int8 */ + return new ndarray((data + p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 + int16 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 + int32 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 + int64 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 + float32 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 + float64 */ + return new ndarray(data + p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 + int8 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 + int16 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 + int32 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 + int64 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 + float32 */ + return new ndarray(data + p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 + float64 */ + return new ndarray(data + p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int64 + int8 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 + int16 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 + int32 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 + int64 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 + float32 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 + float64 */ + return new ndarray(data + p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float32 + int8 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 + int16 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 + int32 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 + int64 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 + float32 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 + float64 */ + return new ndarray(data + p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float64 + int8 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 + int16 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 + int32 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 + int64 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 + float32 */ + return new ndarray(data + p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 + float64 */ + return new ndarray(data + p->data); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(data + other_.data); + } + + ndarray_base* add_bool(bool_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray((data + other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data + other).template astype()); + } else { + return new ndarray(data + other); + } + } + + ndarray_base* add_int(int_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray(data + other); + } else if constexpr(std::is_same_v) { + return new ndarray((data + other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data + other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data + other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray(data + other); + } else if constexpr(std::is_same_v) { + return new ndarray(data + other); + } else if constexpr(std::is_same_v) { + return new ndarray(data + other); + } + } + + ndarray_base* add_float(float64 other) const override { return new ndarray(data + other); } + + ndarray_base* sub(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 - int8 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 - int16 */ + return new ndarray((data - p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 - int32 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 - int64 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 - float32 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 - float64 */ + return new ndarray(data - p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 - int8 */ + return new ndarray((data - p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 - int16 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 - int32 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 - int64 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 - float32 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 - float64 */ + return new ndarray(data - p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 - int8 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 - int16 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 - int32 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 - int64 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 - float32 */ + return new ndarray(data - p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 - float64 */ + return new ndarray(data - p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int64 - int8 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 - int16 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 - int32 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 - int64 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 - float32 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 - float64 */ + return new ndarray(data - p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float32 - int8 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 - int16 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 - int32 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 - int64 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 - float32 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 - float64 */ + return new ndarray(data - p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float64 - int8 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 - int16 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 - int32 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 - int64 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 - float32 */ + return new ndarray(data - p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 - float64 */ + return new ndarray(data - p->data); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(data - other_.data); + } + + ndarray_base* sub_int(int_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray(data - other); + } else if constexpr(std::is_same_v) { + return new ndarray((data - other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data - other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data - other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray(data - other); + } else if constexpr(std::is_same_v) { + return new ndarray(data - other); + } else if constexpr(std::is_same_v) { + return new ndarray(data - other); + } + } + + ndarray_base* sub_float(float64 other) const override { return new ndarray(data - other); } + + ndarray_base* rsub_int(int_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray(other - data); + } else if constexpr(std::is_same_v) { + return new ndarray((other - data).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((other - data).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((other - data).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray(other - data); + } else if constexpr(std::is_same_v) { + return new ndarray(other - data); + } else if constexpr(std::is_same_v) { + return new ndarray(other - data); + } + } + + ndarray_base* rsub_float(float64 other) const override { return new ndarray(other - data); } + + ndarray_base* mul(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 * int8 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 * int16 */ + return new ndarray((data * p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 * int32 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 * int64 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 * float32 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 * float64 */ + return new ndarray(data * p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 * int8 */ + return new ndarray((data * p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 * int16 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 * int32 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 * int64 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 * float32 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 * float64 */ + return new ndarray(data * p->data); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 * int8 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 * int16 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 * int32 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 * int64 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 * float32 */ + return new ndarray(data * p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 * float64 */ + return new ndarray(data * p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int64 * int8 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 * int16 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 * int32 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 * int64 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 * float32 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 * float64 */ + return new ndarray(data * p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float32 * int8 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 * int16 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 * int32 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 * int64 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 * float32 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 * float64 */ + return new ndarray(data * p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float64 * int8 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 * int16 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 * int32 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 * int64 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 * float32 */ + return new ndarray(data * p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 * float64 */ + return new ndarray(data * p->data); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(data * other_.data); + } + + ndarray_base* mul_bool(bool_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray((data * other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data * other).template astype()); + } else { + return new ndarray(data * other); + } + } + + ndarray_base* mul_int(int_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray(data * other); + } else if constexpr(std::is_same_v) { + return new ndarray((data * other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data * other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray((data * other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray(data * other); + } else if constexpr(std::is_same_v) { + return new ndarray(data * other); + } else if constexpr(std::is_same_v) { + return new ndarray(data * other); + } + } + + ndarray_base* mul_float(float64 other) const override { return new ndarray(data * other); } + + ndarray_base* div(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* bool / bool */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool / int8 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool / int16 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool / int32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool / int64 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool / float32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool / float64 */ + return new ndarray(data / p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int8 / bool */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int8 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int16 */ + return new ndarray((data / p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int64 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 / float32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 / float64 */ + return new ndarray(data / p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int16 / bool */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int8 */ + return new ndarray((data / p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int16 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int64 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 / float32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 / float64 */ + return new ndarray(data / p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int32 / bool */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int8 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int16 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int64 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 / float32 */ + return new ndarray(data / p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 / float64 */ + return new ndarray(data / p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int64 / bool */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int8 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int16 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int32 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int64 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 / float32 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 / float64 */ + return new ndarray(data / p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float32 / bool */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int8 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int16 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int32 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int64 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 / float32 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 / float64 */ + return new ndarray(data / p->data); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float64 / bool */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int8 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int16 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int32 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int64 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 / float32 */ + return new ndarray(data / p->data); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 / float64 */ + return new ndarray(data / p->data); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(data / other_.data); + } + + ndarray_base* div_bool(bool_ other) const override { return new ndarray(data / other); } + + ndarray_base* div_int(int_ other) const override { return new ndarray(data / other); } + + ndarray_base* div_float(float64 other) const override { return new ndarray(data / other); } + + ndarray_base* rdiv_bool(bool_ other) const override { return new ndarray(other / data); } + + ndarray_base* rdiv_int(int_ other) const override { return new ndarray(other / data); } + + ndarray_base* rdiv_float(float64 other) const override { return new ndarray(other / data); } + + ndarray_base* matmul(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 @ int8 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ int16 */ + return new ndarray(pkpy::numpy::matmul(data, p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ int32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ int64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ float32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ float64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 @ int8 */ + return new ndarray(pkpy::numpy::matmul(data, p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ int16 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ int32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ int64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ float32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ float64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 @ int8 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ int16 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ int32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ int64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ float32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ float64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int64 @ int8 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ int16 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ int32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ int64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ float32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ float64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float32 @ int8 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ int16 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ int32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ int64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ float32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ float64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float64 @ int8 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ int16 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ int32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ int64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ float32 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ float64 */ + return new ndarray(pkpy::numpy::matmul(data, p->data)); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(pkpy::numpy::matmul(data, other_.data)); + } + + ndarray_base* pow(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 ** int8 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** int16 */ + return new ndarray(data.pow(p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** int32 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** int64 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** float32 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** float64 */ + return new ndarray(data.pow(p->data)); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 ** int8 */ + return new ndarray(data.pow(p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** int16 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** int32 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** int64 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** float32 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** float64 */ + return new ndarray(data.pow(p->data)); + } + } else if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 ** int8 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** int16 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** int32 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** int64 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** float32 */ + return new ndarray(data.pow(p->data)); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** float64 */ + return new ndarray(data.pow(p->data)); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* int64 ** int8 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** int16 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** int32 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** int64 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** float32 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** float64 */ + return new ndarray(data.pow(p->data)); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float32 ** int8 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** int16 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** int32 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** int64 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** float32 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** float64 */ + return new ndarray(data.pow(p->data)); + } + } else if constexpr(std::is_same_v) { + if (auto p = dynamic_cast*>(&other)) { /* float64 ** int8 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** int16 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** int32 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** int64 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** float32 */ + return new ndarray(data.pow(p->data)); + } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** float64 */ + return new ndarray(data.pow(p->data)); + } + } + + const ndarray& other_ = dynamic_cast&>(other); + return new ndarray(data.pow(other_.data)); + } + + ndarray_base* pow_int(int_ other) const override { return new ndarray(data.pow(other)); } + + ndarray_base* pow_float(float64 other) const override { return new ndarray(data.pow(other)); } + + ndarray_base* rpow_int(int_ other) const override { return new ndarray(pkpy::numpy::pow(other, data)); } + + ndarray_base* rpow_float(float64 other) const override { + return new ndarray(pkpy::numpy::pow(other, data)); + } + + int len() const override { return data.shape()[0]; } + + ndarray_base* and_array(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* bool & bool */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool & int8 */ + return new ndarray((data & p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* bool & int16 */ + return new ndarray((data & p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* bool & int32 */ + return new ndarray((data & p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* bool & int64 */ + return new ndarray((data & p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 & bool */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int8 */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int16 */ + return new ndarray((data & p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int32 */ + return new ndarray((data & p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int64 */ + return new ndarray((data & p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int16 & bool */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int8 */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int16 */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int32 */ + return new ndarray((data & p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int64 */ + return new ndarray((data & p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int32 & bool */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int8 */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int16 */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int32 */ + return new ndarray(data & p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int64 */ + return new ndarray((data & p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int64 & bool */ + return new ndarray(data & p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int8 */ + return new ndarray(data & p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int16 */ + return new ndarray(data & p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int32 */ + return new ndarray(data & p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int64 */ + return new ndarray(data & p->data); + } + } + + throw std::runtime_error("& operator is not compatible with floating types"); + } + + ndarray_base* and_bool(bool_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray(data & other); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } + + throw std::runtime_error("& operator is not compatible with floating types"); + } + + ndarray_base* and_int(int_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray((data & other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } else if constexpr(std::is_same_v) { + return new ndarray(data & other); + } + + throw std::runtime_error("& operator is not compatible with floating types"); + } + + ndarray_base* or_array(const ndarray_base& other) const override { + if constexpr(std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* bool | bool */ + return new ndarray(data | p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* bool | int8 */ + return new ndarray((data | p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* bool | int16 */ + return new ndarray((data | p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* bool | int32 */ + return new ndarray((data | p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* bool | int64 */ + return new ndarray((data | p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if(auto p = dynamic_cast*>(&other)) { /* int8 | bool */ + return new ndarray(data | p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int8 */ + return new ndarray(data | p->data); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int16 */ + return new ndarray((data | p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int32 */ + return new ndarray((data | p->data).template astype()); + } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int64 */ + return new ndarray((data | p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int16 | bool */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int8 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int16 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int32 */ + return new ndarray((data | p->data).template astype()); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int64 */ + return new ndarray((data | p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int32 | bool */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int8 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int16 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int32 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int64 */ + return new ndarray((data | p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int64 | bool */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int8 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int16 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int32 */ + return new ndarray(data | p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int64 */ + return new ndarray(data | p->data); + } + } + + throw std::runtime_error("| operator is not compatible with floating types"); + } + + ndarray_base* or_bool(bool_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray(data | other); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } + + throw std::runtime_error("| operator is not compatible with floating types"); + } + + ndarray_base* or_int(int_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray((data | other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } else if constexpr(std::is_same_v) { + return new ndarray(data | other); + } + + throw std::runtime_error("| operator is not compatible with floating types"); + } + + ndarray_base* xor_array(const ndarray_base& other) const override { + if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* bool ^ bool */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int8 */ + return new ndarray((data ^ p->data).template astype()); + } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int16 */ + return new ndarray((data ^ p->data).template astype()); + } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int32 */ + return new ndarray((data ^ p->data).template astype()); + } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int64 */ + return new ndarray((data ^ p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int8 ^ bool */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int8 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int16 */ + return new ndarray((data ^ p->data).template astype()); + } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int32 */ + return new ndarray((data ^ p->data).template astype()); + } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int64 */ + return new ndarray((data ^ p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int16 ^ bool */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int8 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int16 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int32 */ + return new ndarray((data ^ p->data).template astype()); + } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int64 */ + return new ndarray((data ^ p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int32 ^ bool */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int8 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int16 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int32 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int64 */ + return new ndarray((data ^ p->data).template astype()); + } + } else if constexpr (std::is_same_v) { + if (auto p = dynamic_cast *>(&other)) { /* int64 ^ bool */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int8 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int16 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int32 */ + return new ndarray(data ^ p->data); + } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int64 */ + return new ndarray(data ^ p->data); + } + } + + throw std::runtime_error("^ operator is not compatible with floating types"); + } + + ndarray_base* xor_bool(bool_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } + + throw std::runtime_error("^ operator is not compatible with floating types"); + } + + ndarray_base* xor_int(int_ other) const override { + if constexpr(std::is_same_v) { + return new ndarray((data ^ other).template astype()); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } else if constexpr(std::is_same_v) { + return new ndarray(data ^ other); + } + + throw std::runtime_error("^ operator is not compatible with floating types"); + } + + ndarray_base* invert() const override { + if constexpr(std::is_same_v) { + return new ndarray(!data); + } else if constexpr(std::is_same_v) { + return new ndarray(!data); + } else if constexpr(std::is_same_v) { + return new ndarray(!data); + } else if constexpr(std::is_same_v) { + return new ndarray(!data); + } else if constexpr(std::is_same_v) { + return new ndarray(!data); + } + + throw std::runtime_error("~ operator is not compatible with floating types"); + } + + py::object get_item_int(int index) const override { + if(index < 0) index += data.shape()[0]; + if(data.ndim() == 1) { + if constexpr(std::is_same_v) { + return py::bool_(data(index)); + } else if constexpr(std::is_same_v) { + return py::int_(data(index)); + } else if constexpr(std::is_same_v) { + return py::float_(data(index)); + } + } + return py::cast(ndarray(data[index])); + } + + py::object get_item_tuple(py::tuple args) const override { + pkpy::numpy::ndarray store = data; + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + for(int i = 0; i < indices.size() - 1; i++) { + if(indices[i] < 0) indices[i] += store.shape()[0]; + pkpy::numpy::ndarray temp = store[indices[i]]; + store = temp; + } + + if(indices[indices.size() - 1] < 0) indices[indices.size() - 1] += store.shape()[0]; + if(store.ndim() == 1) { + if constexpr(std::is_same_v) { + return py::bool_(store(indices[indices.size() - 1])); + } else if constexpr(std::is_same_v) { + return py::int_(store(indices[indices.size() - 1])); + } else if constexpr(std::is_same_v) { + return py::float_(store(indices[indices.size() - 1])); + } + } + return py::cast(ndarray(store[indices[indices.size() - 1]])); + } + + ndarray_base* get_item_vector(const std::vector& indices) const override { + return new ndarray(data[indices]); + } + + ndarray_base* get_item_slice(py::slice slice) const override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + + return new ndarray(data[std::make_tuple(start, stop, step)]); + } + + void set_item_int(int index, int_ value) override { + if constexpr(std::is_same_v) { + if (data.ndim() == 1) { + data.set_item(index, value); + } else { + data.set_item(index, pkpy::numpy::adapt(std::vector{value})); + } + } else if constexpr(std::is_same_v) { + if (data.ndim() == 1) { + data.set_item(index, static_cast(value)); + } else { + data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } + } + + void set_item_index_int(int index, const std::vector& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_index_int_2d(int index, const std::vector>& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_index_int_3d(int index, const std::vector>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_index_int_4d(int index, const std::vector>>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_float(int index, float64 value) override { + if constexpr(std::is_same_v) { + if (data.ndim() == 1) { + data.set_item(index, value); + } else { + data.set_item(index, pkpy::numpy::adapt(std::vector{value})); + } + } else if constexpr(std::is_same_v) { + if (data.ndim() == 1) { + data.set_item(index, static_cast(value)); + } else { + data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } + } + + void set_item_index_float(int index, const std::vector& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_index_float_2d(int index, const std::vector>& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_index_float_3d(int index, const std::vector>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_index_float_4d(int index, const std::vector>>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_tuple_int1(py::tuple args, int_ value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(std::vector{value})); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], static_cast(value)); + else if(indices.size() == 3 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], indices[2], static_cast(value)); + else if(indices.size() == 4 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], indices[2], indices[3], static_cast(value)); + else if(indices.size() == 5 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], static_cast(value)); + } + + void set_item_tuple_int2(py::tuple args, const std::vector& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_tuple_int3(py::tuple args, const std::vector>& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_tuple_int4(py::tuple args, const std::vector>>& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_tuple_int5(py::tuple args, const std::vector>>>& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_tuple_float1(py::tuple args, float64 value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(std::vector{value})); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], static_cast(value)); + else if(indices.size() == 3 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], indices[2], static_cast(value)); + else if(indices.size() == 4 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], indices[2], indices[3], static_cast(value)); + else if(indices.size() == 5 && indices.size() <= data.ndim()) + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], static_cast(value)); + } + + void set_item_tuple_float2(py::tuple args, const std::vector& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_tuple_float3(py::tuple args, const std::vector>& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_tuple_float4(py::tuple args, const std::vector>>& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_tuple_float5(py::tuple args, const std::vector>>>& value) override { + std::vector indices; + for(auto item: args) { + indices.push_back(py::cast(item)); + } + if(indices.size() == 1) { + int index = indices[0]; + if constexpr(std::is_same_v) { + data.set_item(index, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(index, (pkpy::numpy::adapt(value)).astype()); + } + } else if(indices.size() == 2 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 3 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 4 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); + } + } + else if(indices.size() == 5 && indices.size() <= data.ndim()) { + if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); + } else if constexpr (std::is_same_v) { + data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); + } + } + } + + void set_item_vector_int1(const std::vector& indices, int_ value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(std::vector{value})); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } + + void set_item_vector_int2(const std::vector& indices, const std::vector& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_vector_int3(const std::vector& indices, const std::vector>& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_vector_int4(const std::vector& indices, const std::vector>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_vector_int5(const std::vector& indices, const std::vector>>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_vector_float1(const std::vector& indices, float64 value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(std::vector{value})); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } + + void set_item_vector_float2(const std::vector& indices, const std::vector& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_vector_float3(const std::vector& indices, const std::vector>& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_vector_float4(const std::vector& indices, const std::vector>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_vector_float5(const std::vector& indices, const std::vector>>>& value) override { + if constexpr(std::is_same_v) { + data.set_item(indices, pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_int1(py::slice slice, int_ value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(std::vector{value})); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), + (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } + + void set_item_slice_int2(py::slice slice, const std::vector& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_int3(py::slice slice, const std::vector>& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_int4(py::slice slice, const std::vector>>& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_int5(py::slice slice, const std::vector>>>& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_float1(py::slice slice, float64 value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(std::vector{value})); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), + (pkpy::numpy::adapt(std::vector{value})).astype()); + } + } + + void set_item_slice_float2(py::slice slice, const std::vector& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_float3(py::slice slice, const std::vector>& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_float4(py::slice slice, const std::vector>>& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + void set_item_slice_float5(py::slice slice, const std::vector>>>& value) override { + int start = parseAttr(getattr(slice, "start")); + int stop = parseAttr(getattr(slice, "stop")); + int step = parseAttr(getattr(slice, "step")); + + if(step == INT_MAX) step = 1; + if(step > 0) { + if(start == INT_MAX) start = 0; + if(stop == INT_MAX) stop = data.shape()[0]; + } else if(step < 0) { + if(start == INT_MAX) start = data.shape()[0] - 1; + if(stop == INT_MAX) stop = -(1 + data.shape()[0]); + } + if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); + } else if constexpr(std::is_same_v) { + data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); + } + } + + std::string to_string() const override { + std::ostringstream os; + os << data; + std::string result = os.str(); + + size_t pos = 0; + while ((pos = result.find('{', pos)) != std::string::npos) { + result.replace(pos, 1, "["); + pos += 1; + } + pos = 0; + while ((pos = result.find('}', pos)) != std::string::npos) { + result.replace(pos, 1, "]"); + pos += 1; + } + + if constexpr(std::is_same_v) { + size_t pos = 0; + while ((pos = result.find("true", pos)) != std::string::npos) { + result.replace(pos, 4, "True"); + pos += 4; + } + pos = 0; + while ((pos = result.find("false", pos)) != std::string::npos) { + result.replace(pos, 5, "False"); + pos += 5; + } + } + + for(int i = 0; i < result.size(); i++) { + if(result[i] == '\n') { + result.insert(i + 1, " "); + } + } + return result; + } +}; + diff --git a/include/pkbind/eigen.h b/include/pkbind/eigen.h new file mode 100644 index 0000000..3afe5a6 --- /dev/null +++ b/include/pkbind/eigen.h @@ -0,0 +1,202 @@ +#pragma once + +#include +#include +#include + +namespace pkbind { +namespace detail { + +// --- A) Eigen type detection traits --- + +template +struct is_eigen_dense : std::false_type {}; + +template +struct is_eigen_dense, T>>> + : std::true_type {}; + +template +constexpr bool is_eigen_dense_v = is_eigen_dense::value; + +template +struct is_eigen_ref : std::false_type {}; + +template +struct is_eigen_ref> : std::true_type {}; + +template +constexpr bool is_eigen_ref_v = is_eigen_ref::value; + +// --- B) Helper: try to load Eigen from ndarray_base --- + +template +bool try_load_eigen_from_ndarray(EigenType& out, const ndarray_base& base) { + using Scalar = typename EigenType::Scalar; + constexpr int RowsAtCompile = EigenType::RowsAtCompileTime; + constexpr int ColsAtCompile = EigenType::ColsAtCompileTime; + constexpr bool IsVector = EigenType::IsVectorAtCompileTime; + + auto* typed = dynamic_cast*>(&base); + if (!typed) return false; + + const auto& xarr = typed->data.get_array(); + const NdarrayScalar* ptr = xarr.data(); + auto shape = xarr.shape(); + int ndim = (int)xarr.dimension(); + + if constexpr (IsVector) { + // Accept 1D ndarray for Eigen vectors + if (ndim != 1) return false; + int size = (int)shape[0]; + + // Check compile-time size constraint + if constexpr (RowsAtCompile != Eigen::Dynamic) { + if (size != RowsAtCompile) return false; + } + if constexpr (ColsAtCompile != Eigen::Dynamic) { + if (ColsAtCompile != 1 && size != ColsAtCompile) return false; + } + + out.resize(size, 1); + for (int i = 0; i < size; ++i) { + out(i) = static_cast(static_cast(ptr[i])); + } + return true; + } else { + // Accept 2D ndarray for Eigen matrices + if (ndim != 2) return false; + int rows = (int)shape[0]; + int cols = (int)shape[1]; + + // Check compile-time dimension constraints (critical for overload resolution) + if constexpr (RowsAtCompile != Eigen::Dynamic) { + if (rows != RowsAtCompile) return false; + } + if constexpr (ColsAtCompile != Eigen::Dynamic) { + if (cols != ColsAtCompile) return false; + } + + out.resize(rows, cols); + // Copy element by element with cast (xtensor is row-major) + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + out(i, j) = static_cast(static_cast(ptr[i * cols + j])); + } + } + return true; + } +} + +// --- C) Helper: cast Eigen to Python ndarray --- + +template +pkbind::object eigen_to_python(const EigenType& mat) { + using Scalar = typename EigenType::Scalar; + constexpr bool IsVector = EigenType::IsVectorAtCompileTime; + + if constexpr (IsVector) { + int size = (int)mat.size(); + std::vector flat(size); + for (int i = 0; i < size; ++i) { + flat[i] = mat(i); + } + auto* result = new ::ndarray(flat); + return pkbind::cast(std::unique_ptr(result)); + } else { + int rows = (int)mat.rows(); + int cols = (int)mat.cols(); + std::vector> data(rows, std::vector(cols)); + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + data[i][j] = mat(i, j); + } + } + auto* result = new ::ndarray(data); + return pkbind::cast(std::unique_ptr(result)); + } +} + +} // namespace detail + +// --- D) type_caster for Eigen dense plain types (Matrix, Vector, Array) --- + +template +struct type_caster>> { + T data; + + template + static object cast(U&& value, return_value_policy, handle) { + return detail::eigen_to_python(std::forward(value)); + } + + bool load(handle src, bool convert) { + // Use pkbind's built-in type_caster for ndarray_base + type_caster base_caster; + if (!base_caster.load(src, false)) return false; + auto& base = base_caster.value(); + + // Try exact scalar match first (use ::qualified names to avoid pkbind:: types) + using Scalar = typename T::Scalar; + if constexpr (std::is_same_v) { + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + } else if constexpr (std::is_same_v) { + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + } else if constexpr (std::is_same_v) { + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + } else if constexpr (std::is_same_v) { + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + } + + // Try type-converting matches if convert is allowed + if (convert) { + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + if (detail::try_load_eigen_from_ndarray(data, base)) return true; + } + + return false; + } + + T& value() { return data; } + + constexpr inline static bool is_temporary_v = true; +}; + +// --- E) type_caster for Eigen::Ref --- + +template +struct type_caster> { + using EigenRef = Eigen::Ref; + using PlainNoConst = std::remove_const_t; + + type_caster inner; + std::unique_ptr ref_storage; + + template + static object cast(U&& value, return_value_policy policy, handle parent) { + PlainNoConst plain = value; + return type_caster::cast(std::move(plain), policy, parent); + } + + bool load(handle src, bool convert) { + if (!inner.load(src, convert)) return false; + ref_storage = std::make_unique(inner.value()); + return true; + } + + EigenRef& value() { + return *ref_storage; + } + + constexpr inline static bool is_temporary_v = false; +}; + +} // namespace pkbind diff --git a/pyproject.toml b/pyproject.toml index 829e7d0..8179d5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build" [project] name = "pocket_numpy" -version = "0.0.2" +version = "0.0.3" description = "pocketpy with numpy" readme = "README.md" authors = [ diff --git a/src/numpy.cpp b/src/numpy.cpp index bfa5427..801e94d 100644 --- a/src/numpy.cpp +++ b/src/numpy.cpp @@ -1,2710 +1,7 @@ -#include -#include -#include -#include +#include +#include #include "rdp.hpp" -namespace py = pybind11; - -using bool_ = pkpy::bool_; -using int8 = pkpy::int8; -using int16 = pkpy::int16; -using int32 = pkpy::int32; -using int64 = pkpy::int64; -using int_ = pkpy::int_; -using float32 = pkpy::float32; -using float64 = pkpy::float64; -using float_ = pkpy::float_; - -// Function to parse attributes -int parseAttr(const py::object& obj) { - if(py::isinstance(obj)) { - return INT_MAX; - } else if(py::isinstance(obj)) { - return obj.cast(); - } else { - throw std::runtime_error("Unsupported type"); - } -}; - -class ndarray_base { -public: - virtual ~ndarray_base() = default; - - virtual int ndim() const = 0; - - virtual int size() const = 0; - - virtual std::string dtype() const = 0; - - virtual py::tuple shape() const = 0; - - virtual bool all() const = 0; - - virtual bool any() const = 0; - - virtual py::object sum() const = 0; - - virtual py::object sum_axis(int axis) const = 0; - - virtual py::object sum_axes(py::tuple axes) const = 0; - - virtual py::object prod() const = 0; - - virtual py::object prod_axis(int axis) const = 0; - - virtual py::object prod_axes(py::tuple axes) const = 0; - - virtual py::object min() const = 0; - - virtual py::object min_axis(int axis) const = 0; - - virtual py::object min_axes(py::tuple axes) const = 0; - - virtual py::object max() const = 0; - - virtual py::object max_axis(int axis) const = 0; - - virtual py::object max_axes(py::tuple axes) const = 0; - - virtual py::object mean() const = 0; - - virtual py::object mean_axis(int axis) const = 0; - - virtual py::object mean_axes(py::tuple axes) const = 0; - - virtual py::object std() const = 0; - - virtual py::object std_axis(int axis) const = 0; - - virtual py::object std_axes(py::tuple axes) const = 0; - - virtual py::object var() const = 0; - - virtual py::object var_axis(int axis) const = 0; - - virtual py::object var_axes(py::tuple axes) const = 0; - - virtual py::object argmin() const = 0; - - virtual ndarray_base* argmin_axis(int axis) const = 0; - - virtual py::object argmax() const = 0; - - virtual ndarray_base* argmax_axis(int axis) const = 0; - - virtual ndarray_base* argsort() const = 0; - - virtual ndarray_base* argsort_axis(int axis) const = 0; - - virtual void sort() = 0; - - virtual void sort_axis(int axis) = 0; - - virtual ndarray_base* reshape(const std::vector& shape) const = 0; - - virtual void resize(const std::vector& shape) = 0; - - virtual ndarray_base* squeeze() const = 0; - - virtual ndarray_base* squeeze_axis(int axis) const = 0; - - virtual ndarray_base* transpose() const = 0; - - virtual ndarray_base* transpose_tuple(py::tuple permutations) const = 0; - - virtual ndarray_base* transpose_args(py::args args) const = 0; - - virtual ndarray_base* repeat(int repeats, int axis) const = 0; - - virtual ndarray_base* repeat_axis(const std::vector& repeats, int axis) const = 0; - - virtual ndarray_base* round() const = 0; - - virtual ndarray_base* flatten() const = 0; - - virtual ndarray_base* copy() const = 0; - - virtual ndarray_base* astype(const std::string& dtype) const = 0; - - virtual py::list tolist() const = 0; - - virtual ndarray_base* eq(const ndarray_base& other) const = 0; - - virtual ndarray_base* ne(const ndarray_base& other) const = 0; - - virtual ndarray_base* add(const ndarray_base& other) const = 0; - - virtual ndarray_base* add_bool(bool_ other) const = 0; - - virtual ndarray_base* add_int(int_ other) const = 0; - - virtual ndarray_base* add_float(float64 other) const = 0; - - virtual ndarray_base* sub(const ndarray_base& other) const = 0; - - virtual ndarray_base* sub_int(int_ other) const = 0; - - virtual ndarray_base* sub_float(float64 other) const = 0; - - virtual ndarray_base* rsub_int(int_ other) const = 0; - - virtual ndarray_base* rsub_float(float64 other) const = 0; - - virtual ndarray_base* mul(const ndarray_base& other) const = 0; - - virtual ndarray_base* mul_bool(bool_ other) const = 0; - - virtual ndarray_base* mul_int(int_ other) const = 0; - - virtual ndarray_base* mul_float(float64 other) const = 0; - - virtual ndarray_base* div(const ndarray_base& other) const = 0; - - virtual ndarray_base* div_bool(bool_ other) const = 0; - - virtual ndarray_base* div_int(int_ other) const = 0; - - virtual ndarray_base* div_float(float64 other) const = 0; - - virtual ndarray_base* rdiv_bool(bool_ other) const = 0; - - virtual ndarray_base* rdiv_int(int_ other) const = 0; - - virtual ndarray_base* rdiv_float(float64 other) const = 0; - - virtual ndarray_base* matmul(const ndarray_base& other) const = 0; - - virtual ndarray_base* pow(const ndarray_base& other) const = 0; - - virtual ndarray_base* pow_int(int_ other) const = 0; - - virtual ndarray_base* pow_float(float64 other) const = 0; - - virtual ndarray_base* rpow_int(int_ other) const = 0; - - virtual ndarray_base* rpow_float(float64 other) const = 0; - - virtual ndarray_base* and_array(const ndarray_base& other) const = 0; - - virtual ndarray_base* and_bool(bool_ other) const = 0; - - virtual ndarray_base* and_int(int_ other) const = 0; - - virtual ndarray_base* or_array(const ndarray_base& other) const = 0; - - virtual ndarray_base* or_bool(bool_ other) const = 0; - - virtual ndarray_base* or_int(int_ other) const = 0; - - virtual ndarray_base* xor_array(const ndarray_base& other) const = 0; - - virtual ndarray_base* xor_bool(bool_ other) const = 0; - - virtual ndarray_base* xor_int(int_ other) const = 0; - - virtual ndarray_base* invert() const = 0; - - virtual py::object get_item_int(int index) const = 0; - - virtual py::object get_item_tuple(py::tuple indices) const = 0; - - virtual ndarray_base* get_item_vector(const std::vector& indices) const = 0; - - virtual ndarray_base* get_item_slice(py::slice slice) const = 0; - - virtual void set_item_int(int index, int_ value) = 0; - - virtual void set_item_index_int(int index, const std::vector& value) = 0; - - virtual void set_item_index_int_2d(int index, const std::vector>& value) = 0; - - virtual void set_item_index_int_3d(int index, const std::vector>>& value) = 0; - - virtual void set_item_index_int_4d(int index, const std::vector>>>& value) = 0; - - virtual void set_item_float(int index, float64 value) = 0; - - virtual void set_item_index_float(int index, const std::vector& value) = 0; - - virtual void set_item_index_float_2d(int index, const std::vector>& value) = 0; - - virtual void set_item_index_float_3d(int index, const std::vector>>& value) = 0; - - virtual void set_item_index_float_4d(int index, const std::vector>>>& value) = 0; - - virtual void set_item_tuple_int1(py::tuple args, int_ value) = 0; - - virtual void set_item_tuple_int2(py::tuple args, const std::vector& value) = 0; - - virtual void set_item_tuple_int3(py::tuple args, const std::vector>& value) = 0; - - virtual void set_item_tuple_int4(py::tuple args, const std::vector>>& value) = 0; - - virtual void set_item_tuple_int5(py::tuple args, const std::vector>>>& value) = 0; - - virtual void set_item_tuple_float1(py::tuple args, float64 value) = 0; - - virtual void set_item_tuple_float2(py::tuple args, const std::vector& value) = 0; - - virtual void set_item_tuple_float3(py::tuple args, const std::vector>& value) = 0; - - virtual void set_item_tuple_float4(py::tuple args, const std::vector>>& value) = 0; - - virtual void set_item_tuple_float5(py::tuple args, const std::vector>>>& value) = 0; - - virtual void set_item_vector_int1(const std::vector& indices, int_ value) = 0; - - virtual void set_item_vector_int2(const std::vector& indices, const std::vector& value) = 0; - - virtual void set_item_vector_int3(const std::vector& indices, const std::vector>& value) = 0; - - virtual void set_item_vector_int4(const std::vector& indices, const std::vector>>& value) = 0; - - virtual void set_item_vector_int5(const std::vector& indices, const std::vector>>>& value) = 0; - - virtual void set_item_vector_float1(const std::vector& indices, float64 value) = 0; - - virtual void set_item_vector_float2(const std::vector& indices, const std::vector& value) = 0; - - virtual void set_item_vector_float3(const std::vector& indices, const std::vector>& value) = 0; - - virtual void set_item_vector_float4(const std::vector& indices, const std::vector>>& value) = 0; - - virtual void set_item_vector_float5(const std::vector& indices, const std::vector>>>& value) = 0; - - virtual void set_item_slice_int1(py::slice slice, int_ value) = 0; - - virtual void set_item_slice_int2(py::slice slice, const std::vector& value) = 0; - - virtual void set_item_slice_int3(py::slice slice, const std::vector>& value) = 0; - - virtual void set_item_slice_int4(py::slice slice, const std::vector>>& value) = 0; - - virtual void set_item_slice_int5(py::slice slice, const std::vector>>>& value) = 0; - - virtual void set_item_slice_float1(py::slice slice, float64 value) = 0; - - virtual void set_item_slice_float2(py::slice slice, const std::vector& value) = 0; - - virtual void set_item_slice_float3(py::slice slice, const std::vector>& value) = 0; - - virtual void set_item_slice_float4(py::slice slice, const std::vector>>& value) = 0; - - virtual void set_item_slice_float5(py::slice slice, const std::vector>>>& value) = 0; - - virtual int len() const = 0; - - virtual std::string to_string() const = 0; -}; - -template -class ndarray : public ndarray_base { -public: - pkpy::numpy::ndarray data; - // Constructors - ndarray() = default; - - ndarray(const bool_ value) : data(value) {} - - ndarray(const int8 value) : data(value) {} - - ndarray(const int16 value) : data(value) {} - - ndarray(const int32 value) : data(value) {} - - ndarray(const int_ value) : data(static_cast(value)) {} - - ndarray(const float32 value) : data(value) {} - - ndarray(const float64 value) : data(static_cast(value)) {} - - ndarray(const pkpy::numpy::ndarray& _arr) : data(_arr) {} - - ndarray(const std::vector& init_list) : data(pkpy::numpy::adapt(init_list)) {} - - ndarray(const std::vector>& init_list) : data(pkpy::numpy::adapt(init_list)) {} - - ndarray(const std::vector>>& init_list) : data(pkpy::numpy::adapt(init_list)) {} - - ndarray(const std::vector>>>& init_list) : - data(pkpy::numpy::adapt(init_list)) {} - - ndarray(const std::vector>>>>& init_list) : - data(pkpy::numpy::adapt(init_list)) {} - - // Properties - int ndim() const override { return data.ndim(); } - - int size() const override { return data.size(); } - - std::string dtype() const override { return data.dtype(); } - - py::tuple shape() const override { return py::cast(data.shape()); } - - // Boolean Functions - bool all() const override { return data.all(); } - - bool any() const override { return data.any(); } - - // Aggregation Functions - py::object sum() const override { - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v) { - return py::int_(data.sum()); - } else if constexpr(std::is_same_v || std::is_same_v) { - return py::float_(data.sum()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - py::object sum_axis(int axis) const override { - if ((data.sum(axis)).ndim() == 0) { - return py::cast((data.sum(axis))()); - } else { - return py::cast(ndarray(data.sum(axis))); - } - } - - py::object sum_axes(py::tuple axes) const override { - std::vector axes_; - for(auto item: axes) { - axes_.push_back(py::cast(item)); - } - if ((data.sum(axes_)).ndim() == 0) { - return py::cast((data.sum(axes_))()); - } else { - return py::cast(ndarray(data.sum(axes_))); - } - } - - py::object prod() const override { - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v) { - return py::int_(data.prod()); - } else if constexpr(std::is_same_v || std::is_same_v) { - return py::float_(data.prod()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - py::object prod_axis(int axis) const override { - if ((data.prod(axis)).ndim() == 0) { - return py::cast((data.prod(axis))()); - } else { - return py::cast(ndarray(data.prod(axis))); - } - } - - py::object prod_axes(py::tuple axes) const override { - std::vector axes_; - for(auto item: axes) { - axes_.push_back(py::cast(item)); - } - if ((data.prod(axes_)).ndim() == 0) { - return py::cast((data.prod(axes_))()); - } else { - return py::cast(ndarray(data.prod(axes_))); - } - } - - py::object min() const override { - if constexpr (std::is_same_v) { - return py::bool_(data.min()); - } else if constexpr (std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v) { - return py::int_(data.min()); - } else if constexpr(std::is_same_v || std::is_same_v) { - return py::float_(data.min()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - py::object min_axis(int axis) const override { - if ((data.min(axis)).ndim() == 0) { - return py::cast((data.min(axis))()); - } else { - return py::cast(ndarray(data.min(axis))); - } - - } - - py::object min_axes(py::tuple axes) const override { - std::vector axes_; - for(auto item: axes) { - axes_.push_back(py::cast(item)); - } - if ((data.min(axes_)).ndim() == 0) { - return py::cast((data.min(axes_))()); - } else { - return py::cast(ndarray(data.min(axes_))); - } - } - - py::object max() const override { - if constexpr (std::is_same_v) { - return py::bool_(data.max()); - } else if constexpr (std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v) { - return py::int_(data.max()); - } else if constexpr(std::is_same_v || std::is_same_v) { - return py::float_(data.max()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - py::object max_axis(int axis) const override { - if ((data.max(axis)).ndim() == 0) { - return py::cast((data.max(axis))()); - } else { - return py::cast(ndarray(data.max(axis))); - } - } - - py::object max_axes(py::tuple axes) const override { - std::vector axes_; - for(auto item: axes) { - axes_.push_back(py::cast(item)); - } - if ((data.max(axes_)).ndim() == 0) { - return py::cast((data.max(axes_))()); - } else { - return py::cast(ndarray(data.max(axes_))); - } - } - - py::object mean() const override { - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v) { - return py::float_(data.mean()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - py::object mean_axis(int axis) const override { - if ((data.mean(axis)).ndim() == 0) { - return py::cast((data.mean(axis))()); - } else { - return py::cast(ndarray(data.mean(axis))); - } - } - - py::object mean_axes(py::tuple axes) const override { - std::vector axes_; - for(auto item: axes) - axes_.push_back(py::cast(item)); - if ((data.mean(axes_)).ndim() == 0) { - return py::cast((data.mean(axes_))()); - } else { - return py::cast(ndarray(data.mean(axes_))); - } - } - - py::object std() const override { - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v) { - return py::float_(data.std()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - py::object std_axis(int axis) const override { - if ((data.std(axis)).ndim() == 0) { - return py::cast((data.std(axis))()); - } else { - return py::cast(ndarray(data.std(axis))); - } - } - - py::object std_axes(py::tuple axes) const override { - std::vector axes_; - for(auto item: axes) - axes_.push_back(py::cast(item)); - if ((data.std(axes_)).ndim() == 0) { - return py::cast((data.std(axes_))()); - } else { - return py::cast(ndarray(data.std(axes_))); - } - } - - py::object var() const override { - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v) { - return py::float_(data.var()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - py::object var_axis(int axis) const override { - if ((data.var(axis)).ndim() == 0) { - return py::cast((data.var(axis))()); - } else { - return py::cast(ndarray(data.var(axis))); - } - } - - py::object var_axes(py::tuple axes) const override { - std::vector axes_; - for(auto item: axes) - axes_.push_back(py::cast(item)); - if ((data.var(axes_)).ndim() == 0) { - return py::cast((data.var(axes_))()); - } else { - return py::cast(ndarray(data.var(axes_))); - } - } - - py::object argmin() const override { - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v) { - return py::int_(data.argmin()); - } else if constexpr(std::is_same_v || std::is_same_v) { - return py::int_(data.argmin()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - ndarray_base* argmin_axis(int axis) const override { return new ndarray(data.argmin(axis)); } - - py::object argmax() const override { - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v) { - return py::int_(data.argmax()); - } else if constexpr(std::is_same_v || std::is_same_v) { - return py::int_(data.argmax()); - } else { - throw std::runtime_error("Unsupported type"); - } - } - - ndarray_base* argmax_axis(int axis) const override { return new ndarray(data.argmax(axis)); } - - ndarray_base* argsort() const override { return new ndarray(data.argsort()); } - - ndarray_base* argsort_axis(int axis) const override { return new ndarray(data.argsort(axis)); } - - void sort() override { data = data.sort(); } - - void sort_axis(int axis) override { data = data.sort(axis); } - - ndarray_base* reshape(const std::vector& shape) const override { return new ndarray(data.reshape(shape)); } - - void resize(const std::vector& shape) override { data = data.resize(shape); } - - ndarray_base* squeeze() const override { return new ndarray(data.squeeze()); } - - ndarray_base* squeeze_axis(int axis) const override { return new ndarray(data.squeeze(axis)); } - - ndarray_base* transpose() const override { return new ndarray(data.transpose()); } - - ndarray_base* transpose_tuple(py::tuple permutations) const override { - std::vector perm; - for(auto item: permutations) - perm.push_back(py::cast(item)); - return new ndarray(data.transpose(perm)); - } - - ndarray_base* transpose_args(py::args args) const override { - std::vector perm; - for(auto item: args) - perm.push_back(py::cast(item)); - return new ndarray(data.transpose(perm)); - } - - ndarray_base* repeat(int repeats, int axis) const override { - if (axis == INT_MAX) { - return new ndarray(data.repeat(repeats, data.ndim() - 1)); - } - return new ndarray(data.repeat(repeats, axis)); - } - - ndarray_base* repeat_axis(const std::vector& repeats, int axis) const override { - return new ndarray(data.repeat(repeats, axis)); - } - - ndarray_base* round() const override { return new ndarray(data.round()); } - - ndarray_base* flatten() const override { return new ndarray(data.flatten()); } - - ndarray_base* copy() const override { return new ndarray(data.copy()); } - - ndarray_base* astype(const std::string& dtype) const override { - if(dtype == "bool_") { - return new ndarray(data.template astype()); - } else if(dtype == "int8") { - return new ndarray(data.template astype()); - } else if(dtype == "int16") { - return new ndarray(data.template astype()); - } else if(dtype == "int32") { - return new ndarray(data.template astype()); - } else if(dtype == "int_") { - return new ndarray(data.template astype()); - } else if(dtype == "float32") { - return new ndarray(data.template astype()); - } else if(dtype == "float64") { - return new ndarray(data.template astype()); - } else { - throw std::invalid_argument("Invalid dtype"); - } - } - - py::list tolist() const override { - py::list list; - if(data.ndim() == 1) { - return py::cast(data.to_list()); - } else { - for(int i = 0; i < data.shape()[0]; i++) { - list.append(ndarray(data[i]).tolist()); - } - } - return list; - } - - // Dunder Methods - ndarray_base* eq(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 == int8 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 == int16 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 == int32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 == int64 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 == float32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 == float64 */ - return new ndarray(data == p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 == int8 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 == int16 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 == int32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 == int64 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 == float32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 == float64 */ - return new ndarray(data == p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 == int8 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 == int16 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 == int32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 == int64 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 == float32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 == float64 */ - return new ndarray(data == p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int64 == int8 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 == int16 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 == int32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 == int64 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 == float32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 == float64 */ - return new ndarray(data == p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* float32 == int8 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 == int16 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 == int32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 == int64 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 == float32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 == float64 */ - return new ndarray(data == p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* float64 == int8 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 == int16 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 == int32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 == int64 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 == float32 */ - return new ndarray(data == p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 == float64 */ - return new ndarray(data == p->data); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(data == other_.data); - } - - ndarray_base* ne(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 != int8 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 != int16 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 != int32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 != int64 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 != float32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 != float64 */ - return new ndarray(data != p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 != int8 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 != int16 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 != int32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 != int64 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 != float32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 != float64 */ - return new ndarray(data != p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 != int8 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 != int16 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 != int32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 != int64 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 != float32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 != float64 */ - return new ndarray(data != p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int64 != int8 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 != int16 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 != int32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 != int64 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 != float32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int64 != float64 */ - return new ndarray(data != p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* float32 != int8 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 != int16 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 != int32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 != int64 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 != float32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float32 != float64 */ - return new ndarray(data != p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* float64 != int8 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 != int16 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 != int32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 != int64 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 != float32 */ - return new ndarray(data != p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* float64 != float64 */ - return new ndarray(data != p->data); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(data != other_.data); - } - - ndarray_base* add(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 + int8 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 + int16 */ - return new ndarray((data + p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 + int32 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 + int64 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 + float32 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 + float64 */ - return new ndarray(data + p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 + int8 */ - return new ndarray((data + p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 + int16 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 + int32 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 + int64 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 + float32 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 + float64 */ - return new ndarray(data + p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 + int8 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 + int16 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 + int32 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 + int64 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 + float32 */ - return new ndarray(data + p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 + float64 */ - return new ndarray(data + p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int64 + int8 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 + int16 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 + int32 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 + int64 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 + float32 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 + float64 */ - return new ndarray(data + p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float32 + int8 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 + int16 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 + int32 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 + int64 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 + float32 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 + float64 */ - return new ndarray(data + p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float64 + int8 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 + int16 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 + int32 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 + int64 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 + float32 */ - return new ndarray(data + p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 + float64 */ - return new ndarray(data + p->data); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(data + other_.data); - } - - ndarray_base* add_bool(bool_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray((data + other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data + other).template astype()); - } else { - return new ndarray(data + other); - } - } - - ndarray_base* add_int(int_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray(data + other); - } else if constexpr(std::is_same_v) { - return new ndarray((data + other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data + other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data + other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray(data + other); - } else if constexpr(std::is_same_v) { - return new ndarray(data + other); - } else if constexpr(std::is_same_v) { - return new ndarray(data + other); - } - } - - ndarray_base* add_float(float64 other) const override { return new ndarray(data + other); } - - ndarray_base* sub(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 - int8 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 - int16 */ - return new ndarray((data - p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 - int32 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 - int64 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 - float32 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 - float64 */ - return new ndarray(data - p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 - int8 */ - return new ndarray((data - p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 - int16 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 - int32 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 - int64 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 - float32 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 - float64 */ - return new ndarray(data - p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 - int8 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 - int16 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 - int32 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 - int64 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 - float32 */ - return new ndarray(data - p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 - float64 */ - return new ndarray(data - p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int64 - int8 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 - int16 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 - int32 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 - int64 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 - float32 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 - float64 */ - return new ndarray(data - p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float32 - int8 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 - int16 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 - int32 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 - int64 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 - float32 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 - float64 */ - return new ndarray(data - p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float64 - int8 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 - int16 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 - int32 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 - int64 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 - float32 */ - return new ndarray(data - p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 - float64 */ - return new ndarray(data - p->data); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(data - other_.data); - } - - ndarray_base* sub_int(int_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray(data - other); - } else if constexpr(std::is_same_v) { - return new ndarray((data - other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data - other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data - other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray(data - other); - } else if constexpr(std::is_same_v) { - return new ndarray(data - other); - } else if constexpr(std::is_same_v) { - return new ndarray(data - other); - } - } - - ndarray_base* sub_float(float64 other) const override { return new ndarray(data - other); } - - ndarray_base* rsub_int(int_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray(other - data); - } else if constexpr(std::is_same_v) { - return new ndarray((other - data).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((other - data).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((other - data).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray(other - data); - } else if constexpr(std::is_same_v) { - return new ndarray(other - data); - } else if constexpr(std::is_same_v) { - return new ndarray(other - data); - } - } - - ndarray_base* rsub_float(float64 other) const override { return new ndarray(other - data); } - - ndarray_base* mul(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 * int8 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 * int16 */ - return new ndarray((data * p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 * int32 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 * int64 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 * float32 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 * float64 */ - return new ndarray(data * p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 * int8 */ - return new ndarray((data * p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 * int16 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 * int32 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 * int64 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 * float32 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 * float64 */ - return new ndarray(data * p->data); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 * int8 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 * int16 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 * int32 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 * int64 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 * float32 */ - return new ndarray(data * p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 * float64 */ - return new ndarray(data * p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int64 * int8 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 * int16 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 * int32 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 * int64 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 * float32 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 * float64 */ - return new ndarray(data * p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float32 * int8 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 * int16 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 * int32 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 * int64 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 * float32 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 * float64 */ - return new ndarray(data * p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float64 * int8 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 * int16 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 * int32 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 * int64 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 * float32 */ - return new ndarray(data * p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 * float64 */ - return new ndarray(data * p->data); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(data * other_.data); - } - - ndarray_base* mul_bool(bool_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray((data * other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data * other).template astype()); - } else { - return new ndarray(data * other); - } - } - - ndarray_base* mul_int(int_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray(data * other); - } else if constexpr(std::is_same_v) { - return new ndarray((data * other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data * other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray((data * other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray(data * other); - } else if constexpr(std::is_same_v) { - return new ndarray(data * other); - } else if constexpr(std::is_same_v) { - return new ndarray(data * other); - } - } - - ndarray_base* mul_float(float64 other) const override { return new ndarray(data * other); } - - ndarray_base* div(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* bool / bool */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool / int8 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool / int16 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool / int32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool / int64 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool / float32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool / float64 */ - return new ndarray(data / p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int8 / bool */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int8 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int16 */ - return new ndarray((data / p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 / int64 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 / float32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 / float64 */ - return new ndarray(data / p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int16 / bool */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int8 */ - return new ndarray((data / p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int16 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 / int64 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 / float32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 / float64 */ - return new ndarray(data / p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int32 / bool */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int8 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int16 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 / int64 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 / float32 */ - return new ndarray(data / p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 / float64 */ - return new ndarray(data / p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int64 / bool */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int8 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int16 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int32 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 / int64 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 / float32 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 / float64 */ - return new ndarray(data / p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float32 / bool */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int8 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int16 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int32 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 / int64 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 / float32 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 / float64 */ - return new ndarray(data / p->data); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float64 / bool */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int8 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int16 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int32 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 / int64 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 / float32 */ - return new ndarray(data / p->data); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 / float64 */ - return new ndarray(data / p->data); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(data / other_.data); - } - - ndarray_base* div_bool(bool_ other) const override { return new ndarray(data / other); } - - ndarray_base* div_int(int_ other) const override { return new ndarray(data / other); } - - ndarray_base* div_float(float64 other) const override { return new ndarray(data / other); } - - ndarray_base* rdiv_bool(bool_ other) const override { return new ndarray(other / data); } - - ndarray_base* rdiv_int(int_ other) const override { return new ndarray(other / data); } - - ndarray_base* rdiv_float(float64 other) const override { return new ndarray(other / data); } - - ndarray_base* matmul(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 @ int8 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ int16 */ - return new ndarray(pkpy::numpy::matmul(data, p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ int32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ int64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ float32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 @ float64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 @ int8 */ - return new ndarray(pkpy::numpy::matmul(data, p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ int16 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ int32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ int64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ float32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 @ float64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 @ int8 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ int16 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ int32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ int64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ float32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 @ float64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int64 @ int8 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ int16 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ int32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ int64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ float32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 @ float64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float32 @ int8 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ int16 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ int32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ int64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ float32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 @ float64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float64 @ int8 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ int16 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ int32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ int64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ float32 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 @ float64 */ - return new ndarray(pkpy::numpy::matmul(data, p->data)); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(pkpy::numpy::matmul(data, other_.data)); - } - - ndarray_base* pow(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 ** int8 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** int16 */ - return new ndarray(data.pow(p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** int32 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** int64 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** float32 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 ** float64 */ - return new ndarray(data.pow(p->data)); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 ** int8 */ - return new ndarray(data.pow(p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** int16 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** int32 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** int64 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** float32 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 ** float64 */ - return new ndarray(data.pow(p->data)); - } - } else if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 ** int8 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** int16 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** int32 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** int64 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** float32 */ - return new ndarray(data.pow(p->data)); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 ** float64 */ - return new ndarray(data.pow(p->data)); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* int64 ** int8 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** int16 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** int32 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** int64 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** float32 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* int64 ** float64 */ - return new ndarray(data.pow(p->data)); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float32 ** int8 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** int16 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** int32 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** int64 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** float32 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float32 ** float64 */ - return new ndarray(data.pow(p->data)); - } - } else if constexpr(std::is_same_v) { - if (auto p = dynamic_cast*>(&other)) { /* float64 ** int8 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** int16 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** int32 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** int64 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** float32 */ - return new ndarray(data.pow(p->data)); - } else if (auto p = dynamic_cast*>(&other)) { /* float64 ** float64 */ - return new ndarray(data.pow(p->data)); - } - } - - const ndarray& other_ = dynamic_cast&>(other); - return new ndarray(data.pow(other_.data)); - } - - ndarray_base* pow_int(int_ other) const override { return new ndarray(data.pow(other)); } - - ndarray_base* pow_float(float64 other) const override { return new ndarray(data.pow(other)); } - - ndarray_base* rpow_int(int_ other) const override { return new ndarray(pkpy::numpy::pow(other, data)); } - - ndarray_base* rpow_float(float64 other) const override { - return new ndarray(pkpy::numpy::pow(other, data)); - } - - int len() const override { return data.shape()[0]; } - - ndarray_base* and_array(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* bool & bool */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool & int8 */ - return new ndarray((data & p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* bool & int16 */ - return new ndarray((data & p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* bool & int32 */ - return new ndarray((data & p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* bool & int64 */ - return new ndarray((data & p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 & bool */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int8 */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int16 */ - return new ndarray((data & p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int32 */ - return new ndarray((data & p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 & int64 */ - return new ndarray((data & p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int16 & bool */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int8 */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int16 */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int32 */ - return new ndarray((data & p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int16 & int64 */ - return new ndarray((data & p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int32 & bool */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int8 */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int16 */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int32 */ - return new ndarray(data & p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int32 & int64 */ - return new ndarray((data & p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int64 & bool */ - return new ndarray(data & p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int8 */ - return new ndarray(data & p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int16 */ - return new ndarray(data & p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int32 */ - return new ndarray(data & p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 & int64 */ - return new ndarray(data & p->data); - } - } - - throw std::runtime_error("& operator is not compatible with floating types"); - } - - ndarray_base* and_bool(bool_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray(data & other); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } - - throw std::runtime_error("& operator is not compatible with floating types"); - } - - ndarray_base* and_int(int_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray((data & other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } else if constexpr(std::is_same_v) { - return new ndarray(data & other); - } - - throw std::runtime_error("& operator is not compatible with floating types"); - } - - ndarray_base* or_array(const ndarray_base& other) const override { - if constexpr(std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* bool | bool */ - return new ndarray(data | p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* bool | int8 */ - return new ndarray((data | p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* bool | int16 */ - return new ndarray((data | p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* bool | int32 */ - return new ndarray((data | p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* bool | int64 */ - return new ndarray((data | p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if(auto p = dynamic_cast*>(&other)) { /* int8 | bool */ - return new ndarray(data | p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int8 */ - return new ndarray(data | p->data); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int16 */ - return new ndarray((data | p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int32 */ - return new ndarray((data | p->data).template astype()); - } else if(auto p = dynamic_cast*>(&other)) { /* int8 | int64 */ - return new ndarray((data | p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int16 | bool */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int8 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int16 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int32 */ - return new ndarray((data | p->data).template astype()); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 | int64 */ - return new ndarray((data | p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int32 | bool */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int8 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int16 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int32 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 | int64 */ - return new ndarray((data | p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int64 | bool */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int8 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int16 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int32 */ - return new ndarray(data | p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 | int64 */ - return new ndarray(data | p->data); - } - } - - throw std::runtime_error("| operator is not compatible with floating types"); - } - - ndarray_base* or_bool(bool_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray(data | other); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } - - throw std::runtime_error("| operator is not compatible with floating types"); - } - - ndarray_base* or_int(int_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray((data | other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } else if constexpr(std::is_same_v) { - return new ndarray(data | other); - } - - throw std::runtime_error("| operator is not compatible with floating types"); - } - - ndarray_base* xor_array(const ndarray_base& other) const override { - if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* bool ^ bool */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int8 */ - return new ndarray((data ^ p->data).template astype()); - } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int16 */ - return new ndarray((data ^ p->data).template astype()); - } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int32 */ - return new ndarray((data ^ p->data).template astype()); - } else if (auto p = dynamic_cast *>(&other)) { /* bool ^ int64 */ - return new ndarray((data ^ p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int8 ^ bool */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int8 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int16 */ - return new ndarray((data ^ p->data).template astype()); - } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int32 */ - return new ndarray((data ^ p->data).template astype()); - } else if (auto p = dynamic_cast *>(&other)) { /* int8 ^ int64 */ - return new ndarray((data ^ p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int16 ^ bool */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int8 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int16 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int32 */ - return new ndarray((data ^ p->data).template astype()); - } else if (auto p = dynamic_cast *>(&other)) { /* int16 ^ int64 */ - return new ndarray((data ^ p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int32 ^ bool */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int8 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int16 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int32 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int32 ^ int64 */ - return new ndarray((data ^ p->data).template astype()); - } - } else if constexpr (std::is_same_v) { - if (auto p = dynamic_cast *>(&other)) { /* int64 ^ bool */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int8 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int16 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int32 */ - return new ndarray(data ^ p->data); - } else if (auto p = dynamic_cast *>(&other)) { /* int64 ^ int64 */ - return new ndarray(data ^ p->data); - } - } - - throw std::runtime_error("^ operator is not compatible with floating types"); - } - - ndarray_base* xor_bool(bool_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } - - throw std::runtime_error("^ operator is not compatible with floating types"); - } - - ndarray_base* xor_int(int_ other) const override { - if constexpr(std::is_same_v) { - return new ndarray((data ^ other).template astype()); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } else if constexpr(std::is_same_v) { - return new ndarray(data ^ other); - } - - throw std::runtime_error("^ operator is not compatible with floating types"); - } - - ndarray_base* invert() const override { - if constexpr(std::is_same_v) { - return new ndarray(!data); - } else if constexpr(std::is_same_v) { - return new ndarray(!data); - } else if constexpr(std::is_same_v) { - return new ndarray(!data); - } else if constexpr(std::is_same_v) { - return new ndarray(!data); - } else if constexpr(std::is_same_v) { - return new ndarray(!data); - } - - throw std::runtime_error("~ operator is not compatible with floating types"); - } - - py::object get_item_int(int index) const override { - if(index < 0) index += data.shape()[0]; - if(data.ndim() == 1) { - if constexpr(std::is_same_v) { - return py::bool_(data(index)); - } else if constexpr(std::is_same_v) { - return py::int_(data(index)); - } else if constexpr(std::is_same_v) { - return py::float_(data(index)); - } - } - return py::cast(ndarray(data[index])); - } - - py::object get_item_tuple(py::tuple args) const override { - pkpy::numpy::ndarray store = data; - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - for(int i = 0; i < indices.size() - 1; i++) { - if(indices[i] < 0) indices[i] += store.shape()[0]; - pkpy::numpy::ndarray temp = store[indices[i]]; - store = temp; - } - - if(indices[indices.size() - 1] < 0) indices[indices.size() - 1] += store.shape()[0]; - if(store.ndim() == 1) { - if constexpr(std::is_same_v) { - return py::bool_(store(indices[indices.size() - 1])); - } else if constexpr(std::is_same_v) { - return py::int_(store(indices[indices.size() - 1])); - } else if constexpr(std::is_same_v) { - return py::float_(store(indices[indices.size() - 1])); - } - } - return py::cast(ndarray(store[indices[indices.size() - 1]])); - } - - ndarray_base* get_item_vector(const std::vector& indices) const override { - return new ndarray(data[indices]); - } - - ndarray_base* get_item_slice(py::slice slice) const override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - - return new ndarray(data[std::make_tuple(start, stop, step)]); - } - - void set_item_int(int index, int_ value) override { - if constexpr(std::is_same_v) { - if (data.ndim() == 1) { - data.set_item(index, value); - } else { - data.set_item(index, pkpy::numpy::adapt(std::vector{value})); - } - } else if constexpr(std::is_same_v) { - if (data.ndim() == 1) { - data.set_item(index, static_cast(value)); - } else { - data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } - } - - void set_item_index_int(int index, const std::vector& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_index_int_2d(int index, const std::vector>& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_index_int_3d(int index, const std::vector>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_index_int_4d(int index, const std::vector>>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_float(int index, float64 value) override { - if constexpr(std::is_same_v) { - if (data.ndim() == 1) { - data.set_item(index, value); - } else { - data.set_item(index, pkpy::numpy::adapt(std::vector{value})); - } - } else if constexpr(std::is_same_v) { - if (data.ndim() == 1) { - data.set_item(index, static_cast(value)); - } else { - data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } - } - - void set_item_index_float(int index, const std::vector& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_index_float_2d(int index, const std::vector>& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_index_float_3d(int index, const std::vector>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_index_float_4d(int index, const std::vector>>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_tuple_int1(py::tuple args, int_ value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(std::vector{value})); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], static_cast(value)); - else if(indices.size() == 3 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], indices[2], static_cast(value)); - else if(indices.size() == 4 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], indices[2], indices[3], static_cast(value)); - else if(indices.size() == 5 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], static_cast(value)); - } - - void set_item_tuple_int2(py::tuple args, const std::vector& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_tuple_int3(py::tuple args, const std::vector>& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_tuple_int4(py::tuple args, const std::vector>>& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_tuple_int5(py::tuple args, const std::vector>>>& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_tuple_float1(py::tuple args, float64 value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(std::vector{value})); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], static_cast(value)); - else if(indices.size() == 3 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], indices[2], static_cast(value)); - else if(indices.size() == 4 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], indices[2], indices[3], static_cast(value)); - else if(indices.size() == 5 && indices.size() <= data.ndim()) - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], static_cast(value)); - } - - void set_item_tuple_float2(py::tuple args, const std::vector& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_tuple_float3(py::tuple args, const std::vector>& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_tuple_float4(py::tuple args, const std::vector>>& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_tuple_float5(py::tuple args, const std::vector>>>& value) override { - std::vector indices; - for(auto item: args) { - indices.push_back(py::cast(item)); - } - if(indices.size() == 1) { - int index = indices[0]; - if constexpr(std::is_same_v) { - data.set_item(index, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(index, (pkpy::numpy::adapt(value)).astype()); - } - } else if(indices.size() == 2 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 3 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 4 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], (pkpy::numpy::adapt(value)).astype()); - } - } - else if(indices.size() == 5 && indices.size() <= data.ndim()) { - if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], pkpy::numpy::adapt(value)); - } else if constexpr (std::is_same_v) { - data.set_item(indices[0], indices[1], indices[2], indices[3], indices[4], (pkpy::numpy::adapt(value)).astype()); - } - } - } - - void set_item_vector_int1(const std::vector& indices, int_ value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(std::vector{value})); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } - - void set_item_vector_int2(const std::vector& indices, const std::vector& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_vector_int3(const std::vector& indices, const std::vector>& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_vector_int4(const std::vector& indices, const std::vector>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_vector_int5(const std::vector& indices, const std::vector>>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_vector_float1(const std::vector& indices, float64 value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(std::vector{value})); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } - - void set_item_vector_float2(const std::vector& indices, const std::vector& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_vector_float3(const std::vector& indices, const std::vector>& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_vector_float4(const std::vector& indices, const std::vector>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_vector_float5(const std::vector& indices, const std::vector>>>& value) override { - if constexpr(std::is_same_v) { - data.set_item(indices, pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(indices, (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_int1(py::slice slice, int_ value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(std::vector{value})); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), - (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } - - void set_item_slice_int2(py::slice slice, const std::vector& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_int3(py::slice slice, const std::vector>& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_int4(py::slice slice, const std::vector>>& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_int5(py::slice slice, const std::vector>>>& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_float1(py::slice slice, float64 value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(std::vector{value})); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), - (pkpy::numpy::adapt(std::vector{value})).astype()); - } - } - - void set_item_slice_float2(py::slice slice, const std::vector& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_float3(py::slice slice, const std::vector>& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_float4(py::slice slice, const std::vector>>& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - void set_item_slice_float5(py::slice slice, const std::vector>>>& value) override { - int start = parseAttr(getattr(slice, "start")); - int stop = parseAttr(getattr(slice, "stop")); - int step = parseAttr(getattr(slice, "step")); - - if(step == INT_MAX) step = 1; - if(step > 0) { - if(start == INT_MAX) start = 0; - if(stop == INT_MAX) stop = data.shape()[0]; - } else if(step < 0) { - if(start == INT_MAX) start = data.shape()[0] - 1; - if(stop == INT_MAX) stop = -(1 + data.shape()[0]); - } - if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), pkpy::numpy::adapt(value)); - } else if constexpr(std::is_same_v) { - data.set_item(std::make_tuple(start, stop, step), (pkpy::numpy::adapt(value)).astype()); - } - } - - std::string to_string() const override { - std::ostringstream os; - os << data; - std::string result = os.str(); - - size_t pos = 0; - while ((pos = result.find('{', pos)) != std::string::npos) { - result.replace(pos, 1, "["); - pos += 1; - } - pos = 0; - while ((pos = result.find('}', pos)) != std::string::npos) { - result.replace(pos, 1, "]"); - pos += 1; - } - - if constexpr(std::is_same_v) { - size_t pos = 0; - while ((pos = result.find("true", pos)) != std::string::npos) { - result.replace(pos, 4, "True"); - pos += 4; - } - pos = 0; - while ((pos = result.find("false", pos)) != std::string::npos) { - result.replace(pos, 5, "False"); - pos += 5; - } - } - - for(int i = 0; i < result.size(); i++) { - if(result[i] == '\n') { - result.insert(i + 1, " "); - } - } - return result; - } -}; class Random { public: @@ -2869,89 +166,6 @@ void array_creation_registry(py::module_& m) { register_array_float<5>(m); } -// --- RDP helpers: bridge ndarray/list <-> Eigen types --- - -// Helper: extract Nx2 or Nx3 Eigen matrix from ndarray_base -static rdp::RowVectors ndarray_to_eigen(const ndarray_base& base, int& input_cols) { - int dims = base.ndim(); - if (dims != 2) throw std::invalid_argument("rdp: expected 2D array"); - auto shape_vec = base.shape(); - int rows = shape_vec[0].cast(); - int cols = shape_vec[1].cast(); - if (cols != 2 && cols != 3) throw std::invalid_argument("rdp: expected Nx2 or Nx3 array"); - input_cols = cols; - - if (auto* p = dynamic_cast*>(&base)) { - const double* ptr = p->data.get_array().data(); - if (cols == 3) { - return Eigen::Map(ptr, rows, 3); - } else { - rdp::RowVectors result(rows, 3); - result.setZero(); - Eigen::Map map2(ptr, rows, 2); - result.leftCols(2) = map2; - return result; - } - } - if (auto* p = dynamic_cast*>(&base)) { - const int_* iptr = p->data.get_array().data(); - rdp::RowVectors result(rows, 3); - result.setZero(); - for (int i = 0; i < rows; ++i) - for (int j = 0; j < cols; ++j) - result(i, j) = static_cast(iptr[i * cols + j]); - return result; - } - throw std::invalid_argument("rdp: unsupported ndarray dtype"); -} - -// Helper: convert vector> to Eigen Nx3 (zero-pad 2D to 3D) -static rdp::RowVectors vec2d_to_eigen_d(const std::vector>& coords, int& input_cols) { - int rows = (int)coords.size(); - if (rows == 0) throw std::invalid_argument("rdp: empty coords"); - int cols = (int)coords[0].size(); - if (cols != 2 && cols != 3) throw std::invalid_argument("rdp: expected Nx2 or Nx3"); - input_cols = cols; - rdp::RowVectors result(rows, 3); - result.setZero(); - for (int i = 0; i < rows; ++i) - for (int j = 0; j < cols; ++j) - result(i, j) = coords[i][j]; - return result; -} - -// Helper: convert vector> to Eigen Nx3 -static rdp::RowVectors vec2d_to_eigen_i(const std::vector>& coords, int& input_cols) { - int rows = (int)coords.size(); - if (rows == 0) throw std::invalid_argument("rdp: empty coords"); - int cols = (int)coords[0].size(); - if (cols != 2 && cols != 3) throw std::invalid_argument("rdp: expected Nx2 or Nx3"); - input_cols = cols; - rdp::RowVectors result(rows, 3); - result.setZero(); - for (int i = 0; i < rows; ++i) - for (int j = 0; j < cols; ++j) - result(i, j) = static_cast(coords[i][j]); - return result; -} - -// Helper: Eigen RowVectors result -> ndarray_base (return Nx2 or Nx3) -static std::unique_ptr eigen_to_ndarray(const rdp::RowVectors& mat, int output_cols) { - int N = (int)mat.rows(); - std::vector> data(N, std::vector(output_cols)); - for (int i = 0; i < N; ++i) - for (int j = 0; j < output_cols; ++j) - data[i][j] = mat(i, j); - return std::unique_ptr(new ndarray(data)); -} - -// Helper: Eigen VectorXi mask -> ndarray_base (1D int array) -static std::unique_ptr mask_to_ndarray(const Eigen::VectorXi& mask) { - std::vector data(mask.size()); - for (int i = 0; i < mask.size(); ++i) data[i] = mask[i]; - return std::unique_ptr(new ndarray(data)); -} - PYBIND11_MODULE(numpy, m) { m.doc() = "Python bindings for pkpy::numpy::ndarray using pybind11"; @@ -3619,54 +833,83 @@ PYBIND11_MODULE(numpy, m) { py::arg("rtol") = 1e-5, py::arg("atol") = 1e-8); - // --- RDP bindings --- + // --- RDP bindings (Eigen types auto-converted via pybind11/eigen.h type_caster) --- - // rdp from list> - m.def("rdp", [](std::vector> coords, double epsilon, bool recursive) -> std::unique_ptr { - int input_cols; - auto eigen_coords = vec2d_to_eigen_d(coords, input_cols); - auto result = rdp::douglas_simplify(eigen_coords, epsilon, recursive); - return eigen_to_ndarray(result, input_cols); - }, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); + auto rdp_doc = R"pbdoc( + Simplifies a given array of points using the Ramer-Douglas-Peucker algorithm. - // rdp from list> - m.def("rdp", [](std::vector> coords, double epsilon, bool recursive) -> std::unique_ptr { - int input_cols; - auto eigen_coords = vec2d_to_eigen_i(coords, input_cols); - auto result = rdp::douglas_simplify(eigen_coords, epsilon, recursive); - return eigen_to_ndarray(result, input_cols); - }, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); + Example: + >>> from pocket_numpy import rdp + >>> rdp([[1, 1], [2, 2], [3, 3], [4, 4]]) + [[1, 1], [4, 4]] + )pbdoc"; - // rdp from ndarray - m.def("rdp", [](const ndarray_base& coords, double epsilon, bool recursive) -> std::unique_ptr { - int input_cols; - auto eigen_coords = ndarray_to_eigen(coords, input_cols); - auto result = rdp::douglas_simplify(eigen_coords, epsilon, recursive); - return eigen_to_ndarray(result, input_cols); - }, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); + // rdp: Nx3 (auto-converted from ndarray via type_caster) + m.def("rdp", [](const Eigen::Ref& coords, double epsilon, bool recursive) -> rdp::RowVectors { + return rdp::douglas_simplify(coords, epsilon, recursive); + }, rdp_doc, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); - // rdp_mask from list> - m.def("rdp_mask", [](std::vector> coords, double epsilon, bool recursive) -> std::unique_ptr { - int input_cols; - auto eigen_coords = vec2d_to_eigen_d(coords, input_cols); - auto mask = rdp::douglas_simplify_mask(eigen_coords, epsilon, recursive); - return mask_to_ndarray(mask); - }, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); + // rdp: Nx2 (type_caster rejects Nx3, picks this overload) + m.def("rdp", [](const Eigen::Ref& coords, double epsilon, bool recursive) -> rdp::RowVectorsNx2 { + rdp::RowVectors xyzs(coords.rows(), 3); + xyzs.setZero(); + xyzs.leftCols(2) = coords; + return rdp::douglas_simplify(xyzs, epsilon, recursive).leftCols(2); + }, rdp_doc, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); - // rdp_mask from list> - m.def("rdp_mask", [](std::vector> coords, double epsilon, bool recursive) -> std::unique_ptr { - int input_cols; - auto eigen_coords = vec2d_to_eigen_i(coords, input_cols); - auto mask = rdp::douglas_simplify_mask(eigen_coords, epsilon, recursive); - return mask_to_ndarray(mask); + // rdp: from list> (stl.h handles the conversion) + m.def("rdp", [](std::vector> coords, double epsilon, bool recursive) -> std::unique_ptr { + int rows = (int)coords.size(); + if (rows == 0) throw std::invalid_argument("rdp: empty coords"); + int cols = (int)coords[0].size(); + if (cols != 2 && cols != 3) throw std::invalid_argument("rdp: expected Nx2 or Nx3"); + rdp::RowVectors eigen_coords(rows, 3); + eigen_coords.setZero(); + for (int i = 0; i < rows; ++i) + for (int j = 0; j < cols; ++j) + eigen_coords(i, j) = coords[i][j]; + auto result = rdp::douglas_simplify(eigen_coords, epsilon, recursive); + int N = (int)result.rows(); + std::vector> data(N, std::vector(cols)); + for (int i = 0; i < N; ++i) + for (int j = 0; j < cols; ++j) + data[i][j] = result(i, j); + return std::unique_ptr(new ::ndarray(data)); }, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); - // rdp_mask from ndarray - m.def("rdp_mask", [](const ndarray_base& coords, double epsilon, bool recursive) -> std::unique_ptr { - int input_cols; - auto eigen_coords = ndarray_to_eigen(coords, input_cols); + auto rdp_mask_doc = R"pbdoc( + Simplifies a given array of points using the Ramer-Douglas-Peucker algorithm. + Returns a mask. + )pbdoc"; + + // rdp_mask: Nx3 + m.def("rdp_mask", [](const Eigen::Ref& coords, double epsilon, bool recursive) -> Eigen::VectorXi { + return rdp::douglas_simplify_mask(coords, epsilon, recursive); + }, rdp_mask_doc, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); + + // rdp_mask: Nx2 + m.def("rdp_mask", [](const Eigen::Ref& coords, double epsilon, bool recursive) -> Eigen::VectorXi { + rdp::RowVectors xyzs(coords.rows(), 3); + xyzs.setZero(); + xyzs.leftCols(2) = coords; + return rdp::douglas_simplify_mask(xyzs, epsilon, recursive); + }, rdp_mask_doc, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); + + // rdp_mask: from list> + m.def("rdp_mask", [](std::vector> coords, double epsilon, bool recursive) -> std::unique_ptr { + int rows = (int)coords.size(); + if (rows == 0) throw std::invalid_argument("rdp: empty coords"); + int cols = (int)coords[0].size(); + if (cols != 2 && cols != 3) throw std::invalid_argument("rdp: expected Nx2 or Nx3"); + rdp::RowVectors eigen_coords(rows, 3); + eigen_coords.setZero(); + for (int i = 0; i < rows; ++i) + for (int j = 0; j < cols; ++j) + eigen_coords(i, j) = coords[i][j]; auto mask = rdp::douglas_simplify_mask(eigen_coords, epsilon, recursive); - return mask_to_ndarray(mask); + std::vector mask_data(mask.size()); + for (int i = 0; i < mask.size(); ++i) mask_data[i] = mask[i]; + return std::unique_ptr(new ::ndarray(mask_data)); }, py::arg("coords"), py::arg("epsilon") = 0.0, py::arg("recursive") = true); // Create pocket_numpy module that re-exports rdp/rdp_mask from numpy