#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 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: static py::object rand() { return py::float_(pkpy::numpy::random::rand()); } static ndarray_base* rand_shape(py::args args) { std::vector shape; for(auto item: args) shape.push_back(py::cast(item)); return new ndarray(pkpy::numpy::random::rand(shape)); } static py::object randn() { return py::float_(pkpy::numpy::random::randn()); } static ndarray_base* randn_shape(py::args args) { std::vector shape; for(auto item: args) shape.push_back(py::cast(item)); return new ndarray(pkpy::numpy::random::randn(shape)); } static py::object randint(int low, int high) { return py::int_(pkpy::numpy::random::randint(low, high)); } static ndarray_base* randint_shape(int_ low, int_ high, const std::vector& shape) { return new ndarray(pkpy::numpy::random::randint(low, high, shape)); } static ndarray_base* uniform(float64 low, float64 high, const std::vector& shape) { return new ndarray(pkpy::numpy::random::uniform(low, high, shape)); } }; // Declare ndarray types using ndarray_bool = ndarray; using ndarray_int8 = ndarray; using ndarray_int16 = ndarray; using ndarray_int32 = ndarray; using ndarray_int = ndarray; using ndarray_int = ndarray; using ndarray_float32 = ndarray; using ndarray_float = ndarray; using ndarray_float = ndarray; // Define template for creating n-dimensional vectors template struct nvector_impl { using type = std::vector::type>; }; template struct nvector_impl { using type = T; }; template using nvector = typename nvector_impl::type; // Transform nvector to nvector template nvector transform(const nvector& values) { nvector result; if constexpr(N != 0) { for (const auto& value : values) { result.push_back(transform(value)); } } else { result = static_cast(values); } return result; } void register_array_int(py::module_& m) { m.def("array", [](int_ value, const std::string& dtype) { if (dtype == "bool") { return std::unique_ptr(new ndarray_bool(value)); } else if (dtype == "int8") { return std::unique_ptr(new ndarray_int8(value)); } else if (dtype == "int16") { return std::unique_ptr(new ndarray_int16(value)); } else if (dtype == "int32") { return std::unique_ptr(new ndarray_int32(value)); } else if (dtype == "float32") { return std::unique_ptr(new ndarray_float32(value)); } else if (dtype == "float64") { return std::unique_ptr(new ndarray_float(value)); } return std::unique_ptr(new ndarray_int(value)); }, py::arg("value"), py::arg("dtype") = "int64"); } template void register_array_int(py::module_& m) { m.def("array", [](const nvector& values, const std::string& dtype) { if (dtype == "bool") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "int8") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "int16") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "int32") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "float32") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "float64") { return std::unique_ptr(new ndarray(transform(values))); } return std::unique_ptr(new ndarray(values)); }, py::arg("values"), py::arg("dtype") = "int64"); } void register_array_float(py::module_& m) { m.def("array", [](float64 value, const std::string& dtype) { if (dtype == "bool") { return std::unique_ptr(new ndarray_bool(value)); } else if (dtype == "int8") { return std::unique_ptr(new ndarray_int8(value)); } else if (dtype == "int16") { return std::unique_ptr(new ndarray_int16(value)); } else if (dtype == "int32") { return std::unique_ptr(new ndarray_int32(value)); } else if (dtype == "int64") { return std::unique_ptr(new ndarray_int(value)); } else if (dtype == "float32") { return std::unique_ptr(new ndarray_float32(value)); } return std::unique_ptr(new ndarray_float(value)); }, py::arg("value"), py::arg("dtype") = "float64"); } template void register_array_float(py::module_& m) { m.def("array", [](const nvector& values, const std::string& dtype) { if (dtype == "bool") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "int8") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "int16") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "int32") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "int64") { return std::unique_ptr(new ndarray(transform(values))); } else if (dtype == "float32") { return std::unique_ptr(new ndarray(transform(values))); } return std::unique_ptr(new ndarray(values)); }, py::arg("values"), py::arg("dtype") = "float64"); } // Register array creation functions. void array_creation_registry(py::module_& m) { register_array_int(m); register_array_int<1>(m); register_array_int<2>(m); register_array_int<3>(m); register_array_int<4>(m); register_array_int<5>(m); register_array_float(m); register_array_float<1>(m); register_array_float<2>(m); register_array_float<3>(m); register_array_float<4>(m); register_array_float<5>(m); } PYBIND11_MODULE(numpy, m) { m.doc() = "Python bindings for pkpy::numpy::ndarray using pybind11"; m.attr("bool_") = "bool"; m.attr("int8") = "int8"; m.attr("int16") = "int16"; m.attr("int32") = "int32"; m.attr("int64") = "int64"; m.attr("int_") = "int64"; m.attr("float32") = "float32"; m.attr("float64") = "float64"; m.attr("float_") = "float64"; py::class_(m, "ndarray") .def_property_readonly("ndim", &ndarray_base::ndim) .def_property_readonly("size", &ndarray_base::size) .def_property_readonly("dtype", &ndarray_base::dtype) .def_property_readonly("shape", &ndarray_base::shape) .def("all", &ndarray_base::all) .def("any", &ndarray_base::any) .def("sum", &ndarray_base::sum) .def("sum", &ndarray_base::sum_axis) .def("sum", &ndarray_base::sum_axes) .def("prod", &ndarray_base::prod) .def("prod", &ndarray_base::prod_axis) .def("prod", &ndarray_base::prod_axes) .def("min", &ndarray_base::min) .def("min", &ndarray_base::min_axis) .def("min", &ndarray_base::min_axes) .def("max", &ndarray_base::max) .def("max", &ndarray_base::max_axis) .def("max", &ndarray_base::max_axes) .def("mean", &ndarray_base::mean) .def("mean", &ndarray_base::mean_axis) .def("mean", &ndarray_base::mean_axes) .def("std", &ndarray_base::std) .def("std", &ndarray_base::std_axis) .def("std", &ndarray_base::std_axes) .def("var", &ndarray_base::var) .def("var", &ndarray_base::var_axis) .def("var", &ndarray_base::var_axes) .def("argmin", &ndarray_base::argmin) .def("argmin", &ndarray_base::argmin_axis) .def("argmax", &ndarray_base::argmax) .def("argmax", &ndarray_base::argmax_axis) .def("argsort", &ndarray_base::argsort) .def("argsort", &ndarray_base::argsort_axis) .def("sort", &ndarray_base::sort) .def("sort", &ndarray_base::sort_axis) .def("reshape", &ndarray_base::reshape) .def("resize", &ndarray_base::resize) .def("squeeze", &ndarray_base::squeeze) .def("squeeze", &ndarray_base::squeeze_axis) .def("transpose", &ndarray_base::transpose) .def("transpose", &ndarray_base::transpose_tuple) .def("transpose", &ndarray_base::transpose_args) .def("repeat", &ndarray_base::repeat, py::arg("repeats"), py::arg("axis") = INT_MAX) .def("repeat", &ndarray_base::repeat_axis) .def("round", &ndarray_base::round) .def("flatten", &ndarray_base::flatten) .def("copy", &ndarray_base::copy) .def("astype", &ndarray_base::astype) .def("tolist", &ndarray_base::tolist) .def("__eq__", &ndarray_base::eq) .def("__ne__", &ndarray_base::ne) .def("__add__", &ndarray_base::add) .def("__add__", &ndarray_base::add_bool) .def("__add__", &ndarray_base::add_int) .def("__add__", &ndarray_base::add_float) .def("__radd__", &ndarray_base::add_bool) .def("__radd__", &ndarray_base::add_int) .def("__radd__", &ndarray_base::add_float) .def("__sub__", &ndarray_base::sub) .def("__sub__", &ndarray_base::sub_int) .def("__sub__", &ndarray_base::sub_float) .def("__rsub__", &ndarray_base::rsub_int) .def("__rsub__", &ndarray_base::rsub_float) .def("__mul__", &ndarray_base::mul) .def("__mul__", &ndarray_base::mul_bool) .def("__mul__", &ndarray_base::mul_int) .def("__mul__", &ndarray_base::mul_float) .def("__rmul__", &ndarray_base::mul_bool) .def("__rmul__", &ndarray_base::mul_int) .def("__rmul__", &ndarray_base::mul_float) .def("__truediv__", &ndarray_base::div) .def("__truediv__", &ndarray_base::div_bool) .def("__truediv__", &ndarray_base::div_int) .def("__truediv__", &ndarray_base::div_float) .def("__rtruediv__", &ndarray_base::rdiv_bool) .def("__rtruediv__", &ndarray_base::rdiv_int) .def("__rtruediv__", &ndarray_base::rdiv_float) .def("__matmul__", &ndarray_base::matmul) .def("__pow__", &ndarray_base::pow) .def("__pow__", &ndarray_base::pow_int) .def("__pow__", &ndarray_base::pow_float) .def("__rpow__", &ndarray_base::rpow_int) .def("__rpow__", &ndarray_base::rpow_float) .def("__len__", &ndarray_base::len) .def("__and__", &ndarray_base::and_array) .def("__and__", &ndarray_base::and_bool) .def("__and__", &ndarray_base::and_int) .def("__rand__", &ndarray_base::and_bool) .def("__rand__", &ndarray_base::and_int) .def("__or__", &ndarray_base::or_array) .def("__or__", &ndarray_base::or_bool) .def("__or__", &ndarray_base::or_int) .def("__ror__", &ndarray_base::or_bool) .def("__ror__", &ndarray_base::or_int) .def("__xor__", &ndarray_base::xor_array) .def("__xor__", &ndarray_base::xor_bool) .def("__xor__", &ndarray_base::xor_int) .def("__rxor__", &ndarray_base::xor_bool) .def("__rxor__", &ndarray_base::xor_int) .def("__invert__", &ndarray_base::invert) .def("__getitem__", &ndarray_base::get_item_int) .def("__getitem__", &ndarray_base::get_item_tuple) .def("__getitem__", &ndarray_base::get_item_vector) .def("__getitem__", &ndarray_base::get_item_slice) .def("__setitem__", &ndarray_base::set_item_int) .def("__setitem__", &ndarray_base::set_item_index_int) .def("__setitem__", &ndarray_base::set_item_index_int_2d) .def("__setitem__", &ndarray_base::set_item_index_int_3d) .def("__setitem__", &ndarray_base::set_item_index_int_4d) .def("__setitem__", &ndarray_base::set_item_float) .def("__setitem__", &ndarray_base::set_item_index_float) .def("__setitem__", &ndarray_base::set_item_index_float_2d) .def("__setitem__", &ndarray_base::set_item_index_float_3d) .def("__setitem__", &ndarray_base::set_item_index_float_4d) .def("__setitem__", &ndarray_base::set_item_tuple_int1) .def("__setitem__", &ndarray_base::set_item_tuple_int2) .def("__setitem__", &ndarray_base::set_item_tuple_int3) .def("__setitem__", &ndarray_base::set_item_tuple_int4) .def("__setitem__", &ndarray_base::set_item_tuple_int5) .def("__setitem__", &ndarray_base::set_item_tuple_float1) .def("__setitem__", &ndarray_base::set_item_tuple_float2) .def("__setitem__", &ndarray_base::set_item_tuple_float3) .def("__setitem__", &ndarray_base::set_item_tuple_float4) .def("__setitem__", &ndarray_base::set_item_tuple_float5) .def("__setitem__", &ndarray_base::set_item_vector_int1) .def("__setitem__", &ndarray_base::set_item_vector_int2) .def("__setitem__", &ndarray_base::set_item_vector_int3) .def("__setitem__", &ndarray_base::set_item_vector_int4) .def("__setitem__", &ndarray_base::set_item_vector_int5) .def("__setitem__", &ndarray_base::set_item_vector_float1) .def("__setitem__", &ndarray_base::set_item_vector_float2) .def("__setitem__", &ndarray_base::set_item_vector_float3) .def("__setitem__", &ndarray_base::set_item_vector_float4) .def("__setitem__", &ndarray_base::set_item_vector_float5) .def("__setitem__", &ndarray_base::set_item_slice_int1) .def("__setitem__", &ndarray_base::set_item_slice_int2) .def("__setitem__", &ndarray_base::set_item_slice_int3) .def("__setitem__", &ndarray_base::set_item_slice_int4) .def("__setitem__", &ndarray_base::set_item_slice_int5) .def("__setitem__", &ndarray_base::set_item_slice_float1) .def("__setitem__", &ndarray_base::set_item_slice_float2) .def("__setitem__", &ndarray_base::set_item_slice_float3) .def("__setitem__", &ndarray_base::set_item_slice_float4) .def("__setitem__", &ndarray_base::set_item_slice_float5) .def("__str__", [](const ndarray_base& self) { std::ostringstream os; os << self.to_string(); return os.str(); }) .def("__repr__", [](const ndarray_base& self) { std::ostringstream os; os << "array(" << self.to_string() << ")"; return os.str(); }); py::class_, ndarray_base>(m, "ndarray_int8") .def(py::init<>()) .def(py::init()) .def(py::init&>()) .def(py::init>&>()) .def(py::init>>&>()) .def(py::init>>>&>()) .def(py::init>>>>&>()); py::class_, ndarray_base>(m, "ndarray_int16") .def(py::init<>()) .def(py::init()) .def(py::init&>()) .def(py::init>&>()) .def(py::init>>&>()) .def(py::init>>>&>()) .def(py::init>>>>&>()); py::class_, ndarray_base>(m, "ndarray_int32") .def(py::init<>()) .def(py::init()) .def(py::init&>()) .def(py::init>&>()) .def(py::init>>&>()) .def(py::init>>>&>()) .def(py::init>>>>&>()); py::class_, ndarray_base>(m, "ndarray_bool") .def(py::init<>()) .def(py::init()) .def(py::init&>()) .def(py::init>&>()) .def(py::init>>&>()) .def(py::init>>>&>()) .def(py::init>>>>&>()); py::class_, ndarray_base>(m, "ndarray_int") .def(py::init<>()) .def(py::init()) .def(py::init&>()) .def(py::init>&>()) .def(py::init>>&>()) .def(py::init>>>&>()) .def(py::init>>>>&>()); py::class_, ndarray_base>(m, "ndarray_float32") .def(py::init<>()) .def(py::init()) .def(py::init&>()) .def(py::init>&>()) .def(py::init>>&>()) .def(py::init>>>&>()) .def(py::init>>>>&>()); py::class_, ndarray_base>(m, "ndarray_float") .def(py::init<>()) .def(py::init()) .def(py::init&>()) .def(py::init>&>()) .def(py::init>>&>()) .def(py::init>>>&>()) .def(py::init>>>>&>()); py::class_(m, "random") .def_static("rand", &Random::rand) .def_static("rand_shape", &Random::rand_shape) .def_static("randn", &Random::randn) .def_static("randn_shape", &Random::randn_shape) .def_static("randint", &Random::randint) .def_static("randint_shape", &Random::randint_shape) .def_static("uniform", &Random::uniform); array_creation_registry(m); m.def("array", [](bool_ value) { return std::unique_ptr(new ndarray_bool(value)); }); m.def("array", [](const std::vector& values) { return std::unique_ptr(new ndarray_bool(values)); }); m.def("array", [](const std::vector>& values) { return std::unique_ptr(new ndarray_bool(values)); }); m.def("array", [](const std::vector>>& values) { return std::unique_ptr(new ndarray_bool(values)); }); m.def("array", [](const std::vector>>>& values) { return std::unique_ptr(new ndarray_bool(values)); }); m.def("array", [](const std::vector>>>>& values) { return std::unique_ptr(new ndarray_bool(values)); }); m.def("array", [](int8 value) { return std::unique_ptr(new ndarray_int8(value)); }); m.def("array", [](const std::vector& values) { return std::unique_ptr(new ndarray_int8(values)); }); m.def("array", [](const std::vector>& values) { return std::unique_ptr(new ndarray_int8(values)); }); m.def("array", [](const std::vector>>& values) { return std::unique_ptr(new ndarray_int8(values)); }); m.def("array", [](const std::vector>>>& values) { return std::unique_ptr(new ndarray_int8(values)); }); m.def("array", [](const std::vector>>>>& values) { return std::unique_ptr(new ndarray_int8(values)); }); m.def("array", [](int16 value) { return std::unique_ptr(new ndarray_int16(value)); }); m.def("array", [](const std::vector& values) { return std::unique_ptr(new ndarray_int16(values)); }); m.def("array", [](const std::vector>& values) { return std::unique_ptr(new ndarray_int16(values)); }); m.def("array", [](const std::vector>>& values) { return std::unique_ptr(new ndarray_int16(values)); }); m.def("array", [](const std::vector>>>& values) { return std::unique_ptr(new ndarray_int16(values)); }); m.def("array", [](const std::vector>>>>& values) { return std::unique_ptr(new ndarray_int16(values)); }); m.def("array", [](int32 value) { return std::unique_ptr(new ndarray_int32(value)); }); m.def("array", [](const std::vector& values) { return std::unique_ptr(new ndarray_int32(values)); }); m.def("array", [](const std::vector>& values) { return std::unique_ptr(new ndarray_int32(values)); }); m.def("array", [](const std::vector>>& values) { return std::unique_ptr(new ndarray_int32(values)); }); m.def("array", [](const std::vector>>>& values) { return std::unique_ptr(new ndarray_int32(values)); }); m.def("array", [](const std::vector>>>>& values) { return std::unique_ptr(new ndarray_int32(values)); }); m.def("array", [](float32 value) { return std::unique_ptr(new ndarray_float32(value)); }); m.def("array", [](const std::vector& values) { return std::unique_ptr(new ndarray_float32(values)); }); m.def("array", [](const std::vector>& values) { return std::unique_ptr(new ndarray_float32(values)); }); m.def("array", [](const std::vector>>& values) { return std::unique_ptr(new ndarray_float32(values)); }); m.def("array", [](const std::vector>>>& values) { return std::unique_ptr(new ndarray_float32(values)); }); m.def("array", [](const std::vector>>>>& values) { return std::unique_ptr(new ndarray_float32(values)); }); // Array Creation Functions m.def("ones", [](const std::vector& shape) { return std::unique_ptr(new ndarray_float(pkpy::numpy::ones(shape))); }); m.def("zeros", [](const std::vector& shape) { return std::unique_ptr(new ndarray_float(pkpy::numpy::zeros(shape))); }); m.def("full", [](const std::vector& shape, int_ value) { return std::unique_ptr(new ndarray_int(pkpy::numpy::full(shape, value))); }); m.def("full", [](const std::vector& shape, float64 value) { return std::unique_ptr(new ndarray_float(pkpy::numpy::full(shape, value))); }); m.def("identity", [](int n) { return std::unique_ptr(new ndarray_float(pkpy::numpy::identity(n))); }); m.def("arange", [](int_ stop) { return std::unique_ptr(new ndarray_int(pkpy::numpy::arange(0, stop))); }); m.def("arange", [](int_ start, int_ stop) { return std::unique_ptr(new ndarray_int(pkpy::numpy::arange(start, stop))); }); m.def("arange", [](int_ start, int_ stop, int_ step) { return std::unique_ptr(new ndarray_int(pkpy::numpy::arange(start, stop, step))); }); m.def("arange", [](float64 stop) { return std::unique_ptr(new ndarray_float(pkpy::numpy::arange(0, stop))); }); m.def("arange", [](float64 start, float64 stop) { return std::unique_ptr(new ndarray_float(pkpy::numpy::arange(start, stop))); }); m.def("arange", [](float64 start, float64 stop, float64 step) { return std::unique_ptr(new ndarray_float(pkpy::numpy::arange(start, stop, step))); }); m.def( "linspace", [](float64 start, float64 stop, int num, bool endpoint) { return std::unique_ptr(new ndarray_float(pkpy::numpy::linspace(start, stop, num, endpoint))); }, py::arg("start"), py::arg("stop"), py::arg("num") = 50, py::arg("endpoint") = true); // Trigonometric Functions m.def("sin", [](const ndarray_base& arr) { if (auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::sin(p->data))); } else if (auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::sin(p->data))); } else if (auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::sin(p->data))); } else if (auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::sin(p->data))); } else if (auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::sin(p->data))); } else if (auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::sin(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("cos", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::cos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::cos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::cos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::cos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::cos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::cos(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("tan", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::tan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::tan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::tan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::tan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::tan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::tan(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("arcsin", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arcsin(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arcsin(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arcsin(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arcsin(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arcsin(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arcsin(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("arccos", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arccos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arccos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arccos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arccos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arccos(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arccos(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("arctan", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arctan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arctan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arctan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arctan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arctan(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::arctan(p->data))); } throw std::invalid_argument("Invalid dtype"); }); // Exponential and Logarithmic Functions m.def("exp", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::exp(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::exp(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::exp(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::exp(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::exp(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::exp(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("log", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("log2", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log2(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log2(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log2(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log2(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log2(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log2(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("log10", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log10(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log10(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log10(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log10(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log10(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::log10(p->data))); } throw std::invalid_argument("Invalid dtype"); }); // Miscellaneous Functions m.def("round", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::round(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::round(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::round(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::round(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::round(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::round(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("floor", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::floor(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::floor(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::floor(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::floor(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::floor(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::floor(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("ceil", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::ceil(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::ceil(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::ceil(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::ceil(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::ceil(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::ceil(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def("abs", [](const ndarray_base& arr) { if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::abs(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::abs(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::abs(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::abs(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::abs(p->data))); } else if(auto p = dynamic_cast*>(&arr)) { return std::unique_ptr(new ndarray(pkpy::numpy::abs(p->data))); } throw std::invalid_argument("Invalid dtype"); }); m.def( "concatenate", [](const ndarray_base& arr1, const ndarray_base& arr2, int axis) { if(auto p = dynamic_cast*>(&arr1)) { if(auto q = dynamic_cast*>(&arr2)) { return std::unique_ptr( new ndarray(pkpy::numpy::concatenate(p->data, q->data, axis))); } else if(auto q = dynamic_cast*>(&arr2)) { return std::unique_ptr( new ndarray(pkpy::numpy::concatenate(p->data, q->data, axis))); } } else if(auto p = dynamic_cast*>(&arr1)) { if(auto q = dynamic_cast*>(&arr2)) { return std::unique_ptr( new ndarray(pkpy::numpy::concatenate(p->data, q->data, axis))); } else if(auto q = dynamic_cast*>(&arr2)) { return std::unique_ptr( new ndarray(pkpy::numpy::concatenate(p->data, q->data, axis))); } } throw std::invalid_argument("Invalid dtype"); }, py::arg("arr1"), py::arg("arr2"), py::arg("axis") = 0); // Constants m.attr("pi") = pkpy::numpy::pi; m.attr("inf") = pkpy::numpy::inf; // Testing Functions m.def( "allclose", [](const ndarray_base& arr1, const ndarray_base& arr2, float64 rtol, float64 atol) { if(auto p = dynamic_cast*>(&arr1)) { if(auto q = dynamic_cast*>(&arr2)) { return pkpy::numpy::allclose(p->data, q->data, rtol, atol); } else if(auto q = dynamic_cast*>(&arr2)) { return pkpy::numpy::allclose(p->data, q->data, rtol, atol); } } else if(auto p = dynamic_cast*>(&arr1)) { if(auto q = dynamic_cast*>(&arr2)) { return pkpy::numpy::allclose(p->data, q->data, rtol, atol); } else if(auto q = dynamic_cast*>(&arr2)) { return pkpy::numpy::allclose(p->data, q->data, rtol, atol); } } throw std::invalid_argument("Invalid dtype"); }, py::arg("arr1"), py::arg("arr2"), py::arg("rtol") = 1e-5, py::arg("atol") = 1e-8); }