diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c64c9a..70df50e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.9.0] - 2024-04-11 +### Packaging +- Updated `pyo3` and `numpy` dependencies to 0.21 and adapted to the new `Bound` API. + ## [0.8.1] - 2023-10-20 ### Packaging - Un-deprecated the `linalg` module. diff --git a/Cargo.toml b/Cargo.toml index f28af53..c4cc848 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "num-dual" -version = "0.8.1" +version = "0.9.0" authors = ["Gernot Bauer ", "Philipp Rehner "] edition = "2021" @@ -19,9 +19,9 @@ name = "num_dual" [dependencies] num-traits = "0.2" nalgebra = "0.32" -pyo3 = { version = "0.20", optional = true, features = ["multiple-pymethods", "extension-module", "abi3", "abi3-py37"] } +pyo3 = { version = "0.21", optional = true, features = ["multiple-pymethods", "extension-module", "abi3", "abi3-py37"] } ndarray = { version = "0.15", optional = true } -numpy = { version = "0.20", optional = true } +numpy = { version = "0.21", optional = true } approx = "0.5" simba = "0.8" diff --git a/src/linalg.rs b/src/linalg.rs index d53226c..2454209 100644 --- a/src/linalg.rs +++ b/src/linalg.rs @@ -313,21 +313,15 @@ mod tests { #[test] fn test_solve_dual64() { let a = arr2(&[ - [Dual64::new_scalar(4.0, 3.0), Dual64::new_scalar(3.0, 3.0)], - [Dual64::new_scalar(6.0, 1.0), Dual64::new_scalar(3.0, 2.0)], - ]); - let b = arr1(&[ - Dual64::new_scalar(10.0, 20.0), - Dual64::new_scalar(12.0, 20.0), + [Dual64::new(4.0, 3.0), Dual64::new(3.0, 3.0)], + [Dual64::new(6.0, 1.0), Dual64::new(3.0, 2.0)], ]); + let b = arr1(&[Dual64::new(10.0, 20.0), Dual64::new(12.0, 20.0)]); let lu = LU::new(a).unwrap(); let det = lu.determinant(); - assert_eq!((det.re, det.eps.unwrap()), (-6.0, -4.0)); + assert_eq!((det.re, det.eps), (-6.0, -4.0)); let x = lu.solve(&b); - assert_eq!( - (x[0].re, x[0].eps.unwrap(), x[1].re, x[1].eps.unwrap()), - (1.0, 2.0, 2.0, 1.0) - ); + assert_eq!((x[0].re, x[0].eps, x[1].re, x[1].eps), (1.0, 2.0, 2.0, 1.0)); } #[test] @@ -358,8 +352,8 @@ mod tests { #[test] fn test_eig_dual64() { let a = arr2(&[ - [Dual64::new_scalar(2.0, 1.0), Dual64::new_scalar(2.0, 2.0)], - [Dual64::new_scalar(2.0, 2.0), Dual64::new_scalar(5.0, 3.0)], + [Dual64::new(2.0, 1.0), Dual64::new(2.0, 2.0)], + [Dual64::new(2.0, 2.0), Dual64::new(5.0, 3.0)], ]); let (l, v) = jacobi_eigenvalue(a.clone(), 200); let av = a.dot(&v); @@ -368,26 +362,10 @@ mod tests { assert_abs_diff_eq!(av[(1, 0)].re, (l[0] * v[(1, 0)]).re, epsilon = 1e-14); assert_abs_diff_eq!(av[(0, 1)].re, (l[1] * v[(0, 1)]).re, epsilon = 1e-14); assert_abs_diff_eq!(av[(1, 1)].re, (l[1] * v[(1, 1)]).re, epsilon = 1e-14); - assert_abs_diff_eq!( - av[(0, 0)].eps.unwrap(), - (l[0] * v[(0, 0)]).eps.unwrap(), - epsilon = 1e-14 - ); - assert_abs_diff_eq!( - av[(1, 0)].eps.unwrap(), - (l[0] * v[(1, 0)]).eps.unwrap(), - epsilon = 1e-14 - ); - assert_abs_diff_eq!( - av[(0, 1)].eps.unwrap(), - (l[1] * v[(0, 1)]).eps.unwrap(), - epsilon = 1e-14 - ); - assert_abs_diff_eq!( - av[(1, 1)].eps.unwrap(), - (l[1] * v[(1, 1)]).eps.unwrap(), - epsilon = 1e-14 - ); + assert_abs_diff_eq!(av[(0, 0)].eps, (l[0] * v[(0, 0)]).eps, epsilon = 1e-14); + assert_abs_diff_eq!(av[(1, 0)].eps, (l[0] * v[(1, 0)]).eps, epsilon = 1e-14); + assert_abs_diff_eq!(av[(0, 1)].eps, (l[1] * v[(0, 1)]).eps, epsilon = 1e-14); + assert_abs_diff_eq!(av[(1, 1)].eps, (l[1] * v[(1, 1)]).eps, epsilon = 1e-14); } #[test] @@ -398,9 +376,9 @@ mod tests { #[test] fn test_norm_dual64() { - let v = arr1(&[Dual64::new_scalar(3.0, 1.0), Dual64::new_scalar(4.0, 3.0)]); + let v = arr1(&[Dual64::new(3.0, 1.0), Dual64::new(4.0, 3.0)]); println!("{}", norm(&v)); assert_eq!(norm(&v).re, 5.0); - assert_eq!(norm(&v).eps.unwrap(), 3.0); + assert_eq!(norm(&v).eps, 3.0); } } diff --git a/src/python/dual.rs b/src/python/dual.rs index 7580c39..3003f3e 100644 --- a/src/python/dual.rs +++ b/src/python/dual.rs @@ -3,7 +3,6 @@ use nalgebra::{DVector, SVector}; use numpy::{PyArray, PyReadonlyArrayDyn}; use pyo3::exceptions::PyTypeError; use pyo3::prelude::*; -use pyo3::Python; #[pyclass(name = "Dual64")] #[derive(Clone, Debug)] @@ -92,7 +91,7 @@ impl_dual_num!(PyDual64Dyn, DualDVec64, f64); /// Returns /// ------- /// function value and first derivative -pub fn first_derivative(f: &PyAny, x: f64) -> PyResult<(f64, f64)> { +pub fn first_derivative(f: &Bound<'_, PyAny>, x: f64) -> PyResult<(f64, f64)> { let g = |x| { let res = f.call1((PyDual64::from(x),))?; if let Ok(res) = res.extract::() { @@ -122,7 +121,7 @@ macro_rules! impl_gradient_and_jacobian { /// Returns /// ------- /// function value and gradient - pub fn gradient(f: &PyAny, x: &PyAny) -> PyResult<(f64, Vec)> { + pub fn gradient(f: &Bound<'_, PyAny>, x: &Bound<'_, PyAny>) -> PyResult<(f64, Vec)> { $( if let Ok(x) = x.extract::<[f64; $n]>() { let g = |x: SVector, $n>| { @@ -174,7 +173,7 @@ macro_rules! impl_gradient_and_jacobian { /// Returns /// ------- /// function values and Jacobian - pub fn jacobian(f: &PyAny, x: &PyAny) -> PyResult<(Vec, Vec>)> { + pub fn jacobian(f: &Bound<'_, PyAny>, x: &Bound<'_, PyAny>) -> PyResult<(Vec, Vec>)> { $( if let Ok(x) = x.extract::<[f64; $n]>() { let g = |x: SVector, $n>| { diff --git a/src/python/dual2.rs b/src/python/dual2.rs index 6880cc8..b7d026a 100644 --- a/src/python/dual2.rs +++ b/src/python/dual2.rs @@ -122,7 +122,7 @@ impl_dual_num!(PyDual2_64Dyn, Dual2DVec64, f64); /// Returns /// ------- /// function value, first derivative, and second derivative -pub fn second_derivative(f: &PyAny, x: f64) -> PyResult<(f64, f64, f64)> { +pub fn second_derivative(f: &Bound<'_, PyAny>, x: f64) -> PyResult<(f64, f64, f64)> { let g = |x| { let res = f.call1((PyDual2_64::from(x),))?; if let Ok(res) = res.extract::() { @@ -151,7 +151,7 @@ macro_rules! impl_hessian { /// Returns /// ------- /// function value, gradient and Hessian - pub fn hessian(f: &PyAny, x: &PyAny) -> PyResult<(f64, Vec, Vec>)> { + pub fn hessian(f: &Bound<'_, PyAny>, x: &Bound<'_, PyAny>) -> PyResult<(f64, Vec, Vec>)> { $( if let Ok(x) = x.extract::<[f64; $n]>() { let g = |x: SVector, $n>| { diff --git a/src/python/dual3.rs b/src/python/dual3.rs index 9fa4691..8411ada 100644 --- a/src/python/dual3.rs +++ b/src/python/dual3.rs @@ -77,7 +77,7 @@ impl_dual_num!(PyDual3Dual64, Dual3, PyDual64); /// Returns /// ------- /// function value, first derivative, second derivative, and third derivative -pub fn third_derivative(f: &PyAny, x: f64) -> PyResult<(f64, f64, f64, f64)> { +pub fn third_derivative(f: &Bound<'_, PyAny>, x: f64) -> PyResult<(f64, f64, f64, f64)> { let g = |x| { let res = f.call1((PyDual3_64::from(x),))?; if let Ok(res) = res.extract::() { diff --git a/src/python/hyperdual.rs b/src/python/hyperdual.rs index 794181c..67c4eb8 100644 --- a/src/python/hyperdual.rs +++ b/src/python/hyperdual.rs @@ -126,7 +126,11 @@ impl_dual_num!(PyHyperDual64Dyn, HyperDualDVec64, f64); /// ------- /// function value, first partial derivative w.r.t. x, /// first parital derivative w.r.t. y, and second partial derivative -pub fn second_partial_derivative(f: &PyAny, x: f64, y: f64) -> PyResult<(f64, f64, f64, f64)> { +pub fn second_partial_derivative( + f: &Bound<'_, PyAny>, + x: f64, + y: f64, +) -> PyResult<(f64, f64, f64, f64)> { let g = |x, y| { let res = f.call1((PyHyperDual64::from(x), PyHyperDual64::from(y)))?; if let Ok(res) = res.extract::() { @@ -159,9 +163,9 @@ macro_rules! impl_partial_hessian { /// function value, gradient w.r.t. x, gradient w.r.t. y, and partial Hessian #[allow(clippy::type_complexity)] pub fn partial_hessian( - f: &PyAny, - x: &PyAny, - y: &PyAny, + f: &Bound<'_, PyAny>, + x: &Bound<'_, PyAny>, + y: &Bound<'_, PyAny>, ) -> PyResult<(f64, Vec, Vec, Vec>)> { $( if let (Ok(x), Ok(y)) = (x.extract::<[f64; $m]>(), y.extract::<[f64; $n]>()) { diff --git a/src/python/hyperhyperdual.rs b/src/python/hyperhyperdual.rs index 34bd5de..8a1f9af 100644 --- a/src/python/hyperhyperdual.rs +++ b/src/python/hyperhyperdual.rs @@ -79,7 +79,7 @@ impl_dual_num!(PyHyperHyperDual64, HyperHyperDual64, f64); /// third partial derivative #[allow(clippy::type_complexity)] pub fn third_partial_derivative( - f: &PyAny, + f: &Bound<'_, PyAny>, x: f64, y: f64, z: f64, @@ -130,7 +130,7 @@ pub fn third_partial_derivative( /// third partial derivative #[allow(clippy::type_complexity)] pub fn third_partial_derivative_vec( - f: &PyAny, + f: &Bound<'_, PyAny>, x: Vec, i: usize, j: usize, diff --git a/src/python/mod.rs b/src/python/mod.rs index aa4d3be..70b4224 100644 --- a/src/python/mod.rs +++ b/src/python/mod.rs @@ -1,3 +1,4 @@ +#![allow(non_snake_case)] use pyo3::prelude::*; use pyo3::wrap_pyfunction; @@ -34,7 +35,7 @@ pub use hyperdual::{ pub use hyperhyperdual::PyHyperHyperDual64; #[pymodule] -pub fn num_dual(_py: Python, m: &PyModule) -> PyResult<()> { +pub fn num_dual(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add("__version__", env!("CARGO_PKG_VERSION"))?; m.add_class::()?; m.add_class::()?; diff --git a/src/python_macro.rs b/src/python_macro.rs index 1eab06c..c7ca6c3 100644 --- a/src/python_macro.rs +++ b/src/python_macro.rs @@ -213,231 +213,207 @@ macro_rules! impl_dual_num { self.0.mul_add(a.0, b.0).into() } - fn __add__(&self, rhs: &PyAny) -> PyResult { - Python::with_gil(|py| { - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() + r))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() + r.0))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::>() { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array() - .mapv(|ri| Py::new(py, Self(self.0.clone() + ri)).unwrap()), + fn __add__<'py>(&self, rhs: &Bound<'py, PyAny>) -> PyResult> { + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() + r))?.into_any()); + }; + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() + r.0))?.into_any()); + }; + if let Ok(r) = rhs.extract::>() { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array() + .mapv(|ri| Py::new(rhs.py(), Self(self.0.clone() + ri)).unwrap()), + ) + .into_any()); + } + if let Ok(r) = rhs.extract::>() { + // check data type of first element + if r.as_array() + .get(0) + .unwrap() + .bind(rhs.py()) + .is_instance_of::() + { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array().mapv(|ri| { + Py::new(rhs.py(), Self(self.0.clone() + ri.extract::(rhs.py()).unwrap().0)) + .unwrap() + }), ) - .into()); - } - if let Ok(r) = rhs.extract::>() { - // check data type of first element - if r.readonly() - .as_array() - .get(0) - .unwrap() - .as_ref(py) - .is_instance_of::() - { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array().mapv(|ri| { - Py::new(py, Self(self.0.clone() + ri.extract::(py).unwrap().0)) - .unwrap() - }), - ) - .into()); - } else { - return Err(PyErr::new::(format!( - "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", - stringify!($py_type_name) - ))); - } + .into_any()); + } else { + return Err(PyErr::new::(format!( + "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", + stringify!($py_type_name) + ))); } + } - Err(PyErr::new::(format!( - "Addition of \nleft: {}\nright: {:?}\nis not implemented!", - stringify!($py_type_name), - rhs.get_type() - ))) - }) + Err(PyErr::new::(format!( + "Addition of \nleft: {}\nright: {:?}\nis not implemented!", + stringify!($py_type_name), + rhs.get_type() + ))) } - fn __radd__(&self, other: &PyAny) -> PyResult { - if let Ok(o) = other.extract::() { - return Ok((self.0.clone() + o).into()); - }; - Err(PyErr::new::(format!("not implemented!"))) + fn __radd__(&self, lhs: f64) -> Self { + (self.0.clone() + lhs).into() } - fn __sub__(&self, rhs: &PyAny) -> PyResult { - Python::with_gil(|py| { - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() - r))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() - r.0))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::>() { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array() - .mapv(|ri| Py::new(py, Self(self.0.clone() - ri)).unwrap()), + fn __sub__<'py>(&self, rhs: &Bound<'py, PyAny>) -> PyResult> { + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() - r))?.into_any()); + }; + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() - r.0))?.into_any()); + }; + if let Ok(r) = rhs.extract::>() { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array() + .mapv(|ri| Py::new(rhs.py(), Self(self.0.clone() - ri)).unwrap()), + ) + .into_any()); + } + if let Ok(r) = rhs.extract::>() { + // check data type of first element + if r.as_array() + .get(0) + .unwrap() + .bind(rhs.py()) + .is_instance_of::() + { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array().mapv(|ri| { + Py::new(rhs.py(), Self(self.0.clone() - ri.extract::(rhs.py()).unwrap().0)) + .unwrap() + }), ) - .into()); - } - if let Ok(r) = rhs.extract::>() { - // check data type of first element - if r.readonly() - .as_array() - .get(0) - .unwrap() - .as_ref(py) - .is_instance_of::() - { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array().mapv(|ri| { - Py::new(py, Self(self.0.clone() - ri.extract::(py).unwrap().0)) - .unwrap() - }), - ) - .into()); - } else { - return Err(PyErr::new::(format!( - "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", - stringify!($py_type_name) - ))); - } + .into_any()); + } else { + return Err(PyErr::new::(format!( + "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", + stringify!($py_type_name) + ))); } + } - Err(PyErr::new::(format!( - "Subtraction of \nleft: {}\nright: {:?}\nis not implemented!", - stringify!($py_type_name), - rhs.get_type() - ))) - }) + Err(PyErr::new::(format!( + "Subtraction of \nleft: {}\nright: {:?}\nis not implemented!", + stringify!($py_type_name), + rhs.get_type() + ))) } - fn __rsub__(&self, other: &PyAny) -> PyResult { - if let Ok(o) = other.extract::() { - return Ok((-self.0.clone() + o).into()); - }; - Err(PyErr::new::(format!("not implemented!"))) + fn __rsub__(&self, lhs: f64) -> Self { + (-self.0.clone() + lhs).into() } - fn __mul__(&self, rhs: &PyAny) -> PyResult { - Python::with_gil(|py| { - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() * r))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() * r.0))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::>() { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array() - .mapv(|ri| Py::new(py, Self(self.0.clone() * ri)).unwrap()), + fn __mul__<'py>(&self, rhs: &Bound<'py, PyAny>) -> PyResult> { + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() * r))?.into_any()); + }; + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() * r.0))?.into_any()); + }; + if let Ok(r) = rhs.extract::>() { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array() + .mapv(|ri| Py::new(rhs.py(), Self(self.0.clone() * ri)).unwrap()), + ) + .into_any()); + } + if let Ok(r) = rhs.extract::>() { + // check data type of first element + if r.as_array() + .get(0) + .unwrap() + .bind(rhs.py()) + .is_instance_of::() + { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array().mapv(|ri| { + Py::new(rhs.py(), Self(self.0.clone() * ri.extract::(rhs.py()).unwrap().0)) + .unwrap() + }), ) - .into()); - } - if let Ok(r) = rhs.extract::>() { - // check data type of first element - if r.readonly() - .as_array() - .get(0) - .unwrap() - .as_ref(py) - .is_instance_of::() - { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array().mapv(|ri| { - Py::new(py, Self(self.0.clone() * ri.extract::(py).unwrap().0)) - .unwrap() - }), - ) - .into()); - } else { - return Err(PyErr::new::(format!( - "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", - stringify!($py_type_name) - ))); - } + .into_any()); + } else { + return Err(PyErr::new::(format!( + "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", + stringify!($py_type_name) + ))); } + } - Err(PyErr::new::(format!( - "Multiplication of \nleft: {}\nright: {:?}\nis not implemented!", - stringify!($py_type_name), - rhs.get_type() - ))) - }) + Err(PyErr::new::(format!( + "Multiplication of \nleft: {}\nright: {:?}\nis not implemented!", + stringify!($py_type_name), + rhs.get_type() + ))) } - fn __rmul__(&self, other: &PyAny) -> PyResult { - if let Ok(o) = other.extract::() { - return Ok((self.0.clone() * o).into()); - }; - Err(PyErr::new::(format!("not implemented!"))) + fn __rmul__(&self, lhs: f64) -> Self { + (self.0.clone() * lhs).into() } - fn __truediv__(&self, rhs: &PyAny) -> PyResult { - Python::with_gil(|py| { - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() / r))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::() { - return Ok(PyCell::new(py, Self(self.0.clone() / r.0))?.to_object(py)); - }; - if let Ok(r) = rhs.extract::>() { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array() - .mapv(|ri| Py::new(py, Self(self.0.clone() / ri)).unwrap()), + fn __truediv__<'py>(&self, rhs: &Bound<'py, PyAny>) -> PyResult> { + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() / r))?.into_any()); + }; + if let Ok(r) = rhs.extract::() { + return Ok(Bound::new(rhs.py(), Self(self.0.clone() / r.0))?.into_any()); + }; + if let Ok(r) = rhs.extract::>() { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array() + .mapv(|ri| Py::new(rhs.py(), Self(self.0.clone() / ri)).unwrap()), + ) + .into_any()); + } + if let Ok(r) = rhs.extract::>() { + // check data type of first element + if r.as_array() + .get(0) + .unwrap() + .bind(rhs.py()) + .is_instance_of::() + { + return Ok(PyArray::from_owned_object_array_bound( + rhs.py(), + r.as_array().mapv(|ri| { + Py::new(rhs.py(), Self(self.0.clone() / ri.extract::(rhs.py()).unwrap().0)) + .unwrap() + }), ) - .into()); - } - if let Ok(r) = rhs.extract::>() { - // check data type of first element - if r.readonly() - .as_array() - .get(0) - .unwrap() - .as_ref(py) - .is_instance_of::() - { - return Ok(PyArray::from_owned_object_array( - py, - r.as_array().mapv(|ri| { - Py::new(py, Self(self.0.clone() / ri.extract::(py).unwrap().0)) - .unwrap() - }), - ) - .into()); - } else { - return Err(PyErr::new::(format!( - "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", - stringify!($py_type_name) - ))); - } + .into_any()); + } else { + return Err(PyErr::new::(format!( + "Operation with the provided object type is not implemented. Supported data types are 'float', 'int' and '{}'.", + stringify!($py_type_name) + ))); } + } - Err(PyErr::new::(format!( - "Division of \nleft: {}\nright: {:?}\nis not implemented!", - stringify!($py_type_name), - rhs.get_type() - ))) - }) + Err(PyErr::new::(format!( + "Division of \nleft: {}\nright: {:?}\nis not implemented!", + stringify!($py_type_name), + rhs.get_type() + ))) } - fn __rtruediv__(&self, other: &PyAny) -> PyResult { - if let Ok(o) = other.extract::() { - return Ok((self.0.recip() * o).into()); - }; - Err(PyErr::new::(format!("not implemented!"))) + fn __rtruediv__(&self, lhs: f64) -> Self { + (self.0.recip() * lhs).into() } - fn __pow__(&self, rhs: &PyAny, _mod: Option) -> PyResult { + fn __pow__(&self, rhs: &Bound<'_, PyAny>, _mod: Option) -> PyResult { if let Ok(r) = rhs.extract::() { return Ok(self.0.powi(r).into()); };