Skip to main content

relp_num/
signed_one.rs

1//! # Signed One
2//!
3//! A type that is always one or minus one.
4use std::cmp::Ordering;
5use std::fmt;
6use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7
8use crate::{Negateable, NonZero, Sign, Signed};
9
10/// # SignedOne
11///
12/// A number that is either `1` or `-1`, stored in a single byte.
13///
14/// Can be used when a type from the `MatrixProvider` can only have the value `1` or `-1`, such as
15/// with some network problems, where an arc is either incoming or outgoing. The incidence matrix of
16/// a network holds nothing but these two values, and storing a rational number for each of them
17/// wastes both space and time. This type stores the coefficient in a byte and lets
18/// [`Absorb`](crate::Absorb) apply it to a wide accumulator directly: multiplying by `PlusOne` is a
19/// clone, multiplying by `MinusOne` is a clone and a sign flip, never a multiplication.
20///
21/// The variants are *not* declared in increasing numeric order, so the derived [`Ord`] would be
22/// wrong; the impl below compares the discriminants instead, like [`Sign`] does.
23#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
24pub enum SignedOne {
25    /// +1.
26    #[default]
27    PlusOne = 1,
28    /// -1.
29    MinusOne = -1,
30}
31
32impl num_traits::One for SignedOne {
33    #[inline]
34    fn one() -> Self {
35        Self::PlusOne
36    }
37}
38
39impl Mul<SignedOne> for SignedOne {
40    type Output = Self;
41
42    #[inline]
43    fn mul(self, rhs: SignedOne) -> Self::Output {
44        match (self, rhs) {
45            (Self::PlusOne, Self::PlusOne) => Self::PlusOne,
46            (Self::PlusOne, Self::MinusOne) => Self::MinusOne,
47            (Self::MinusOne, Self::PlusOne) => Self::MinusOne,
48            (Self::MinusOne, Self::MinusOne) => Self::PlusOne,
49        }
50    }
51}
52
53/// This type is positive or negative; it is never zero.
54impl Signed for SignedOne {
55    #[inline]
56    fn signum(&self) -> Sign {
57        match self {
58            SignedOne::PlusOne => Sign::Positive,
59            SignedOne::MinusOne => Sign::Negative,
60        }
61    }
62}
63
64/// Both negations are representable: `PlusOne` and `MinusOne` are each other's additive inverse.
65impl Negateable for SignedOne {
66    #[inline]
67    fn negate(&mut self) {
68        *self = match self {
69            SignedOne::PlusOne => SignedOne::MinusOne,
70            SignedOne::MinusOne => SignedOne::PlusOne,
71        };
72    }
73}
74
75impl Neg for SignedOne {
76    type Output = Self;
77
78    #[inline]
79    fn neg(mut self) -> Self::Output {
80        Negateable::negate(&mut self);
81        self
82    }
83}
84
85impl NonZero for SignedOne {
86    #[inline]
87    fn is_not_zero(&self) -> bool {
88        true
89    }
90}
91
92/// The variants are declared with `PlusOne` first, so a derived `Ord` would order `PlusOne` before
93/// `MinusOne`. Compare the discriminants instead, which gives `MinusOne < PlusOne`.
94impl Ord for SignedOne {
95    #[inline]
96    fn cmp(&self, other: &Self) -> Ordering {
97        (*self as i8).cmp(&(*other as i8))
98    }
99}
100
101impl PartialOrd for SignedOne {
102    #[inline]
103    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
104        Some(self.cmp(other))
105    }
106}
107
108/// Debug forwards to `Display`, because `1` and `-1` read better in test output than the variant
109/// names.
110impl fmt::Debug for SignedOne {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        fmt::Display::fmt(&self, f)
113    }
114}
115
116impl fmt::Display for SignedOne {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        match self {
119            SignedOne::PlusOne => f.write_str("1"),
120            SignedOne::MinusOne => f.write_str("-1"),
121        }
122    }
123}
124
125macro_rules! define_signed_ops {
126    ($primitive:ident) => {
127        impl From<SignedOne> for $primitive {
128            fn from(rhs: SignedOne) -> Self {
129                match rhs {
130                    SignedOne::PlusOne => 1,
131                    SignedOne::MinusOne => -1,
132                }
133            }
134        }
135
136        impl From<&SignedOne> for $primitive {
137            fn from(rhs: &SignedOne) -> Self {
138                match rhs {
139                    SignedOne::PlusOne => 1,
140                    SignedOne::MinusOne => -1,
141                }
142            }
143        }
144
145        impl Mul<SignedOne> for $primitive {
146            type Output = Self;
147
148            fn mul(mut self, rhs: SignedOne) -> Self::Output {
149                MulAssign::mul_assign(&mut self, rhs);
150                self
151            }
152        }
153
154        impl Mul<&SignedOne> for $primitive {
155            type Output = Self;
156
157            fn mul(mut self, rhs: &SignedOne) -> Self::Output {
158                MulAssign::mul_assign(&mut self, rhs);
159                self
160            }
161        }
162
163        impl Mul<&SignedOne> for &$primitive {
164            type Output = $primitive;
165
166            fn mul(self, rhs: &SignedOne) -> Self::Output {
167                match rhs {
168                    SignedOne::PlusOne => *self,
169                    SignedOne::MinusOne => -self,
170                }
171            }
172        }
173
174        impl MulAssign<&SignedOne> for $primitive {
175            fn mul_assign(&mut self, rhs: &SignedOne) {
176                MulAssign::mul_assign(self, *rhs);
177            }
178        }
179
180        impl MulAssign<SignedOne> for $primitive {
181            fn mul_assign(&mut self, rhs: SignedOne) {
182                match rhs {
183                    SignedOne::PlusOne => {},
184                    SignedOne::MinusOne => *self = -*self,
185                }
186            }
187        }
188
189        impl Div<SignedOne> for $primitive {
190            type Output = Self;
191
192            fn div(mut self, rhs: SignedOne) -> Self::Output {
193                MulAssign::mul_assign(&mut self, rhs);
194                self
195            }
196        }
197
198        impl Div<&SignedOne> for $primitive {
199            type Output = Self;
200
201            fn div(mut self, rhs: &SignedOne) -> Self::Output {
202                MulAssign::mul_assign(&mut self, rhs);
203                self
204            }
205        }
206
207        impl DivAssign<&SignedOne> for $primitive {
208            fn div_assign(&mut self, rhs: &SignedOne) {
209                DivAssign::div_assign(self, *rhs);
210            }
211        }
212
213        impl DivAssign<SignedOne> for $primitive {
214            fn div_assign(&mut self, rhs: SignedOne) {
215                MulAssign::mul_assign(self, rhs);
216            }
217        }
218    }
219}
220
221macro_rules! define_unsigned_ops {
222    ($primitive:ident) => {
223        impl Add<SignedOne> for $primitive {
224            type Output = Self;
225
226            fn add(mut self, rhs: SignedOne) -> Self::Output {
227                AddAssign::add_assign(&mut self, rhs);
228                self
229            }
230        }
231
232        impl Add<&SignedOne> for $primitive {
233            type Output = Self;
234
235            fn add(mut self, rhs: &SignedOne) -> Self::Output {
236                AddAssign::add_assign(&mut self, rhs);
237                self
238            }
239        }
240
241        impl AddAssign<&SignedOne> for $primitive {
242            fn add_assign(&mut self, rhs: &SignedOne) {
243                AddAssign::add_assign(self, *rhs);
244            }
245        }
246
247        impl AddAssign<SignedOne> for $primitive {
248            fn add_assign(&mut self, rhs: SignedOne) {
249                match rhs {
250                    SignedOne::PlusOne => *self += 1,
251                    SignedOne::MinusOne => *self -= 1,
252                }
253            }
254        }
255
256        impl Sub<SignedOne> for $primitive {
257            type Output = Self;
258
259            fn sub(mut self, rhs: SignedOne) -> Self::Output {
260                SubAssign::sub_assign(&mut self, rhs);
261                self
262            }
263        }
264
265        impl Sub<&SignedOne> for $primitive {
266            type Output = Self;
267
268            fn sub(mut self, rhs: &SignedOne) -> Self::Output {
269                SubAssign::sub_assign(&mut self, rhs);
270                self
271            }
272        }
273
274        impl SubAssign<&SignedOne> for $primitive {
275            fn sub_assign(&mut self, rhs: &SignedOne) {
276                SubAssign::sub_assign(self, *rhs);
277            }
278        }
279
280        impl SubAssign<SignedOne> for $primitive {
281            fn sub_assign(&mut self, rhs: SignedOne) {
282                match rhs {
283                    SignedOne::PlusOne => *self -= 1,
284                    SignedOne::MinusOne => *self += 1,
285                }
286            }
287        }
288    }
289}
290
291define_signed_ops!(i8);
292define_signed_ops!(i16);
293define_signed_ops!(i32);
294define_signed_ops!(i64);
295define_signed_ops!(i128);
296define_unsigned_ops!(i8);
297define_unsigned_ops!(i16);
298define_unsigned_ops!(i32);
299define_unsigned_ops!(i64);
300define_unsigned_ops!(i128);
301
302define_unsigned_ops!(u8);
303define_unsigned_ops!(u16);
304define_unsigned_ops!(u32);
305define_unsigned_ops!(u64);
306define_unsigned_ops!(u128);
307
308#[cfg(test)]
309mod test {
310    use std::cmp::Ordering;
311
312    use crate::{Negateable, NonZero, Sign, Signed};
313    use crate::fixed::SignedOne;
314
315    #[test]
316    fn test_signed_one() {
317        assert_eq!(<SignedOne as num_traits::One>::one(), SignedOne::PlusOne);
318        assert_eq!(SignedOne::PlusOne * SignedOne::PlusOne, SignedOne::PlusOne);
319        assert_eq!(SignedOne::PlusOne * SignedOne::MinusOne, SignedOne::MinusOne);
320        assert_eq!(SignedOne::MinusOne * SignedOne::MinusOne, SignedOne::PlusOne);
321    }
322
323    #[test]
324    fn test_default() {
325        assert_eq!(SignedOne::default(), SignedOne::PlusOne);
326    }
327
328    #[test]
329    fn test_signum() {
330        assert_eq!(SignedOne::PlusOne.signum(), Sign::Positive);
331        assert_eq!(SignedOne::MinusOne.signum(), Sign::Negative);
332        assert!(SignedOne::PlusOne.is_positive());
333        assert!(!SignedOne::MinusOne.is_positive());
334        assert!(SignedOne::MinusOne.is_negative());
335        assert!(!SignedOne::PlusOne.is_negative());
336    }
337
338    #[test]
339    fn test_non_zero() {
340        assert!(SignedOne::PlusOne.is_not_zero());
341        assert!(SignedOne::MinusOne.is_not_zero());
342    }
343
344    #[test]
345    fn test_negate() {
346        assert_eq!(-SignedOne::PlusOne, SignedOne::MinusOne);
347        assert_eq!(-SignedOne::MinusOne, SignedOne::PlusOne);
348
349        let mut value = SignedOne::PlusOne;
350        value.negate();
351        assert_eq!(value, SignedOne::MinusOne);
352        value.negate();
353        assert_eq!(value, SignedOne::PlusOne);
354    }
355
356    /// A derived `Ord` would get this backwards, because `PlusOne` is declared first.
357    #[test]
358    fn test_ord() {
359        assert_eq!(SignedOne::MinusOne.cmp(&SignedOne::PlusOne), Ordering::Less);
360        assert_eq!(SignedOne::PlusOne.cmp(&SignedOne::MinusOne), Ordering::Greater);
361        assert!(SignedOne::MinusOne < SignedOne::PlusOne);
362
363        for a in [SignedOne::MinusOne, SignedOne::PlusOne] {
364            assert_eq!(a.cmp(&a), Ordering::Equal);
365            for b in [SignedOne::MinusOne, SignedOne::PlusOne] {
366                assert_eq!(a.partial_cmp(&b), Some(a.cmp(&b)));
367                assert_eq!(a.cmp(&b), b.cmp(&a).reverse());
368                assert_eq!(a == b, a.cmp(&b) == Ordering::Equal);
369            }
370        }
371    }
372
373    #[test]
374    fn test_display() {
375        assert_eq!(SignedOne::PlusOne.to_string(), "1");
376        assert_eq!(SignedOne::MinusOne.to_string(), "-1");
377        assert_eq!(format!("{:?}", SignedOne::PlusOne), "1");
378        assert_eq!(format!("{:?}", SignedOne::MinusOne), "-1");
379    }
380
381    #[test]
382    fn test_integer() {
383        assert_eq!(1 + SignedOne::PlusOne, 2);
384        assert_eq!(-1 + SignedOne::PlusOne, 0);
385        assert_eq!(1 + SignedOne::PlusOne, 2);
386        assert_eq!(-1 + SignedOne::PlusOne, 0);
387        assert_eq!(33 / SignedOne::PlusOne, 33);
388        assert_eq!(-33 / &SignedOne::PlusOne, -33);
389        assert_eq!(894 * SignedOne::PlusOne, 894);
390        assert_eq!(-894 * &SignedOne::PlusOne, -894);
391
392        assert_eq!(1 + SignedOne::MinusOne, 0);
393        assert_eq!(-1 + SignedOne::MinusOne, -2);
394        assert_eq!(1 - SignedOne::MinusOne, 2);
395        assert_eq!(-1 - SignedOne::MinusOne, 0);
396        assert_eq!(33 / SignedOne::MinusOne, -33);
397        assert_eq!(-33 / &SignedOne::MinusOne, 33);
398        assert_eq!(894 * SignedOne::MinusOne, -894);
399        assert_eq!(-894 * &SignedOne::MinusOne, 894);
400    }
401}