--- a/src/direct_product.rs Thu May 01 00:08:09 2025 -0500 +++ b/src/direct_product.rs Thu May 01 01:05:00 2025 -0500 @@ -320,44 +320,57 @@ type PairOutput<F, A, B> = Pair<<A as Euclidean<F>>::Output, <B as Euclidean<F>>::Output>; -impl<A, B, F> Euclidean<F> for Pair<A, B> -where - A: Euclidean<F>, - B: Euclidean<F>, - F: Float, - PairOutput<F, A, B>: Euclidean<F>, - Self: Sized - + Mul<F, Output = PairOutput<F, A, B>> - + MulAssign<F> - + Div<F, Output = PairOutput<F, A, B>> - + DivAssign<F> - + Add<Self, Output = PairOutput<F, A, B>> - + Sub<Self, Output = PairOutput<F, A, B>> - + for<'b> Add<&'b Self, Output = PairOutput<F, A, B>> - + for<'b> Sub<&'b Self, Output = PairOutput<F, A, B>> - + AddAssign<Self> - + for<'b> AddAssign<&'b Self> - + SubAssign<Self> - + for<'b> SubAssign<&'b Self> - + Neg<Output = PairOutput<F, A, B>>, -{ - type Output = PairOutput<F, A, B>; +/// We need to restrict `A` and `B` as [`Euclidean`] to have closed `Output` +/// to avoid compiler overflows that the requirement +/// ``` +/// Pair<<A as Euclidean<F>>::Output, <B as Euclidean<F>>::Output> : Euclidean<F> +/// ``` +/// would generate. - fn dot<I: Instance<Self>>(&self, other: I) -> F { - let Pair(u, v) = other.decompose(); - self.0.dot(u) + self.1.dot(v) - } +macro_rules! impl_euclidean { + ($field:ty) => { + impl<A, B> Euclidean<$field> for Pair<A, B> + where + A: Euclidean<$field>, + B: Euclidean<$field>, + PairOutput<$field, A, B>: Euclidean<$field>, + Self: Sized + + Mul<$field, Output = PairOutput<$field, A, B>> + + MulAssign<$field> + + Div<$field, Output = PairOutput<$field, A, B>> + + DivAssign<$field> + + Add<Self, Output = PairOutput<$field, A, B>> + + Sub<Self, Output = PairOutput<$field, A, B>> + + for<'b> Add<&'b Self, Output = PairOutput<$field, A, B>> + + for<'b> Sub<&'b Self, Output = PairOutput<$field, A, B>> + + AddAssign<Self> + + for<'b> AddAssign<&'b Self> + + SubAssign<Self> + + for<'b> SubAssign<&'b Self> + + Neg<Output = PairOutput<$field, A, B>>, + { + type Output = PairOutput<$field, A, B>; - fn norm2_squared(&self) -> F { - self.0.norm2_squared() + self.1.norm2_squared() - } + fn dot<I: Instance<Self>>(&self, other: I) -> $field { + let Pair(u, v) = other.decompose(); + self.0.dot(u) + self.1.dot(v) + } + + fn norm2_squared(&self) -> $field { + self.0.norm2_squared() + self.1.norm2_squared() + } - fn dist2_squared<I: Instance<Self>>(&self, other: I) -> F { - let Pair(u, v) = other.decompose(); - self.0.dist2_squared(u) + self.1.dist2_squared(v) - } + fn dist2_squared<I: Instance<Self>>(&self, other: I) -> $field { + let Pair(u, v) = other.decompose(); + self.0.dist2_squared(u) + self.1.dist2_squared(v) + } + } + }; } +impl_euclidean!(f32); +impl_euclidean!(f64); + impl<F, A, B, U, V> AXPY<F, Pair<U, V>> for Pair<A, B> where U: Space,