1use std::{
9 cmp::Ordering,
10 fmt::{Debug, Display},
11 ops::{self, Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
12};
13
14use crate::expressions::{Atomic, IntegerExpression};
15
16#[derive(Debug, Clone, Copy, PartialEq, Hash)]
18pub struct Fraction {
19 negated: bool,
21 numerator: u32,
23 denominator: u32,
25}
26
27impl Display for Fraction {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 debug_assert!(self.is_simplified());
30
31 if let Ok(c) = i64::try_from(*self) {
32 write!(f, "{c}")
33 } else {
34 if self.negated {
35 write!(f, "-")?;
36 }
37 write!(f, "{}/{}", self.numerator, self.denominator)
38 }
39 }
40}
41
42impl Fraction {
43 pub fn is_negative(&self) -> bool {
59 debug_assert!(self.is_simplified());
60 self.negated
61 }
62
63 pub fn is_zero(&self) -> bool {
78 self.numerator == 0
79 }
80
81 pub fn is_integer(&self) -> bool {
97 self.numerator.is_multiple_of(self.denominator)
98 }
99
100 fn is_simplified(&self) -> bool {
102 num::integer::gcd(self.numerator, self.denominator) == 1
103 }
104
105 pub fn new(numerator: u32, denominator: u32, negated: bool) -> Self {
123 Self {
124 negated,
125 numerator,
126 denominator,
127 }
128 .canonicalize()
129 }
130
131 fn canonicalize(self) -> Self {
133 if self.numerator == 0 {
135 return Self {
136 negated: false,
137 numerator: 0,
138 denominator: 1,
139 };
140 }
141
142 if self.denominator == 0 {
144 return Self {
145 negated: false,
146 numerator: 1,
147 denominator: 0,
148 };
149 }
150
151 let mut numerator = self.numerator;
153 let mut denominator = self.denominator;
154 let gcd = num::integer::gcd(self.numerator, self.denominator);
155
156 numerator /= gcd;
157 denominator /= gcd;
158
159 Self {
160 negated: self.negated,
161 numerator,
162 denominator,
163 }
164 }
165
166 pub fn inverse(&self) -> Self {
180 if self.numerator() == 0 {
181 panic!("Division by zero undefined!");
182 }
183
184 Self {
185 negated: self.negated,
186 numerator: self.denominator,
187 denominator: self.numerator,
188 }
189 }
190
191 pub fn denominator(&self) -> u32 {
202 debug_assert!(self.is_simplified());
203 self.denominator
204 }
205
206 pub fn numerator(&self) -> u32 {
217 debug_assert!(self.is_simplified());
218 self.numerator
219 }
220
221 pub fn get_ceil(&self) -> Option<u32> {
243 debug_assert!(self.is_simplified());
244 if self.is_negative() {
245 return None;
246 }
247
248 let mut c = self.numerator / self.denominator;
249 if !self.numerator.is_multiple_of(self.denominator) {
250 c += 1;
251 }
252
253 Some(c)
254 }
255
256 pub fn get_floor(&self) -> Option<u32> {
278 debug_assert!(self.is_simplified());
279 if self.is_negative() {
280 return None;
281 }
282
283 Some(self.numerator / self.denominator)
284 }
285}
286
287impl ops::Neg for Fraction {
288 type Output = Self;
289
290 fn neg(self) -> Self::Output {
291 debug_assert!(self.is_simplified());
292 Self {
293 negated: !self.negated,
294 numerator: self.numerator,
295 denominator: self.denominator,
296 }
297 }
298}
299
300impl Eq for Fraction {}
301
302impl Add for Fraction {
303 type Output = Self;
304
305 fn add(self, rhs: Self) -> Self::Output {
306 if self.negated == rhs.negated {
307 Fraction::new(
308 self.numerator * rhs.denominator + rhs.numerator * self.denominator,
309 self.denominator * rhs.denominator,
310 self.negated,
311 )
312 } else {
313 let denominator = self.denominator * rhs.denominator;
314 let (negated, non_negated) = if self.negated {
315 (self, rhs)
316 } else {
317 (rhs, self)
318 };
319
320 if non_negated.numerator * negated.denominator
321 >= negated.numerator * non_negated.denominator
322 {
323 Fraction::new(
324 non_negated.numerator * negated.denominator
325 - negated.numerator * non_negated.denominator,
326 denominator,
327 false,
328 )
329 } else {
330 Fraction::new(
331 negated.numerator * non_negated.denominator
332 - non_negated.numerator * negated.denominator,
333 denominator,
334 true,
335 )
336 }
337 }
338 }
339}
340
341impl AddAssign for Fraction {
342 fn add_assign(&mut self, rhs: Self) {
343 *self = *self + rhs;
344 }
345}
346
347impl Sub for Fraction {
348 type Output = Self;
349
350 fn sub(self, rhs: Self) -> Self::Output {
351 self + (-rhs)
352 }
353}
354
355impl SubAssign for Fraction {
356 fn sub_assign(&mut self, rhs: Self) {
357 *self = *self - rhs;
358 }
359}
360
361impl Mul for Fraction {
362 type Output = Self;
363
364 fn mul(self, rhs: Self) -> Self::Output {
365 Fraction::new(
366 self.numerator * rhs.numerator,
367 self.denominator * rhs.denominator,
368 self.negated ^ rhs.negated,
369 )
370 }
371}
372
373impl MulAssign for Fraction {
374 fn mul_assign(&mut self, rhs: Self) {
375 *self = *self * rhs;
376 }
377}
378
379impl Div for Fraction {
380 type Output = Self;
381
382 #[allow(clippy::suspicious_arithmetic_impl)]
383 fn div(self, rhs: Self) -> Self::Output {
384 self * Fraction::new(rhs.denominator, rhs.numerator, rhs.negated)
385 }
386}
387
388impl DivAssign for Fraction {
389 fn div_assign(&mut self, rhs: Self) {
390 *self = *self / rhs;
391 }
392}
393
394impl From<u32> for Fraction {
395 fn from(value: u32) -> Self {
396 Fraction {
397 negated: false,
398 numerator: value,
399 denominator: 1,
400 }
401 }
402}
403
404impl PartialOrd for Fraction {
405 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
406 Some(self.cmp(other))
407 }
408}
409
410impl Ord for Fraction {
411 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
412 let a = self.numerator * other.denominator;
413 let b = other.numerator * self.denominator;
414
415 if self.negated && !other.negated {
416 return Ordering::Less;
417 }
418
419 if !self.negated && other.negated {
420 return Ordering::Greater;
421 }
422
423 if self.negated && other.negated {
424 return a.cmp(&b).reverse();
426 }
427 a.cmp(&b)
428 }
429}
430
431impl TryFrom<Fraction> for i64 {
432 type Error = ();
433
434 fn try_from(value: Fraction) -> Result<Self, Self::Error> {
436 if value.numerator.is_multiple_of(value.denominator) {
437 let mut res = value.numerator as i64 / value.denominator as i64;
438
439 if value.negated {
440 res = -res;
441 }
442
443 Ok(res)
444 } else {
445 Err(())
446 }
447 }
448}
449
450impl<T: Atomic> From<Fraction> for IntegerExpression<T> {
451 fn from(value: Fraction) -> Self {
452 if let Ok(c) = i64::try_from(value) {
454 if c < 0 {
455 return -IntegerExpression::Const(-c as u32);
456 } else {
457 return IntegerExpression::Const(c as u32);
458 }
459 }
460
461 let mut expr =
463 IntegerExpression::Const(value.numerator) / IntegerExpression::Const(value.denominator);
464
465 if value.negated {
466 expr = -expr;
467 }
468
469 expr
470 }
471}
472
473#[cfg(test)]
474mod tests {
475
476 use crate::expressions::Variable;
477
478 use super::*;
479
480 #[test]
481 fn test_fraction_getters() {
482 let f = Fraction::new(4, 8, false);
483 assert_eq!(f.numerator(), 1);
484 assert_eq!(f.denominator(), 2);
485 assert!(!f.is_negative());
486
487 let f = Fraction::new(12, 9, true);
488 assert_eq!(f.numerator(), 4);
489 assert_eq!(f.denominator(), 3);
490 }
491
492 #[test]
493 fn test_fraction_get_ceil() {
494 let f = Fraction::new(6, 2, false);
496 assert_eq!(f.get_ceil(), Some(3));
497
498 let f = Fraction::new(4, 2, true);
499 assert_eq!(f.get_ceil(), None);
500
501 let f = Fraction::new(5, 2, false);
503 assert_eq!(f.get_ceil(), Some(3));
504
505 let f = Fraction::new(1, 3, false);
506 assert_eq!(f.get_ceil(), Some(1));
507
508 let f = Fraction::new(7, 3, false);
509 assert_eq!(f.get_ceil(), Some(3));
510
511 let f = Fraction::new(2, 3, false);
512 assert_eq!(f.get_ceil(), Some(1));
513
514 let f = Fraction::new(0, 1, false);
516 assert_eq!(f.get_ceil(), Some(0));
517
518 let f = Fraction::new(1, 2, true);
520 assert_eq!(f.get_ceil(), None);
521 }
522
523 #[test]
524 fn test_fraction_get_floor() {
525 let f = Fraction::new(6, 2, false);
527 assert_eq!(f.get_floor(), Some(3));
528
529 let f = Fraction::new(4, 2, true);
530 assert_eq!(f.get_floor(), None);
531
532 let f = Fraction::new(5, 2, false);
534 assert_eq!(f.get_floor(), Some(2));
535
536 let f = Fraction::new(1, 3, false);
537 assert_eq!(f.get_floor(), Some(0));
538
539 let f = Fraction::new(7, 3, false);
540 assert_eq!(f.get_floor(), Some(2));
541
542 let f = Fraction::new(0, 1, false);
544 assert_eq!(f.get_floor(), Some(0));
545
546 let f = Fraction::new(1, 2, true);
548 assert_eq!(f.get_floor(), None);
549
550 let f = Fraction::new(9, 3, false);
552 assert_eq!(f.get_floor(), f.get_ceil());
553 }
554
555 #[test]
556 fn test_fraction_is_zero() {
557 let f = Fraction::new(0, 1, false);
559 assert!(f.is_zero());
560
561 let f = Fraction::new(0, 1, true);
562 assert!(f.is_zero());
563
564 let f = Fraction::new(0, 5, false);
565 assert!(f.is_zero());
566
567 let f = Fraction::new(1, 2, false);
569 assert!(!f.is_zero());
570
571 let f = Fraction::new(42, 7, false);
572 assert!(!f.is_zero());
573
574 let f = Fraction::new(1, 2, true);
575 assert!(!f.is_zero());
576
577 let f = Fraction::new(0, 5, true);
579 assert!(f.is_zero());
580 assert_eq!(f.numerator(), 0);
581 assert_eq!(f.denominator(), 1);
582 assert!(!f.is_negative());
583 }
584
585 #[test]
586 fn test_fraction_is_integer() {
587 let f1 = Fraction::new(4, 2, false);
588 assert!(f1.is_integer());
589 let f2 = Fraction::new(5, 2, false);
590 assert!(!f2.is_integer());
591 let f3 = Fraction::new(0, 1, false);
592 assert!(f3.is_integer());
593 let f4 = Fraction::new(0, 0, false);
594 assert!(f4.is_integer()); }
596
597 #[test]
598 fn test_simplification_for_div_by_zero() {
599 let f1 = Fraction::new(42, 0, true);
600 let f2 = Fraction::new(1, 0, false);
601 assert_eq!(f1, f2);
602 }
603
604 #[test]
605 fn test_fraction_addition() {
606 let f1 = Fraction::new(1, 2, false);
607 let f2 = Fraction::new(1, 3, false);
608 let result = f1 + f2;
609 assert_eq!(result.numerator, 5);
610 assert_eq!(result.denominator, 6);
611 assert!(!result.negated);
612
613 let f1 = Fraction::new(5, 10, false);
614 let f2 = Fraction::new(10, 30, true);
615 let result = f1 + f2;
616 assert_eq!(result.numerator, 1);
617 assert_eq!(result.denominator, 6);
618 assert!(!result.negated);
619
620 let f1 = Fraction::new(3, 6, true);
621 let f2 = Fraction::new(1, 3, false);
622 let result = f1 + f2;
623 assert_eq!(result.numerator, 1);
624 assert_eq!(result.denominator, 6);
625 assert!(result.negated);
626
627 let mut f1 = Fraction::new(3, 6, true);
628 let f2 = Fraction::new(2, 8, true);
629 f1 += f2;
630 assert_eq!(f1.numerator, 3);
631 assert_eq!(f1.denominator, 4);
632 assert!(f1.negated);
633 }
634
635 #[test]
636 fn test_fraction_subtraction() {
637 let f1 = Fraction::new(100, 200, false);
638 let f2 = Fraction::new(10, 30, false);
639 let result = f1 - f2;
640 assert_eq!(result.numerator, 1);
641 assert_eq!(result.denominator, 6);
642 assert!(!result.negated);
643
644 let f1 = Fraction::new(9, 18, false);
645 let f2 = Fraction::new(1, 3, true);
646 let result = f1 - f2;
647 assert_eq!(result.numerator, 5);
648 assert_eq!(result.denominator, 6);
649 assert!(!result.negated);
650
651 let mut f1 = Fraction::new(3, 6, true);
652 let f2 = Fraction::new(1, 3, false);
653 f1 -= f2;
654 assert_eq!(f1.numerator, 5);
655 assert_eq!(f1.denominator, 6);
656 assert!(f1.negated);
657 }
658
659 #[test]
660 fn test_fraction_multiplication() {
661 let f1 = Fraction::new(1, 2, false);
662 let f2 = Fraction::new(1, 3, false);
663 let result = f1 * f2;
664 assert_eq!(result.numerator, 1);
665 assert_eq!(result.denominator, 6);
666 assert!(!result.negated);
667
668 let f1 = Fraction::new(1, 2, false);
669 let f2 = Fraction::new(5, 15, true);
670 let result = f1 * f2;
671 assert_eq!(result.numerator, 1);
672 assert_eq!(result.denominator, 6);
673 assert!(result.negated);
674
675 let f1 = Fraction::new(1, 2, true);
676 let f2 = Fraction::new(1, 3, true);
677 let result = f1 * f2;
678 assert_eq!(result.numerator, 1);
679 assert_eq!(result.denominator, 6);
680 assert!(!result.negated);
681
682 let mut f1 = Fraction::new(1, 2, false);
683 let f2 = Fraction::new(1, 3, true);
684 f1 *= f2;
685 assert_eq!(f1.numerator, 1);
686 assert_eq!(f1.denominator, 6);
687 assert!(f1.negated);
688 }
689
690 #[test]
691 fn test_fraction_division() {
692 let f1 = Fraction::new(1, 2, false);
693 let f2 = Fraction::new(1, 3, false);
694 let result = f1 / f2;
695 assert_eq!(result.numerator, 3);
696 assert_eq!(result.denominator, 2);
697 assert!(!result.negated);
698
699 let f1 = Fraction::new(5, 10, false);
700 let f2 = Fraction::new(20, 40, false);
701 let result = f1 / f2;
702 assert_eq!(result.numerator, 1);
703 assert_eq!(result.denominator, 1);
704
705 let mut f1 = Fraction::new(1, 2, false);
706 let f2 = Fraction::new(1, 3, true);
707 f1 /= f2;
708 assert_eq!(f1.numerator, 3);
709 assert_eq!(f1.denominator, 2);
710 assert!(f1.negated);
711 }
712
713 #[test]
714 fn test_fraction_negation() {
715 let f1 = Fraction::new(1, 2, false);
716 let result = -f1;
717 assert_eq!(result.numerator, 1);
718 assert_eq!(result.denominator, 2);
719 assert!(result.negated);
720 }
721
722 #[test]
723 fn test_fraction_addition_with_negation() {
724 let f1 = Fraction::new(1, 2, false);
725 let f2 = Fraction::new(1, 3, true);
726 let result = f1 + f2;
727 assert_eq!(result.numerator, 1);
728 assert_eq!(result.denominator, 6);
729 assert!(!result.negated);
730 }
731
732 #[test]
733 fn test_fraction_subtraction_with_negation() {
734 let f1 = Fraction::new(1, 2, false);
735 let f2 = Fraction::new(1, 3, true);
736 let result = f1 - f2;
737 assert_eq!(result.numerator, 5);
738 assert_eq!(result.denominator, 6);
739 assert!(!result.negated);
740 }
741
742 #[test]
743 fn test_fraction_multiplication_with_negation() {
744 let f1 = Fraction::new(1, 2, false);
745 let f2 = Fraction::new(1, 3, true);
746 let result = f1 * f2;
747 assert_eq!(result.numerator, 1);
748 assert_eq!(result.denominator, 6);
749 assert!(result.negated);
750 }
751
752 #[test]
753 fn test_fraction_division_with_negation() {
754 let f1 = Fraction::new(1, 2, false);
755 let f2 = Fraction::new(1, 3, true);
756 let result = f1 / f2;
757 assert_eq!(result.numerator, 3);
758 assert_eq!(result.denominator, 2);
759 assert!(result.negated);
760 }
761
762 #[test]
763 fn test_fraction_simplification() {
764 let f = Fraction::new(4, 8, false).canonicalize();
765 assert_eq!(f.numerator, 1);
766 assert_eq!(f.denominator, 2);
767 assert!(!f.negated);
768 }
769
770 #[test]
771 fn test_fraction_eq() {
772 let f1 = Fraction::new(1, 2, false);
773 let f2 = Fraction::new(1, 2, false);
774 assert_eq!(f1, f2);
775
776 let f1 = Fraction::new(1, 2, false);
777 let f2 = Fraction::new(1, 2, true);
778 assert_ne!(f1, f2);
779
780 let f1 = Fraction::new(1, 2, false);
781 let f2 = Fraction::new(2, 4, false);
782 assert_eq!(f1, f2);
783
784 let f1 = Fraction::new(1, 2, false);
785 let f2 = Fraction::new(2, 4, true);
786 assert_ne!(f1, f2);
787
788 let f1 = Fraction::new(0, 2, true);
789 let f2 = Fraction::new(0, 2, false);
790 assert_eq!(f1, f2);
791
792 let f1 = Fraction::new(0, 2, true);
793 let f2 = Fraction::new(0, 3, true);
794 assert_eq!(f1, f2);
795 }
796
797 #[test]
798 fn test_fraction_simplification_with_negation() {
799 let f = Fraction::new(4, 8, true).canonicalize();
800 assert_eq!(f.numerator, 1);
801 assert_eq!(f.denominator, 2);
802 assert!(f.negated);
803 }
804
805 #[test]
806 fn test_fraction_from_u32() {
807 let f: Fraction = 5u32.into();
808 assert_eq!(f.numerator, 5);
809 assert_eq!(f.denominator, 1);
810 assert!(!f.negated);
811 }
812
813 #[test]
814 fn test_fraction_try_into_i64_success() {
815 let f = Fraction::new(4, 2, false);
816 let result: Result<i64, ()> = f.try_into();
817 assert_eq!(result.unwrap(), 2);
818 }
819
820 #[test]
821 fn test_fraction_try_into_i64_failure() {
822 let f = Fraction::new(5, 2, false);
823 let result: Result<i64, ()> = f.try_into();
824 assert!(result.is_err());
825 }
826
827 #[test]
828 fn test_fraction_try_into_i64_negated() {
829 let f = Fraction::new(4, 2, true);
830 let result: Result<i64, ()> = f.try_into();
831 assert_eq!(result.unwrap(), -2);
832 }
833
834 #[test]
835 fn test_fraction_display() {
836 let f = Fraction::new(1, 2, false);
837 assert_eq!(f.to_string(), "1/2");
838
839 let f = Fraction::new(1, 2, true);
840 assert_eq!(f.to_string(), "-1/2");
841
842 let f = Fraction::new(1, 1, false);
843 assert_eq!(f.to_string(), "1");
844 }
845
846 #[test]
847 fn test_fraction_into_integer_expression() {
848 let f = Fraction::new(1, 2, false);
849 let expr: IntegerExpression<Variable> = f.into();
850 assert_eq!(
851 expr,
852 IntegerExpression::Const(1) / IntegerExpression::Const(2)
853 );
854
855 let f = Fraction::new(1, 2, true);
856 let expr: IntegerExpression<Variable> = f.into();
857 assert_eq!(
858 expr,
859 -(IntegerExpression::Const(1) / IntegerExpression::Const(2))
860 );
861
862 let f = Fraction::new(1, 1, false);
863 let expr: IntegerExpression<Variable> = f.into();
864 assert_eq!(expr, IntegerExpression::Const(1));
865
866 let f = Fraction::new(1, 1, true);
867 let expr: IntegerExpression<Variable> = f.into();
868 assert_eq!(expr, -IntegerExpression::Const(1));
869 }
870
871 #[test]
872 fn test_inverse() {
873 let f = Fraction::new(1, 2, true);
874 let expected = Fraction::new(2, 1, true);
875 assert_eq!(f.inverse(), expected);
876
877 let f = Fraction::new(1, 2, false);
878 let expected = Fraction::new(2, 1, false);
879 assert_eq!(f.inverse(), expected);
880 }
881
882 #[test]
883 #[should_panic]
884 fn test_inverse_panics_on_0_numerator() {
885 let f = Fraction::new(0, 2, true);
886 let _ = f.inverse();
887 }
888
889 #[test]
890 fn test_fraction_ord() {
891 let f1 = Fraction::new(1, 2, false);
892 let f2 = Fraction::new(1, 2, false);
893 assert_eq!(f1.cmp(&f2), Ordering::Equal);
894 assert_eq!(f2.cmp(&f1), Ordering::Equal);
895
896 let f1 = Fraction::new(1, 2, true);
897 let f2 = Fraction::new(1, 2, true);
898 assert_eq!(f1.cmp(&f2), Ordering::Equal);
899 assert_eq!(f2.cmp(&f1), Ordering::Equal);
900
901 let f1 = Fraction::new(1, 2, true);
902 let f2 = Fraction::new(1, 2, false);
903 assert_eq!(f1.cmp(&f2), Ordering::Less);
904 assert_eq!(f2.cmp(&f1), Ordering::Greater);
905
906 let f1 = Fraction::new(1, 2, false);
907 let f2 = Fraction::new(2, 2, false);
908 assert_eq!(f1.cmp(&f2), Ordering::Less);
909 assert_eq!(f2.cmp(&f1), Ordering::Greater);
910
911 let f1 = Fraction::new(1, 4, false);
912 let f2 = Fraction::new(1, 2, false);
913 assert_eq!(f1.cmp(&f2), Ordering::Less);
914 assert_eq!(f2.cmp(&f1), Ordering::Greater);
915 }
916}