1#[cfg(not(feature = "gmp"))]
8use num_bigint::BigInt;
9#[cfg(not(feature = "gmp"))]
10use num_integer::Integer as _;
11#[cfg(not(feature = "gmp"))]
12use num_traits::{One, Zero};
13#[cfg(not(feature = "gmp"))]
14use std::ops::{Add, Div, Mul, Rem, Sub};
15
16#[cfg(not(feature = "gmp"))]
17use crate::domain::{Domain, EuclideanDomain};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct IntegerDomain;
33
34#[cfg(not(feature = "gmp"))]
35#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
48pub struct Integer(BigInt);
49
50#[cfg(not(feature = "gmp"))]
51impl Integer {
52 pub fn new<T: Into<BigInt>>(value: T) -> Self {
54 Self(value.into())
55 }
56
57 pub fn inner(&self) -> &BigInt {
59 &self.0
60 }
61
62 pub fn to_bigint(&self) -> BigInt {
64 self.0.clone()
65 }
66
67 pub fn to_i64(&self) -> Option<i64> {
69 use num_traits::ToPrimitive;
70 self.0.to_i64()
71 }
72
73 pub fn pow_u32(&self, exp: u32) -> Self {
75 use num_traits::Pow;
76 Integer(self.0.clone().pow(exp))
77 }
78}
79
80#[cfg(not(feature = "gmp"))]
81impl std::fmt::Display for Integer {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 write!(f, "{}", self.0)
84 }
85}
86
87#[cfg(not(feature = "gmp"))]
88impl Domain for IntegerDomain {
89 type Element = Integer;
90
91 fn zero(&self) -> Self::Element {
92 Integer(BigInt::zero())
93 }
94
95 fn one(&self) -> Self::Element {
96 Integer(BigInt::one())
97 }
98
99 fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
100 Integer(a.0.clone() + b.0.clone())
101 }
102
103 fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
104 Integer(a.0.clone() - b.0.clone())
105 }
106
107 fn neg(&self, a: &Self::Element) -> Self::Element {
108 Integer(-a.0.clone())
109 }
110
111 fn mul(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
112 Integer(a.0.clone() * b.0.clone())
113 }
114
115 fn div(&self, a: &Self::Element, b: &Self::Element) -> Option<Self::Element> {
116 if b.0.is_zero() {
117 return None;
118 }
119 let (q, r) = a.0.clone().div_rem(&b.0);
120 if r.is_zero() { Some(Integer(q)) } else { None }
121 }
122
123 fn inv(&self, a: &Self::Element) -> Option<Self::Element> {
124 if a.0.is_one() {
125 Some(self.one())
126 } else if a.0 == -BigInt::one() {
127 Some(Integer(-BigInt::one()))
128 } else {
129 None
130 }
131 }
132}
133
134#[cfg(not(feature = "gmp"))]
135impl EuclideanDomain for IntegerDomain {
136 fn div_rem(
137 &self,
138 a: &Self::Element,
139 b: &Self::Element,
140 ) -> Option<(Self::Element, Self::Element)> {
141 if b.0.is_zero() {
142 return None;
143 }
144 let (q, r) = a.0.clone().div_rem(&b.0);
145 Some((Integer(q), Integer(r)))
146 }
147}
148
149#[cfg(not(feature = "gmp"))]
150impl From<i64> for Integer {
151 fn from(value: i64) -> Self {
152 Self::new(value)
153 }
154}
155
156#[cfg(not(feature = "gmp"))]
157impl From<BigInt> for Integer {
158 fn from(value: BigInt) -> Self {
159 Self(value)
160 }
161}
162
163#[cfg(not(feature = "gmp"))]
169macro_rules! impl_int_op_owned {
170 ($trait:ident, $method:ident, $op:tt) => {
171 impl $trait for Integer {
172 type Output = Integer;
173 fn $method(self, rhs: Integer) -> Integer {
174 Integer(self.0 $op rhs.0)
175 }
176 }
177 impl $trait<&Integer> for Integer {
178 type Output = Integer;
179 fn $method(self, rhs: &Integer) -> Integer {
180 Integer(self.0 $op &rhs.0)
181 }
182 }
183 impl $trait<Integer> for &Integer {
184 type Output = Integer;
185 fn $method(self, rhs: Integer) -> Integer {
186 Integer(&self.0 $op rhs.0)
187 }
188 }
189 impl $trait<&Integer> for &Integer {
190 type Output = Integer;
191 fn $method(self, rhs: &Integer) -> Integer {
192 Integer(&self.0 $op &rhs.0)
193 }
194 }
195 };
196}
197
198#[cfg(not(feature = "gmp"))]
199impl_int_op_owned!(Add, add, +);
200#[cfg(not(feature = "gmp"))]
201impl_int_op_owned!(Sub, sub, -);
202#[cfg(not(feature = "gmp"))]
203impl_int_op_owned!(Mul, mul, *);
204#[cfg(not(feature = "gmp"))]
205impl_int_op_owned!(Div, div, /);
206#[cfg(not(feature = "gmp"))]
207impl_int_op_owned!(Rem, rem, %);
208
209#[cfg(not(feature = "gmp"))]
210impl std::ops::Neg for Integer {
211 type Output = Integer;
212 fn neg(self) -> Integer {
213 Integer(-self.0)
214 }
215}
216#[cfg(not(feature = "gmp"))]
217impl std::ops::Neg for &Integer {
218 type Output = Integer;
219 fn neg(self) -> Integer {
220 Integer(-self.0.clone())
221 }
222}
223
224#[cfg(not(feature = "gmp"))]
225impl std::ops::ShrAssign<u32> for Integer {
226 fn shr_assign(&mut self, shift: u32) {
227 self.0 >>= shift;
228 }
229}
230#[cfg(not(feature = "gmp"))]
231impl std::ops::Shr<u32> for Integer {
232 type Output = Integer;
233 fn shr(self, shift: u32) -> Integer {
234 Integer(self.0 >> shift)
235 }
236}
237#[cfg(not(feature = "gmp"))]
238impl std::ops::Shr<u32> for &Integer {
239 type Output = Integer;
240 fn shr(self, shift: u32) -> Integer {
241 Integer(&self.0 >> shift)
242 }
243}
244
245#[cfg(not(feature = "gmp"))]
246impl std::ops::AddAssign<&Integer> for Integer {
247 fn add_assign(&mut self, rhs: &Integer) {
248 self.0 += &rhs.0;
249 }
250}
251#[cfg(not(feature = "gmp"))]
252impl std::ops::SubAssign<&Integer> for Integer {
253 fn sub_assign(&mut self, rhs: &Integer) {
254 self.0 -= &rhs.0;
255 }
256}
257#[cfg(not(feature = "gmp"))]
258impl std::ops::MulAssign<&Integer> for Integer {
259 fn mul_assign(&mut self, rhs: &Integer) {
260 self.0 *= &rhs.0;
261 }
262}
263#[cfg(not(feature = "gmp"))]
264impl std::ops::DivAssign<&Integer> for Integer {
265 fn div_assign(&mut self, rhs: &Integer) {
266 self.0 /= &rhs.0;
267 }
268}
269
270#[cfg(not(feature = "gmp"))]
277impl Integer {
278 pub fn modpow(&self, exp: &Integer, modulus: &Integer) -> Integer {
280 Integer(self.0.modpow(&exp.0, &modulus.0))
281 }
282
283 pub fn mod_floor(&self, modulus: &Integer) -> Integer {
285 use num_integer::Integer as _;
286 Integer(self.0.mod_floor(&modulus.0))
287 }
288
289 pub fn div_rem(&self, other: &Integer) -> (Integer, Integer) {
291 use num_integer::Integer as _;
292 let (q, r) = self.0.div_rem(&other.0);
293 (Integer(q), Integer(r))
294 }
295
296 pub fn is_even(&self) -> bool {
298 use num_integer::Integer as _;
299 self.0.is_even()
300 }
301
302 pub fn is_negative(&self) -> bool {
304 use num_traits::Signed;
305 self.0.is_negative()
306 }
307
308 pub fn is_zero(&self) -> bool {
310 use num_traits::Zero;
311 self.0.is_zero()
312 }
313
314 pub fn is_one(&self) -> bool {
316 use num_traits::One;
317 self.0.is_one()
318 }
319
320 pub fn abs(&self) -> Integer {
322 use num_traits::Signed;
323 Integer(self.0.abs())
324 }
325
326 pub fn sqrt(&self) -> Integer {
328 Integer(self.0.sqrt())
329 }
330}
331
332#[cfg(not(feature = "gmp"))]
333#[cfg(test)]
334mod tests {
335 use super::*;
336
337 #[test]
338 fn integer_addition() {
339 let domain = IntegerDomain;
340 let a = Integer::from(3);
341 let b = Integer::from(5);
342 assert_eq!(domain.add(&a, &b), Integer::from(8));
343 }
344
345 #[test]
346 fn integer_div_exact() {
347 let domain = IntegerDomain;
348 let a = Integer::from(10);
349 let b = Integer::from(3);
350 assert!(domain.div(&a, &b).is_none());
351 let c = Integer::from(2);
352 assert_eq!(domain.div(&a, &c), Some(Integer::from(5)));
353 }
354
355 #[test]
356 fn integer_div_rem() {
357 let domain = IntegerDomain;
358 let a = Integer::from(17);
359 let b = Integer::from(5);
360 let (q, r) = domain.div_rem(&a, &b).unwrap();
361 assert_eq!(q, Integer::from(3));
362 assert_eq!(r, Integer::from(2));
363 }
364}
365
366#[cfg(not(feature = "gmp"))]
367#[cfg(test)]
368mod proptests {
369 use super::*;
370 use proptest::prelude::*;
371
372 fn any_integer() -> impl Strategy<Value = Integer> {
373 any::<i64>().prop_map(Integer::from)
374 }
375
376 proptest! {
377 #[test]
378 fn addition_is_commutative(a in any_integer(), b in any_integer()) {
379 let domain = IntegerDomain;
380 assert_eq!(domain.add(&a, &b), domain.add(&b, &a));
381 }
382
383 #[test]
384 fn multiplication_is_commutative(a in any_integer(), b in any_integer()) {
385 let domain = IntegerDomain;
386 assert_eq!(domain.mul(&a, &b), domain.mul(&b, &a));
387 }
388
389 #[test]
390 fn zero_is_additive_identity(a in any_integer()) {
391 let domain = IntegerDomain;
392 let zero = domain.zero();
393 assert_eq!(domain.add(&a, &zero), a);
394 }
395
396 #[test]
397 fn subtraction_cancels_addition(a in any_integer(), b in any_integer()) {
398 let domain = IntegerDomain;
399 let sum = domain.add(&a, &b);
400 assert_eq!(domain.sub(&sum, &b), a);
401 }
402 }
403}