Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blanket impl of SimdPartialOrd prevents any Wrapper<T> of T: SimdValue defining vectorised field impls #44

Open
cormacrelf opened this issue Apr 21, 2023 · 0 comments

Comments

@cormacrelf
Copy link

cormacrelf commented Apr 21, 2023

SimdPartialOrd is blanket implemented for any T: SimdValue<Element = T, SimdBool = bool> + PartialOrd.

I am working on the num_dual crate, trying to make its dual number algebra work like a scalar does for nalgebra purposes. Here's a simplified illustration of the problem (playground).

The illustration has a DualNumber<T> type, which I would like to eventually support DualNumber<f32x4> etc. The object is to put one of those inside a nalgebra vector, i.e. Vector3<DualNumber<f32x4>>, and have that type produce vectorized code. So DualNumber<Simd<[f32; N]>> has to implement everything that f32 does. Including SimdRealField/SimdComplexField.

All of the SimdRealField/SimdComplexField traits require SimdPartialOrd. There is a blanket implementation of SimdPartialOrd, and the existence of that blanket impl prevents any type like DualNumber<T> implementing SimdPartialOrd manually and generic over T's SimdValue implementation / choice of SimdBool.

A type like this needs to have type SimdBool = T::SimdBool; in its SimdValue, and then use the vectorised SimdBool in its implementations of SimdRealField/SimdComplexField. Since I can't implement SimdPartialOrd and am forced to rely on the blanket impl, I can't really generate those vectorised bools. And moreover, since I cannot implement SimdPartialOrd, I have to constrain the SimdRealField/SimdComplexField implementations to T: SimdValue<Element = T, SimdBool = bool>, which means I cannot ever use those traits on DualNumber<f32x4>.

Essentially, the blanket implementation on SimdPartialOrd has foreclosed the possibility of vectorising any new algebraic field implementations in such a way that nalgebra can use them. The resulting DualNumber can only be used with f32 and f64 directly. It only has the un-vectorised code in RealField and ComplexField.

There is one workaround, which is unacceptable: do not implement PartialOrd on DualNumber. Then the trait solver will reject that blanket impl and you can make your own. But the whole point of this exercise was to have operator overloading work with nalgebra, I'm not giving up PartialOrd.

My recommendation is to add a marker trait like the one in the illustration, reproduced here:

trait OptIn {}
impl OptIn for f32 {}
impl OptIn for f64 {}

impl<T> SimdPartialOrd for T
where
      T: SimdValue<Element = T, SimdBool = bool> + PartialOrd,
      // and crucially, add this as a constraint
      T: OptIn,
{}

That way, because DualNumber<T> chooses not to implement OptIn, it is unaffected by the blanket impl of SimdPartialOrd. It can then

  • impl SimdValue for DualNumber<T> where T: SimdValue with Element = DualNumber<T::Element> and SimdBool = T::SimdBool>
  • impl SimdPartialOrd for DualNumber<T> where T: SimdPartialOrd, very simple forwarding impl (to only compare the real parts)
  • impl SimdRealField for DualNumber<T> where T: SimdRealField, using T's simd operations to implement dual numbers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant