1#![allow(non_upper_case_globals)]
9
10use std::ops::{Add, Neg, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
11use std::str::FromStr;
12use derive_more::{Display, Debug};
13use num_traits::{Zero, One};
14use auto_impl_ops::auto_ops;
15
16use crate::abst::{MathType, AddMonOps, AddGrpOps, MonOps, RingOps, FieldOps, EucRingOps, AddMon, AddGrp, Mon, Ring, EucRing, Field};
17use crate::util::parse_err::ParseErr;
18
19type I = i32;
20
21#[derive(Clone, Copy, PartialEq, Eq, Default, Display, Debug)]
23#[display( "{}", _0)]
24#[debug( "{}", _0)]
25pub struct FF<const p: I>(I);
26
27impl<const p: I> FF<p> {
28 pub fn new(a: I) -> Self {
29 assert!(p > 0);
30 Self(a.rem_euclid(p))
31 }
32
33 pub fn rep(&self) -> &I {
34 &self.0
35 }
36}
37
38impl<const p: I> From<I> for FF<p> {
39 fn from(a: I) -> Self {
40 Self::new(a)
41 }
42}
43
44impl<const p: I> FromStr for FF<p> {
45 type Err = ParseErr;
46 fn from_str(s: &str) -> Result<Self, Self::Err> {
47 let a = s.parse::<I>().map_err(|_| ParseErr::invalid(s, &Self::math_symbol()))?;
48 Ok(Self::from(a))
49 }
50}
51
52impl<const p: I> Zero for FF<p> {
53 fn zero() -> Self {
54 Self(0)
55 }
56
57 fn is_zero(&self) -> bool {
58 self.0.is_zero()
59 }
60}
61
62impl<const p: I> One for FF<p> {
63 fn one() -> Self {
64 Self(1)
65 }
66
67 fn is_one(&self) -> bool {
68 self.0.is_one()
69 }
70}
71
72macro_rules! impl_unop {
73 ($trait:ident, $method:ident) => {
74 impl<const p: I> $trait for FF<p> {
75 type Output = Self;
76 fn $method(self) -> Self::Output {
77 Self::new(self.0.$method())
78 }
79 }
80
81 impl<const p: I> $trait for &FF<p> {
82 type Output = FF<p>;
83 #[inline]
84 fn $method(self) -> Self::Output {
85 FF::new(self.0.$method())
86 }
87 }
88 };
89}
90
91impl_unop!(Neg, neg);
92
93macro_rules! impl_binop {
94 ($trait:ident, $method:ident) => {
95 #[auto_ops]
96 impl<const p: I> $trait<&FF<p>> for &FF<p> {
97 type Output = FF<p>;
98 fn $method(self, rhs: &FF<p>) -> Self::Output {
99 FF::new(self.0.$method(&rhs.0))
100 }
101 }
102 }
103}
104
105impl_binop!(Add, add);
106impl_binop!(Sub, sub);
107impl_binop!(Mul, mul);
108
109#[auto_ops]
110impl<const p: I> Div<&FF<p>> for &FF<p> {
111 type Output = FF<p>;
112 fn div(self, rhs: &FF<p>) -> Self::Output {
113 assert!(!rhs.is_zero());
114 self * rhs.inv().unwrap()
115 }
116}
117
118#[auto_ops]
119impl<const p: I> Rem<&FF<p>> for &FF<p> {
120 type Output = FF<p>;
121 fn rem(self, rhs: &FF<p>) -> Self::Output {
122 assert!(!rhs.is_zero());
123 FF::zero() }
125}
126
127macro_rules! impl_alg_ops {
128 ($trait:ident) => {
129 impl<const p: I> $trait for FF<p> {}
130 impl<const p: I> $trait<FF<p>> for &FF<p> {}
131 };
132}
133
134impl_alg_ops!(AddMonOps);
135impl_alg_ops!(AddGrpOps);
136impl_alg_ops!(MonOps);
137impl_alg_ops!(RingOps);
138impl_alg_ops!(EucRingOps);
139impl_alg_ops!(FieldOps);
140
141impl<const p: I> MathType for FF<p> {
142 fn math_symbol() -> String {
143 use crate::util::format::subscript;
144 format!("F{}", subscript(p as isize))
145 }
146}
147
148impl<const p: I> AddMon for FF<p> {}
149impl<const p: I> AddGrp for FF<p> {}
150impl<const p: I> Mon for FF<p> {}
151
152impl<const p: I> Ring for FF<p> {
153 fn inv(&self) -> Option<Self> {
154 if self.is_zero() {
155 None
156 } else {
157 let (d, x, _y) = I::gcdx(&self.0, &p);
159
160 assert!(d.is_one());
161
162 let inv = Self::new(x);
163 Some(inv)
164 }
165 }
166
167 fn is_unit(&self) -> bool {
168 !self.is_zero()
169 }
170
171 fn normalizing_unit(&self) -> Self {
172 if self.is_zero() {
173 Self::one()
174 } else {
175 self.inv().unwrap()
176 }
177 }
178}
179
180impl<const p: I> EucRing for FF<p> {}
181impl<const p: I> Field for FF<p> {}
182
183mod tex {
184 use crate::util::tex::TeX;
185 use super::*;
186
187 impl<const p: I> TeX for FF<p> {
188 fn tex_math_symbol() -> String {
189 format!("\\mathbb{{F}}_{p}")
190 }
191 fn tex_string(&self) -> String {
192 self.to_string()
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 type F3 = FF<3>;
202 type F5 = FF<5>;
203
204 #[test]
205 fn init() {
206 let a = F3::new(-7);
207 assert_eq!(a.0, 2);
208
209 let a = F5::new(-7);
210 assert_eq!(a.0, 3);
211 }
212
213 #[test]
214 fn display() {
215 let a = F3::new(-7);
216 assert_eq!(format!("{}", a), "2");
217
218 let a = F5::new(-7);
219 assert_eq!(format!("{}", a), "3");
220 }
221
222 #[test]
223 fn debug() {
224 let a = F3::new(-7);
225 assert_eq!(format!("{:?}", a), "2");
226
227 let a = F5::new(-7);
228 assert_eq!(format!("{:?}", a), "3");
229 }
230
231 #[test]
232 fn add() {
233 let a = F5::new(3);
234 let b = F5::new(4);
235
236 assert_eq!(a + b, F5::new(2));
237 }
238
239 #[test]
240 fn add_assign() {
241 let mut a = F5::new(3);
242 a += F5::new(4);
243 assert_eq!(a, F5::new(2));
244 }
245
246 #[test]
247 fn neg() {
248 let a = F5::new(3);
249 assert_eq!(-a, F5::new(2));
250 }
251
252 #[test]
253 fn sub() {
254 let a = F5::new(3);
255 let b = F5::new(4);
256
257 assert_eq!(a - b, F5::new(4));
258 }
259
260 #[test]
261 fn sub_assign() {
262 let mut a = F5::new(3);
263 a -= F5::new(4);
264 assert_eq!(a, F5::new(4));
265 }
266
267 #[test]
268 fn mul() {
269 let a = F5::new(3);
270 let b = F5::new(4);
271 assert_eq!(a * b, F5::new(2));
272 }
273
274 #[test]
275 fn mul_assign() {
276 let mut a = F5::new(3);
277 a *= F5::new(4);
278 assert_eq!(a, F5::new(2));
279 }
280
281 #[test]
282 fn div() {
283 let a = F5::new(4);
284 let b = F5::new(3);
285 assert_eq!(a / b, F5::new(3));
286 }
287
288 #[test]
289 fn div_assign() {
290 let mut a = F5::new(4);
291 a /= F5::new(3);
292 assert_eq!(a, F5::new(3));
293 }
294
295
296 #[test]
297 fn rem() {
298 let a = F5::new(4);
299 let b = F5::new(3);
300 assert_eq!(a % b, F5::zero());
301 }
302
303 #[test]
304 fn rem_assign() {
305 let mut a = F5::new(4);
306 a %= F5::new(3);
307 assert_eq!(a, F5::zero());
308 }
309
310 #[test]
311 fn tex() {
312 use crate::util::tex::TeX;
313 assert_eq!(F3::tex_math_symbol(), "\\mathbb{F}_3");
314 assert_eq!(F3::from(5).tex_string(), "2");
315 }
316}