1use std::cmp::Ordering;
2use std::fmt;
3use std::ops::Neg;
4
5pub use crate::rational::Rational;
6
7pub trait IntoRational {
9 fn into_rational(self) -> Rational;
10}
11
12impl IntoRational for Rational {
13 fn into_rational(self) -> Rational {
14 self
15 }
16}
17
18impl IntoRational for i32 {
19 fn into_rational(self) -> Rational {
20 Rational::from(self)
21 }
22}
23
24impl IntoRational for i64 {
25 fn into_rational(self) -> Rational {
26 Rational::from(self)
27 }
28}
29
30impl IntoRational for (i64, i64) {
32 fn into_rational(self) -> Rational {
33 ratio(self.0, self.1)
34 }
35}
36
37pub fn ratio(n: i64, d: i64) -> Rational {
39 Rational::new(n, d)
40}
41
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49#[derive(Clone, Debug, PartialEq, Eq)]
50pub struct Coef {
51 pub m: Rational,
53 pub c: Rational,
55}
56
57impl Coef {
58 pub fn zero() -> Self {
59 Coef::constant(Rational::zero())
60 }
61
62 pub fn constant(c: Rational) -> Self {
63 Coef {
64 m: Rational::zero(),
65 c,
66 }
67 }
68
69 pub fn big_m(m: Rational) -> Self {
70 Coef {
71 m,
72 c: Rational::zero(),
73 }
74 }
75
76 pub fn is_zero(&self) -> bool {
77 self.m.is_zero() && self.c.is_zero()
78 }
79
80 pub fn is_negative(&self) -> bool {
81 match self.m.cmp(&Rational::zero()) {
82 Ordering::Less => true,
83 Ordering::Greater => false,
84 Ordering::Equal => self.c.is_negative(),
85 }
86 }
87
88 pub fn is_positive(&self) -> bool {
89 match self.m.cmp(&Rational::zero()) {
90 Ordering::Greater => true,
91 Ordering::Less => false,
92 Ordering::Equal => self.c.is_positive(),
93 }
94 }
95
96 pub(crate) fn sub_mul(&mut self, f: &Coef, r: &Rational) {
98 self.m -= &f.m * r;
99 self.c -= &f.c * r;
100 }
101}
102
103impl PartialOrd for Coef {
104 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
105 Some(self.cmp(other))
106 }
107}
108
109impl Ord for Coef {
110 fn cmp(&self, other: &Self) -> Ordering {
111 self.m.cmp(&other.m).then_with(|| self.c.cmp(&other.c))
112 }
113}
114
115impl Neg for Coef {
116 type Output = Coef;
117
118 fn neg(self) -> Coef {
119 Coef {
120 m: -self.m,
121 c: -self.c,
122 }
123 }
124}
125
126impl fmt::Display for Coef {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 if self.m.is_zero() {
129 return write!(f, "{}", self.c);
130 }
131 let one = Rational::one();
132 let m = if self.m == one {
133 "M".to_string()
134 } else if self.m == -one {
135 "-M".to_string()
136 } else {
137 format!("{}M", self.m)
138 };
139 if self.c.is_zero() {
140 write!(f, "{m}")
141 } else if self.c.is_negative() {
142 write!(f, "{m} - {}", -self.c.clone())
143 } else {
144 write!(f, "{m} + {}", self.c)
145 }
146 }
147}