dimforge / alga

Abstract algebra for Rust.
194 stars 39 forks source link

Deriving a Ring trait requires a two-sided multiplicative inverse #100

Closed mark-schultz-wu closed 4 years ago

mark-schultz-wu commented 4 years ago

I am trying to implement the ring of integers mod n for n non-prime (so this is a ring, not a field). Here is a link to the relevant code.

The section which errors has the following form:

#[derive(Clone, Copy, PartialEq, Alga)]
#[alga_traits(Ring(Additive, Multiplicative))]
struct Modular<const Q: u32>(u32);

The rest of the code is implementing various traits. The particular error is below:

error[E0277]: the trait bound `Modular<Q>: TwoSidedInverse<Multiplicative>` is not satisfied
  --> src/lib.rs:10:34
   |
10 | #[derive(Clone, Copy, PartialEq, Alga)]
   |                                  ^^^^ the trait `TwoSidedInverse<Multiplicative>` is not implemented for `Modular<Q>`
   |
  ::: /home/mark/.cargo/registry/src/github.com-1ecc6299db9ec823/alga-0.9.3/src/general/one_operator.rs:49:36
   |
49 |     PartialEq + AbstractMagma<O> + TwoSidedInverse<O>
   |                                    ------------------ required by this bound in `AbstractQuasigroup`
   |
   = help: the following implementations were found:
             <Modular<Q> as TwoSidedInverse<Additive>>
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Modular<Q>: TwoSidedInverse<Multiplicative>` is not satisfied
   --> src/lib.rs:10:34
    |
10  | #[derive(Clone, Copy, PartialEq, Alga)]
    |                                  ^^^^ the trait `TwoSidedInverse<Multiplicative>` is not implemented for `Modular<Q>`
    |
   ::: /home/mark/.cargo/registry/src/github.com-1ecc6299db9ec823/alga-0.9.3/src/general/one_operator.rs:189:38
    |
189 | pub trait AbstractLoop<O: Operator>: AbstractQuasigroup<O> + Identity<O> {}
    |                                      --------------------- required by this bound in `AbstractLoop`
    |
    = help: the following implementations were found:
              <Modular<Q> as TwoSidedInverse<Additive>>
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
error: could not compile `latticecrypto`

To learn more, run the command again with --verbose.

It seems that the issue is that I have not provided a TwoSidedInverse implementation. But I want to implement an integral domain for which not every element has a multiplicative inverse, so this seems like the "right" thing to be doing. Is this behavior expected? Is there some other way that I can use alga to implement the modular arithmetic mod n for n composite?

mark-schultz-wu commented 4 years ago

I've tried looking into this a bit further, and it seems like the issue is within alga_derive. In particular, in get_dependencies monoid currently depends on quasigroup, when it should (mathematically) depend on semigroup. This is where the two_sided_inverse requirement seems to be coming from.

I'm very unfamiliar with procedural macros though, so don't know if I am misunderstanding something.

mark-schultz-wu commented 4 years ago

I've implemented some (reasonable in terms of the underlying mathematics) changes to alga_derive here which fix my issue.