diff --git a/Cargo.toml b/Cargo.toml index 6eeabbf..b085b41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ members = [ "crates/sophus", "crates/sophus_core", "crates/sophus_lie", - "crates/sophus_pyo3", "crates/sophus_image", "crates/sophus_sensor", "crates/sophus_opt", @@ -29,7 +28,6 @@ sophus_core = {path = "crates/sophus_core", version = "0.10.0"} sophus_image = {path = "crates/sophus_image", version = "0.10.0"} sophus_lie = {path = "crates/sophus_lie", version = "0.10.0"} sophus_opt = {path = "crates/sophus_opt", version = "0.10.0"} -sophus_pyo3 = {path = "crates/sophus_pyo3", version = "0.10.0"} sophus_sensor = {path = "crates/sophus_sensor", version = "0.10.0"} approx = "0.5" diff --git a/crates/sophus/Cargo.toml b/crates/sophus/Cargo.toml index 6d7a5a4..be16f6f 100644 --- a/crates/sophus/Cargo.toml +++ b/crates/sophus/Cargo.toml @@ -15,16 +15,12 @@ sophus_core.workspace = true sophus_image.workspace = true sophus_lie.workspace = true sophus_opt.workspace = true -sophus_pyo3.workspace = true sophus_sensor.workspace = true nalgebra.workspace = true ndarray.workspace = true [features] -pyo3 = [ - "sophus_pyo3/pyo3", -] simd = [ "sophus_core/simd", "sophus_image/simd", diff --git a/crates/sophus_pyo3/Cargo.toml b/crates/sophus_pyo3/Cargo.toml deleted file mode 100644 index 220fe64..0000000 --- a/crates/sophus_pyo3/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -description = "sophus - geometry for robotics and computer vision" -name = "sophus_pyo3" -readme = "../../README.md" - -edition.workspace = true -include.workspace = true -keywords.workspace = true -license.workspace = true -repository.workspace = true -version.workspace = true - -[dependencies] -sophus_core.workspace = true -sophus_lie.workspace = true - -nalgebra.workspace = true -numpy.workspace = true - -[dependencies.pyo3] -optional = true -version = "0.21.2" -# "abi3-py38" tells pyo3 (and maturin) to build using the stable ABI with minimum Python version 3.8 -features = ["abi3-py38"] - -[features] -default = [] -pyo3 = ["dep:pyo3"] -std = [ - "sophus_core/std", - "sophus_lie/std", -] \ No newline at end of file diff --git a/crates/sophus_pyo3/pyproject.toml b/crates/sophus_pyo3/pyproject.toml deleted file mode 100644 index 9df84ad..0000000 --- a/crates/sophus_pyo3/pyproject.toml +++ /dev/null @@ -1,7 +0,0 @@ -[build-system] -build-backend = "maturin" -requires = ["maturin>=1.0,<2.0"] - -[tool.maturin] -# "extension-module" tells pyo3 we want to build an extension module (skips linking against libpython.so) -features = ["pyo3/extension-module"] diff --git a/crates/sophus_pyo3/src/lib.rs b/crates/sophus_pyo3/src/lib.rs deleted file mode 100644 index 169e836..0000000 --- a/crates/sophus_pyo3/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![deny(missing_docs)] -//! pyo3 bindings for sophus-rs - -/// python wrapper -#[cfg(feature = "pyo3")] -pub mod pyo3; - -#[cfg(feature = "pyo3")] -use crate::pyo3::lie_groups::PyIsometry2; -#[cfg(feature = "pyo3")] -use crate::pyo3::lie_groups::PyIsometry3; -#[cfg(feature = "pyo3")] -use crate::pyo3::lie_groups::PyRotation2; -#[cfg(feature = "pyo3")] -use crate::pyo3::lie_groups::PyRotation3; -#[cfg(feature = "pyo3")] -use numpy::pyo3::prelude::*; - -/// A Python module implemented in Rust. The name of this function must match -/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to -/// import the module. -#[pymodule] -#[cfg(feature = "pyo3")] -fn sophus_pyo3(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - Ok(()) -} diff --git a/crates/sophus_pyo3/src/pyo3.rs b/crates/sophus_pyo3/src/pyo3.rs deleted file mode 100644 index 1229133..0000000 --- a/crates/sophus_pyo3/src/pyo3.rs +++ /dev/null @@ -1,4 +0,0 @@ -/// Error handling -pub mod errors; -/// Lie groups -pub mod lie_groups; diff --git a/crates/sophus_pyo3/src/pyo3/errors.rs b/crates/sophus_pyo3/src/pyo3/errors.rs deleted file mode 100644 index 891a3b3..0000000 --- a/crates/sophus_pyo3/src/pyo3/errors.rs +++ /dev/null @@ -1,53 +0,0 @@ -use numpy::PyArray1; -use numpy::PyArrayMethods; -use numpy::PyUntypedArrayMethods; -use pyo3::exceptions::PyOSError; -use pyo3::Bound; -use pyo3::PyErr; -use std::fmt; - -/// Error for mismatched array dimensions -#[derive(Debug)] -pub struct PyArray1DimMismatch { - expected: usize, - actual: usize, - file: &'static str, - line: u32, -} - -impl std::error::Error for PyArray1DimMismatch {} - -impl fmt::Display for PyArray1DimMismatch { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}:{} Expected array of dimension {}, got {}", - self.file, self.line, self.expected, self.actual - ) - } -} - -impl std::convert::From for PyErr { - fn from(err: PyArray1DimMismatch) -> PyErr { - PyOSError::new_err(err.to_string()) - } -} - -/// Check if array has expected dimension -pub fn check_array1_dim_impl( - array: &Bound>, - expected: usize, - file: &'static str, - line: u32, -) -> Result<(), PyArray1DimMismatch> { - if array.readonly().len() == expected { - Ok(()) - } else { - Err(PyArray1DimMismatch { - expected, - actual: array.len(), - file, - line, - }) - } -} diff --git a/crates/sophus_pyo3/src/pyo3/lie_groups.rs b/crates/sophus_pyo3/src/pyo3/lie_groups.rs deleted file mode 100644 index fb91638..0000000 --- a/crates/sophus_pyo3/src/pyo3/lie_groups.rs +++ /dev/null @@ -1,422 +0,0 @@ -use crate::pyo3::errors::check_array1_dim_impl; -use crate::pyo3::errors::PyArray1DimMismatch; -use numpy::PyArray1; -use numpy::PyArray2; -use numpy::PyArrayMethods; -use pyo3::pyclass; -use pyo3::pymethods; -use pyo3::Bound; -use pyo3::Py; -use pyo3::PyRef; -use pyo3::PyRefMut; -use pyo3::Python; -use sophus_lie::prelude::*; -use sophus_lie::Isometry2; -use sophus_lie::Isometry2F64; -use sophus_lie::Isometry3; -use sophus_lie::Isometry3F64; -use sophus_lie::Rotation2; -use sophus_lie::Rotation3; - -macro_rules! check_array1_dim { - ($array:expr, $expected:expr) => { - check_array1_dim_impl($array, $expected, file!(), line!()) - }; -} - -macro_rules! crate_py_lie_group_class { - ($py_group: ident, $rust_group:ty, $name: literal, - $dof:literal, $params:literal, $point:literal, $ambient:literal) => { - /// Python wrapper for Lie group - #[pyclass(name = $name)] - #[derive(Debug, Clone)] - pub struct $py_group { - /// wrapped rust group - inner: $rust_group, - } - - #[pymethods] - impl $py_group { - #[staticmethod] - fn ad( - tangent: &Bound>, - py: Python, - ) -> Result>, PyArray1DimMismatch> { - check_array1_dim!(tangent, $dof)?; - let read_only_tangent = tangent.readonly(); - let tangent_slice = read_only_tangent.as_slice().unwrap(); - let tangent_vec = nalgebra::SVector::::from_column_slice(tangent_slice); - - Ok( - PyArray1::from_slice_bound(py, <$rust_group>::ad(&tangent_vec).as_slice()) - .reshape([$ambient, $ambient]) - .unwrap() - .into(), - ) - } - - fn adj(&self, py: Python) -> Py> { - let adj = self.inner.adj(); - PyArray1::from_slice_bound(py, adj.as_slice()) - .reshape([$dof, $dof]) - .unwrap() - .into() - } - - fn compact(&self, py: Python) -> Py> { - let compact = self.inner.compact(); - PyArray1::from_slice_bound(py, compact.as_slice()) - .reshape([$point, $ambient]) - .unwrap() - .into() - } - - #[staticmethod] - fn da_a_mul_b(a: &Self, b: &Self, py: Python) -> Py> { - let result = <$rust_group>::da_a_mul_b(&a.inner, &b.inner); - PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$params, $params]) - .unwrap() - .into() - } - - #[staticmethod] - fn db_a_mul_b(a: &Self, b: &Self, py: Python) -> Py> { - let result = <$rust_group>::db_a_mul_b(&a.inner, &b.inner); - PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$params, $params]) - .unwrap() - .into() - } - - #[staticmethod] - fn dx_exp( - tangent: &Bound>, - py: Python, - ) -> Result>, PyArray1DimMismatch> { - check_array1_dim!(tangent, $dof)?; - let read_only_tangent = tangent.readonly(); - let tangent_slice = read_only_tangent.as_slice().unwrap(); - let tangent_vec = nalgebra::SVector::::from_column_slice(tangent_slice); - - let result = <$rust_group>::dx_exp(&tangent_vec); - Ok(PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$params, $dof]) - .unwrap() - .into()) - } - - #[staticmethod] - fn dx_exp_x_at_0(py: Python) -> Py> { - let result = <$rust_group>::dx_exp_x_at_0(); - PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$params, $dof]) - .unwrap() - .into() - } - - #[staticmethod] - fn dx_exp_x_times_point_at_0( - point: &Bound>, - py: Python, - ) -> Result>, PyArray1DimMismatch> { - check_array1_dim!(point, $point)?; - let read_only_point = point.readonly(); - let point_slice = read_only_point.as_slice().unwrap(); - let point_vec = nalgebra::SVector::::from_column_slice(point_slice); - - let result = <$rust_group>::dx_exp_x_times_point_at_0(point_vec); - Ok(PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$params, $point]) - .unwrap() - .into()) - } - - #[staticmethod] - fn dx_log_a_exp_x_b_at_0(a: &Self, b: &Self, py: Python) -> Py> { - let result = <$rust_group>::dx_log_a_exp_x_b_at_0(&a.inner, &b.inner); - PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$dof, $dof]) - .unwrap() - .into() - } - - #[staticmethod] - fn dx_log_x( - params: &Bound>, - py: Python, - ) -> Result>, PyArray1DimMismatch> { - check_array1_dim!(params, $params)?; - let read_only_params = params.readonly(); - let params_slice = read_only_params.as_slice().unwrap(); - let params_vec = nalgebra::SVector::::from_column_slice(params_slice); - let result = <$rust_group>::dx_log_x(¶ms_vec); - Ok(PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$dof, $params]) - .unwrap() - .into()) - } - - #[staticmethod] - fn exp(tangent: &Bound>) -> Result { - check_array1_dim!(tangent, $dof)?; - let read_only_tangent = tangent.readonly(); - let tangent_slice = read_only_tangent.as_slice().unwrap(); - let tangent_vec = nalgebra::SVector::::from_column_slice(tangent_slice); - - let result = <$rust_group>::exp(&tangent_vec); - Ok(Self { inner: result }) - } - - #[staticmethod] - fn from_params(params: &Bound>) -> Result { - check_array1_dim!(params, $params)?; - let read_only_params = params.readonly(); - let params_slice = read_only_params.as_slice().unwrap(); - let params_vec = nalgebra::SVector::::from_column_slice(params_slice); - - Ok(Self { - inner: <$rust_group>::from_params(¶ms_vec), - }) - } - - fn group_mul(&self, other: &$py_group) -> Self { - Self { - inner: self.inner.group_mul(&other.inner), - } - } - - #[staticmethod] - fn hat( - omega: &Bound>, - py: Python, - ) -> Result>, PyArray1DimMismatch> { - check_array1_dim!(omega, $dof)?; - let read_only_omega = omega.readonly(); - let omega_slice = read_only_omega.as_slice().unwrap(); - let omega_vec = nalgebra::SVector::::from_column_slice(omega_slice); - - let result = <$rust_group>::hat(&omega_vec); - Ok(PyArray1::from_slice_bound(py, result.as_slice()) - .reshape([$ambient, $ambient]) - .unwrap() - .into()) - } - - #[new] - fn identity() -> Self { - Self { - inner: <$rust_group>::identity(), - } - } - - fn inverse(&self) -> Self { - Self { - inner: self.inner.inverse(), - } - } - - fn log(&self, py: Python) -> Py> { - let log = self.inner.log(); - PyArray1::from_slice_bound(py, log.as_slice()).into() - } - - fn matrix(&self, py: Python) -> Py> { - let matrix = self.inner.matrix(); - PyArray1::from_slice_bound(py, matrix.as_slice()) - .reshape([$ambient, $ambient]) - .unwrap() - .into() - } - - fn params(&self, py: Python) -> Py> { - let params = self.inner.params(); - PyArray1::from_slice_bound(py, params.as_slice()).into() - } - - fn set_params( - &mut self, - params: &Bound>, - ) -> Result<(), PyArray1DimMismatch> { - check_array1_dim!(params, $params)?; - let read_only_params = params.readonly(); - let params_slice = read_only_params.as_slice().unwrap(); - let params_vec = nalgebra::SVector::::from_column_slice(params_slice); - - self.inner.set_params(¶ms_vec); - - Ok(()) - } - - #[staticmethod] - fn to_ambient( - point: &Bound>, - py: Python, - ) -> Result>, PyArray1DimMismatch> { - check_array1_dim!(point, $point)?; - let read_only_point = point.readonly(); - let point_slice = read_only_point.as_slice().unwrap(); - let point_vec = nalgebra::SVector::::from_column_slice(point_slice); - - let result = <$rust_group>::to_ambient(&point_vec); - Ok(PyArray1::from_slice_bound(py, result.as_slice()).into()) - } - - fn transform( - &self, - py: Python, - point: &Bound>, - ) -> Result>, PyArray1DimMismatch> { - check_array1_dim!(point, $point)?; - let read_only_point = point.readonly(); - let point_slice = read_only_point.as_slice().unwrap(); - let point_vec = nalgebra::SVector::::from_column_slice(point_slice); - - let result = self.inner.transform(&point_vec); - Ok( - PyArray1::from_slice_bound(py, result.fixed_rows::<$point>(0).as_slice()) - .into(), - ) - } - - #[staticmethod] - fn vee( - omega_hat: &Bound>, - py: Python, - ) -> Result>, PyArray1DimMismatch> { - let omega_hat = omega_hat.readonly(); - let omega_hat_slice = omega_hat.as_slice().unwrap(); - let omega_hat_mat = nalgebra::SMatrix::::from_column_slice( - omega_hat_slice, - ); - - let result = <$rust_group>::vee(&omega_hat_mat); - Ok(PyArray1::from_slice_bound(py, result.as_slice()).into()) - } - - fn __mul__(&self, other: &$py_group) -> Self { - Self { - inner: self.inner.group_mul(&other.inner), - } - } - - fn __str__(&self) -> String { - format!("{}", self.inner.compact()) - } - } - }; -} - -crate_py_lie_group_class!(PyRotation2, Rotation2::, "Rotation2", 1, 2, 2, 2); -crate_py_lie_group_class!( - PyBaseIsometry2, - Isometry2::, - "BaseIsometry2", - 3, - 4, - 2, - 3 -); -crate_py_lie_group_class!(PyRotation3, Rotation3::, "Rotation3", 3, 4, 3, 3); -crate_py_lie_group_class!( - PyBaseIsometry3, - Isometry3::, - "BaseIsometry3", - 6, - 7, - 3, - 4 -); - -macro_rules! augment_py_product_group_class { - ( - $py_base: ident, - $py_product_group: ident, - $rust_group:ty, - $py_factor_group: ident, - $name: literal, - $point:literal - ) => { - /// Python wrapper for python group - #[pyclass(name = $name, extends=$py_base)] - #[derive(Debug, Clone)] - pub struct $py_product_group {} - - #[pymethods] - impl $py_product_group { - #[new] - fn from_translation_and_rotation( - translation: &Bound>, - rotation: $py_factor_group, - ) -> Result<(Self, $py_base), PyArray1DimMismatch> { - check_array1_dim!(translation, $point)?; - let read_only_translation = translation.readonly(); - let translation_slice = read_only_translation.as_slice().unwrap(); - let translation_vec = - nalgebra::SVector::::from_column_slice(translation_slice); - - Ok(( - Self {}, - $py_base { - inner: <$rust_group>::from_translation_and_rotation( - &translation_vec, - &rotation.inner, - ), - }, - )) - } - - fn translation<'a>(self_: PyRef<'_, Self>, py: Python<'a>) -> Bound<'a, PyArray1> { - let super_ = self_.as_ref(); - let translation = super_.inner.translation(); - PyArray1::from_slice_bound(py, translation.as_slice()) - } - - fn rotation(self_: PyRef<'_, Self>) -> $py_factor_group { - let super_ = self_.as_ref(); - $py_factor_group { - inner: super_.inner.rotation(), - } - } - - fn set_translation( - mut self_: PyRefMut<'_, Self>, - translation: &Bound>, - ) -> Result<(), PyArray1DimMismatch> { - check_array1_dim!(translation, $point)?; - - let super_ = self_.as_mut(); - let read_only_translation = translation.readonly(); - let translation_slice = read_only_translation.as_slice().unwrap(); - let translation_vec = - nalgebra::SVector::::from_column_slice(translation_slice); - - super_.inner.set_translation(&translation_vec); - - Ok(()) - } - - fn set_rotation(mut self_: PyRefMut<'_, Self>, rotation: $py_factor_group) { - let super_ = self_.as_mut(); - super_.inner.set_rotation(&rotation.inner); - } - } - }; -} - -augment_py_product_group_class!( - PyBaseIsometry2, - PyIsometry2, - Isometry2F64, - PyRotation2, - "Isometry2", - 2 -); -augment_py_product_group_class!( - PyBaseIsometry3, - PyIsometry3, - Isometry3F64, - PyRotation3, - "Isometry3", - 3 -); diff --git a/publish_all.sh b/publish_all.sh index 1e1508d..038c006 100644 --- a/publish_all.sh +++ b/publish_all.sh @@ -5,7 +5,6 @@ set -e # exit on error cargo publish -p sophus_core cargo publish -p sophus_lie -cargo publish -p sophus_pyo3 cargo publish -p sophus_image cargo publish -p sophus_sensor cargo publish -p sophus_opt