1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
//! //! Algebraic _additive_ _group_ traits. //! //! An algebraic _additive_ _group_ is an _additive_ _monoid_ `M`, //! where each group element `g` has a unique additive _inverse_ //! element denoted `-g`. The inverse operation is called //! _negation_. //! //! # Axioms //! //! ```notrust //! ∀g ∈ M //! //! Inverse: ∃-g ∈ M: g + -g = -g + g = 0. //! ``` //! //! # References //! //! See [references] for a formal definition of an additive group. //! #![doc(include = "../doc/references.md")] use monoid::add_monoid::*; /// /// An algebraic _additive group_. /// pub trait AddGroup: AddMonoid { /// The unique additive inverse of a group element. fn negate(&self) -> Self; /// The additive "subtraction" of two group elements. fn sub(&self, other: &Self) -> Self { self.add(&other.negate()) } /// Test the left axiom of negation. fn axiom_left_negate(&self) -> bool { self.negate().add(self) == Self::zero() } /// Test the right axiom of negation. fn axiom_right_negate(&self) -> bool { self.add(&self.negate()) == Self::zero() } } /// /// A "numeric" algebraic _additive group_. /// /// `NumAddGroup` trait is for types that only form additive groups /// when "numeric" comparisons are used, e.g. floating point types. /// pub trait NumAddGroup: NumAddMonoid { /// The unique additive inverse of a group element. fn negate(&self) -> Self; /// The additive "subtraction" of two group elements. fn sub(&self, other: &Self) -> Self { self.add(&other.negate()) } /// Numerically test the left axiom of negation. fn axiom_left_negate(&self, eps: &Self::Error) -> bool { self.negate().add(self).num_eq(&Self::zero(), eps) } /// Numerically test the right axiom of negation. fn axiom_right_negate(&self, eps: &Self::Error) -> bool { self.add(&self.negate()).num_eq(&Self::zero(), eps) } } /// /// Trait implementation macro for integer types. /// /// A macro used to avoid writing repetitive, boilerplate `AddGroup` /// implementations for built-in signed integer types. Probably not /// needed if Rust had a signed `Integer` super-trait. /// macro_rules! integer_add_group { ($type:ty) => { impl AddGroup for $type { /// Additive group negation uses "wrapping" negate to /// avoid overflow and guarantee the closure axiom. fn negate(&self) -> Self { self.wrapping_neg() } } }; ($type:ty, $($others:ty),+) => { integer_add_group! {$type} integer_add_group! {$($others),+} }; } // Only signed integers form an additive group. integer_add_group! { i8, i16, i32, i64, i128, isize } /// /// Trait implementation macro for floating point types. /// /// A macro used to avoid writing repetitive, boilerplate /// `NumAddGroup` implementations for built-in signed floating point /// types. Probably not needed if Rust had a `Float` super-trait. /// macro_rules! float_add_group { ($type:ty) => { impl NumAddGroup for $type { // Negation is just floating point negation. fn negate(&self) -> Self { -*self } } }; ($type:ty, $($others:ty),+) => { float_add_group! {$type} float_add_group! {$($others),+} }; } // Numeric additive group floating point types. float_add_group! { f32, f64 } // Module unit tests are in a separate file. #[cfg(test)] #[path = "add_group_test.rs"] mod add_group_test;