dimforge / alga

Abstract algebra for Rust.
194 stars 39 forks source link

Instructions incomplete/incorrect on how to define an additive group #63

Open jeremysalwen opened 5 years ago

jeremysalwen commented 5 years ago

If I define an additive group according to the instructions in the documentation, it still will not satisfy the AdditiveGroup trait, and I can't do addition with it (e.g. element + element).

use alga::general::{AbstractMagma, Additive, AdditiveGroup, Identity, Inverse}; // 0.7.2
use alga_derive::Alga; // 0.7.1

#[derive(Alga, Clone, Copy, PartialEq, Debug)]
#[alga_traits(Group(Additive))]
pub struct TrivialGroup;

impl AbstractMagma<Additive> for TrivialGroup {
    fn operate(&self, _right: &Self) -> Self {
        TrivialGroup {}
    }
}

impl Identity<Additive> for TrivialGroup {
    fn identity() -> Self {
        TrivialGroup {}
    }
}

impl Inverse<Additive> for TrivialGroup {
    fn inverse(&self) -> Self {
        TrivialGroup {}
    }
}

struct Bar<T: AdditiveGroup> {
    t: T,
}

fn main() {
    let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
}

Gives the error:

error[E0277]: the trait bound `TrivialGroup: num_traits::identities::Zero` is not satisfied
  --> src/main.rs:31:15
   |
31 |     let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
   |               ^^^^^^^^^^^^^^^^^^^ the trait `num_traits::identities::Zero` is not implemented for `TrivialGroup`
   |
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
  --> src/main.rs:26:1
   |
26 | struct Bar<T: AdditiveGroup> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `TrivialGroup: std::ops::Neg` is not satisfied
  --> src/main.rs:31:15
   |
31 |     let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
   |               ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Neg` is not implemented for `TrivialGroup`
   |
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedNeg` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
  --> src/main.rs:26:1
   |
26 | struct Bar<T: AdditiveGroup> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: cannot subtract `TrivialGroup` from `TrivialGroup`
  --> src/main.rs:31:15
   |
31 |     let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
   |               ^^^^^^^^^^^^^^^^^^^ no implementation for `TrivialGroup - TrivialGroup`
   |
   = help: the trait `std::ops::Sub` is not implemented for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedSub` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveQuasigroup` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
  --> src/main.rs:26:1
   |
26 | struct Bar<T: AdditiveGroup> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: cannot subtract-assign `TrivialGroup` from `TrivialGroup`
  --> src/main.rs:31:15
   |
31 |     let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
   |               ^^^^^^^^^^^^^^^^^^^ no implementation for `TrivialGroup -= TrivialGroup`
   |
   = help: the trait `std::ops::SubAssign` is not implemented for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedSub` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveQuasigroup` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveLoop` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
  --> src/main.rs:26:1
   |
26 | struct Bar<T: AdditiveGroup> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: cannot add-assign `TrivialGroup` to `TrivialGroup`
  --> src/main.rs:31:15
   |
31 |     let foo = Bar::<TrivialGroup> { t: TrivialGroup {} };
   |               ^^^^^^^^^^^^^^^^^^^ no implementation for `TrivialGroup += TrivialGroup`
   |
   = help: the trait `std::ops::AddAssign` is not implemented for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::ClosedAdd` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveSemigroup` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveMonoid` for `TrivialGroup`
   = note: required because of the requirements on the impl of `_ALGA_DERIVE_TrivialGroup::_alga::general::AdditiveGroup` for `TrivialGroup`
note: required by `Bar`
  --> src/main.rs:26:1
   |
26 | struct Bar<T: AdditiveGroup> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

See also: https://stackoverflow.com/questions/54303935/defining-additivegroup-with-alga-crate

WaDelma commented 5 years ago

There is some confusion here: alga_derive implements AbstractGroup<Additive> for you which is different from AdditiveGroup which requires the extra Zero, Neg, SubAssign, AddAssign traits to be implemented.

These restrict to what kind of things it can accept, but as a trade make using it cleaner

The alga_derive documentations doesn't talk about this explicitly though.

jeremysalwen commented 5 years ago

I think I understand, but are you sure that list of required traits is complete? The compiler is complaining, I think it wants me to implement Add as well. So it seems like in total, in order to define an AdditiveGroup I need all this boilerplate?

#[derive(Alga, Clone, Copy, PartialEq, Debug)]
#[alga_traits(Group(Additive))]
pub struct TrivialGroup;

impl AbstractMagma<Additive> for TrivialGroup {
    fn operate(&self, _right: &Self) -> Self {
        TrivialGroup {}
    }
}

impl Identity<Additive> for TrivialGroup {
    fn identity() -> Self {
        TrivialGroup {}
    }
}

impl Inverse<Additive> for TrivialGroup {
    fn inverse(&self) -> Self {
        TrivialGroup {}
    }
}

impl Zero for TrivialGroup {
    fn zero() -> Self {
        TrivialGroup::identity()
    }
    fn is_zero(&self) -> bool {
        true
    }
}

impl Add for TrivialGroup {
    type Output = TrivialGroup;
    fn add(self, _other: TrivialGroup) -> Self::Output {
        self
    }
}

impl Neg for TrivialGroup {
    type Output = TrivialGroup;
    fn neg(self) -> TrivialGroup {
        self
    }
}

impl AddAssign for TrivialGroup {
    fn add_assign(&mut self, _other : TrivialGroup) {
    }
}

impl SubAssign for TrivialGroup {
    fn sub_assign(&mut self, _other :TrivialGroup) {
    }
}

It seems like there are only three things I'm defining: the "add" operator, the "negate" operator, and the "zero" element, but I still have to manually implement 8 Traits on top of everything that alga_derive derives? Is there really no macro that does the obvious derivations of the 5 redundant traits?

sebcrozet commented 5 years ago

@jeremysalwen That's correct. We only have macros for implementing the Abstract* traits currently. Though adding macros for the non-Abstract traits would definitely be a great addition.