From 42db99759ffde6ee16f8d2d6aba26e65bc8f35f5 Mon Sep 17 00:00:00 2001 From: AndreaRigoni Date: Thu, 5 Mar 2026 14:26:05 +0000 Subject: [PATCH] fix py dense --- .gitignore | 5 +- src/Core/Vector.h | 5 ++ src/Math/Dense.h | 8 +- src/Python/CMakeLists.txt | 6 +- src/Python/math_bindings.cpp | 114 ++++++++++++++++++++----- src/Python/testing/core_pybind_test.py | 2 +- src/Python/testing/math_pybind_test.py | 61 +++++++++++++ test.cpp | 10 --- 8 files changed, 174 insertions(+), 37 deletions(-) delete mode 100644 test.cpp diff --git a/.gitignore b/.gitignore index 8cd3cea..07b2233 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ compile_commands.json dist/ build_python/ -src/Python/uLib/*.so* \ No newline at end of file +src/Python/uLib/*.so* +src/Python/uLib/*.pyd +src/Python/uLib/*.pyc +src/Python/uLib/__pycache__ diff --git a/src/Core/Vector.h b/src/Core/Vector.h index 2622816..d7cf928 100644 --- a/src/Core/Vector.h +++ b/src/Core/Vector.h @@ -117,6 +117,10 @@ bool operator!=(const MetaAllocator &, const MetaAllocator &) { return false; } + + + + // Vector Implemetation ... wraps std::vector template class Vector : public std::vector> { typedef std::vector> BaseClass; @@ -136,6 +140,7 @@ public: Vector(unsigned int size) : BaseClass(size) {} Vector(unsigned int size, T &value) : BaseClass(size, value) {} Vector() : BaseClass(0) {} + Vector(std::initializer_list init) : BaseClass(init) {} inline VectorCommaInit operator<<(T scalar) { return VectorCommaInit(this, scalar); diff --git a/src/Math/Dense.h b/src/Math/Dense.h index ef302a3..5f08d36 100644 --- a/src/Math/Dense.h +++ b/src/Math/Dense.h @@ -47,6 +47,7 @@ #ifndef ULIB_DENSEMATRIX_H #define ULIB_DENSEMATRIX_H +// #include #include #include @@ -144,6 +145,11 @@ typedef Eigen::Matrix2d Matrix2d; typedef Eigen::Matrix3d Matrix3d; typedef Eigen::Matrix4d Matrix4d; +typedef Eigen::MatrixXi MatrixXi; +typedef Eigen::MatrixXf MatrixXf; +typedef Eigen::MatrixXd MatrixXd; + + //////////////////////////////////////////////////////////////////////////////// // Vector String interaction /////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -185,7 +191,7 @@ std::string VectorxT_ToString(const Eigen::Matrix &vec) { // } template -void operator>>(std::string &str, Eigen::Matrix &vec) { +void operator >> (std::string &str, Eigen::Matrix &vec) { VectorxT_StringTo(vec, str); } diff --git a/src/Python/CMakeLists.txt b/src/Python/CMakeLists.txt index 095031f..b165b98 100644 --- a/src/Python/CMakeLists.txt +++ b/src/Python/CMakeLists.txt @@ -38,15 +38,15 @@ if(BUILD_TESTING) add_test(NAME pybind_general COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/pybind_test.py) set_tests_properties(pybind_general PROPERTIES - ENVIRONMENT "PYTHONPATH=$") + ENVIRONMENT "PYTHONPATH=$:${PROJECT_SOURCE_DIR}/src/Python") add_test(NAME pybind_core COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/core_pybind_test.py) set_tests_properties(pybind_core PROPERTIES - ENVIRONMENT "PYTHONPATH=$") + ENVIRONMENT "PYTHONPATH=$:${PROJECT_SOURCE_DIR}/src/Python") add_test(NAME pybind_math COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/testing/math_pybind_test.py) set_tests_properties(pybind_math PROPERTIES - ENVIRONMENT "PYTHONPATH=$") + ENVIRONMENT "PYTHONPATH=$:${PROJECT_SOURCE_DIR}/src/Python") endif() diff --git a/src/Python/math_bindings.cpp b/src/Python/math_bindings.cpp index fcb2394..2c60f88 100644 --- a/src/Python/math_bindings.cpp +++ b/src/Python/math_bindings.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "Math/Dense.h" #include "Math/Transform.h" #include "Math/Geometry.h" @@ -32,34 +34,104 @@ PYBIND11_MAKE_OPAQUE(uLib::Vector); PYBIND11_MAKE_OPAQUE(uLib::Vector); PYBIND11_MAKE_OPAQUE(uLib::Vector); PYBIND11_MAKE_OPAQUE(uLib::Vector); + PYBIND11_MAKE_OPAQUE(uLib::Vector); PYBIND11_MAKE_OPAQUE(uLib::Vector); +template +void bind_eigen_type(py::module_ &m, const char *name) { + using Scalar = typename MatrixType::Scalar; + constexpr bool is_vector = MatrixType::IsVectorAtCompileTime; + + // Default constructor (zeros) + m.def(name, []() -> MatrixType { + if constexpr (MatrixType::RowsAtCompileTime == Eigen::Dynamic || MatrixType::ColsAtCompileTime == Eigen::Dynamic) { + return MatrixType(); // Empty dynamic matrix + } else { + return MatrixType::Zero(); // Zero static matrix + } + }); + + // Specialized constructor for dynamic matrices + if constexpr (MatrixType::RowsAtCompileTime == Eigen::Dynamic || MatrixType::ColsAtCompileTime == Eigen::Dynamic) { + m.def(name, [](int rows, int cols) -> MatrixType { + MatrixType mat; + mat.setZero(rows, cols); + return mat; + }); + } + + // Initialize from list + m.def(name, [](py::list l) -> MatrixType { + MatrixType mat; + if constexpr (is_vector) { + mat.setZero(l.size()); + for (size_t i = 0; i < l.size(); ++i) { + mat(i) = l[i].cast(); + } + } else { + int rows = MatrixType::RowsAtCompileTime == Eigen::Dynamic ? (int)std::sqrt(l.size()) : MatrixType::RowsAtCompileTime; + int cols = MatrixType::ColsAtCompileTime == Eigen::Dynamic ? (int)std::sqrt(l.size()) : MatrixType::ColsAtCompileTime; + mat.setZero(rows, cols); + for (size_t i = 0; i < (size_t)l.size(); ++i) { + mat(i / cols, i % cols) = l[i].cast(); + } + } + return mat; + }); + + // Initialize from py::array + m.def(name, [](py::array_t arr) -> MatrixType { + auto buf = arr.request(); + MatrixType mat; + if constexpr (is_vector) { + mat.setZero(buf.size); + Scalar* ptr = static_cast(buf.ptr); + for (ssize_t i = 0; i < buf.size; ++i) mat(i) = ptr[i]; + } else { + int rows = buf.shape.size() > 0 ? (int)buf.shape[0] : 1; + int cols = buf.shape.size() > 1 ? (int)buf.shape[1] : 1; + mat.setZero(rows, cols); + Scalar* ptr = static_cast(buf.ptr); + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + mat(i, j) = ptr[i * cols + j]; + } + } + } + return mat; + }); +} + void init_math(py::module_ &m) { // 1. Basic Eigen Types (Vectors and Matrices) - py::class_(m, "Vector1f").def(py::init<>()); - py::class_(m, "Vector2f").def(py::init<>()); - py::class_(m, "Vector3f").def(py::init<>()); - py::class_(m, "Vector4f").def(py::init<>()); - py::class_(m, "Vector1i").def(py::init<>()); - py::class_(m, "Vector2i").def(py::init<>()); - py::class_(m, "Vector3i").def(py::init<>()); - py::class_(m, "Vector4i").def(py::init<>()); - py::class_(m, "Vector1d").def(py::init<>()); - py::class_(m, "Vector2d").def(py::init<>()); - py::class_(m, "Vector3d").def(py::init<>()); - py::class_(m, "Vector4d").def(py::init<>()); + bind_eigen_type(m, "Vector1f"); + bind_eigen_type(m, "Vector2f"); + bind_eigen_type(m, "Vector3f"); + bind_eigen_type(m, "Vector4f"); + bind_eigen_type(m, "Vector1i"); + bind_eigen_type(m, "Vector2i"); + bind_eigen_type(m, "Vector3i"); + bind_eigen_type(m, "Vector4i"); + bind_eigen_type(m, "Vector1d"); + bind_eigen_type(m, "Vector2d"); + bind_eigen_type(m, "Vector3d"); + bind_eigen_type(m, "Vector4d"); - py::class_(m, "Matrix2f").def(py::init<>()); - py::class_(m, "Matrix3f").def(py::init<>()); - py::class_(m, "Matrix4f").def(py::init<>()); - py::class_(m, "Matrix2i").def(py::init<>()); - py::class_(m, "Matrix3i").def(py::init<>()); - py::class_(m, "Matrix4i").def(py::init<>()); - py::class_(m, "Matrix2d").def(py::init<>()); - py::class_(m, "Matrix3d").def(py::init<>()); - py::class_(m, "Matrix4d").def(py::init<>()); + bind_eigen_type(m, "Matrix2f"); + bind_eigen_type(m, "Matrix3f"); + bind_eigen_type(m, "Matrix4f"); + bind_eigen_type(m, "Matrix2i"); + bind_eigen_type(m, "Matrix3i"); + bind_eigen_type(m, "Matrix4i"); + bind_eigen_type(m, "Matrix2d"); + bind_eigen_type(m, "Matrix3d"); + bind_eigen_type(m, "Matrix4d"); + + bind_eigen_type(m, "MatrixXi"); + bind_eigen_type(m, "MatrixXf"); + bind_eigen_type(m, "MatrixXd"); // 2. Homogeneous types py::class_(m, "HPoint3f") diff --git a/src/Python/testing/core_pybind_test.py b/src/Python/testing/core_pybind_test.py index 9cd3f56..1ce470d 100644 --- a/src/Python/testing/core_pybind_test.py +++ b/src/Python/testing/core_pybind_test.py @@ -19,7 +19,7 @@ class TestCoreOptions(unittest.TestCase): class TestCoreObject(unittest.TestCase): def test_object(self): obj = uLib.Core.Object() - self.assertIsNotN one(obj) + self.assertIsNotNone(obj) class TestCoreTimer(unittest.TestCase): def test_timer(self): diff --git a/src/Python/testing/math_pybind_test.py b/src/Python/testing/math_pybind_test.py index f3d7c2a..a2e48c0 100644 --- a/src/Python/testing/math_pybind_test.py +++ b/src/Python/testing/math_pybind_test.py @@ -10,6 +10,67 @@ def vector4f0(v, target): diff[3] = 0 # ignoring w return np.all(np.abs(diff) < 0.001) + +class TestMathMatrix(unittest.TestCase): + + def test_matrix(self): + def check_1234(m2f): + self.assertEqual(m2f[0, 0], 1) + self.assertEqual(m2f[0, 1], 2) + self.assertEqual(m2f[1, 0], 3) + self.assertEqual(m2f[1, 1], 4) + + m2f = uLib.Math.Matrix2f() + m2f[0, 0] = 1 + m2f[0, 1] = 2 + m2f[1, 0] = 3 + m2f[1, 1] = 4 + check_1234(m2f) + + m2f = uLib.Math.Matrix2f([1, 2, 3, 4]) + check_1234(m2f) + + # m2f = uLib.Math.Matrix2f([[1, 2], [3, 4]]) + # check_1234(m2f) + + m2f = uLib.Math.Matrix2f(np.array([[1, 2], [3, 4]])) + check_1234(m2f) + + def test_vector2(self): + v2f = uLib.Math.Vector2f() + v2f[0] = 1 + v2f[1] = 2 + self.assertEqual(v2f[0], 1) + self.assertEqual(v2f[1], 2) + + v2f = uLib.Math.Vector2f([1, 2]) + self.assertEqual(v2f[0], 1) + self.assertEqual(v2f[1], 2) + + v2f = uLib.Math.Vector2f(np.array([1, 2])) + self.assertEqual(v2f[0], 1) + self.assertEqual(v2f[1], 2) + + def test_vector3(self): + v3f = uLib.Math.Vector3f() + v3f[0] = 1 + v3f[1] = 2 + v3f[2] = 3 + self.assertEqual(v3f[0], 1) + self.assertEqual(v3f[1], 2) + self.assertEqual(v3f[2], 3) + + v3f = uLib.Math.Vector3f([1, 2, 3]) + self.assertEqual(v3f[0], 1) + self.assertEqual(v3f[1], 2) + self.assertEqual(v3f[2], 3) + + v3f = uLib.Math.Vector3f(np.array([1, 2, 3])) + self.assertEqual(v3f[0], 1) + self.assertEqual(v3f[1], 2) + self.assertEqual(v3f[2], 3) + + class TestMathGeometry(unittest.TestCase): def test_geometry(self): Geo = uLib.Math.Geometry() diff --git a/test.cpp b/test.cpp deleted file mode 100644 index 9969c96..0000000 --- a/test.cpp +++ /dev/null @@ -1,10 +0,0 @@ - -#include "Core/Object.h" - - - -int main() -{ - uLib::Object obj; - return 0; -}