1use std::fmt::Debug;
2use std::marker::PhantomData;
3
4use feanor_serde::newtype_struct::*;
5use libc;
6use serde::de::DeserializeSeed;
7use serde::ser::SerializeTuple;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10use crate::algorithms::bigint_ops::deserialize_bigint_from_bytes;
11use crate::divisibility::*;
12use crate::homomorphism::*;
13use crate::integer::*;
14use crate::ordered::*;
15use crate::pid::*;
16use crate::primitive_int::*;
17use crate::ring::*;
18use crate::rings::rust_bigint::*;
19use crate::specialization::*;
20use crate::{
21 algorithms, impl_eval_poly_locally_for_ZZ, impl_interpolation_base_ring_char_zero, impl_poly_gcd_locally_for_ZZ,
22};
23
24mod mpir_bindings;
25
26pub struct MPZEl {
28 integer: mpir_bindings::__mpz_struct,
29}
30
31impl MPZEl {
32 fn new() -> Self {
33 unsafe {
34 let mut result = mpir_bindings::UNINIT_MPZ;
35 mpir_bindings::__gmpz_init(&mut result as mpir_bindings::mpz_ptr);
36 return MPZEl { integer: result };
37 }
38 }
39
40 pub fn assign(&mut self, rhs: &MPZEl) {
41 unsafe {
42 mpir_bindings::__gmpz_set(
43 &mut self.integer as mpir_bindings::mpz_ptr,
44 &rhs.integer as mpir_bindings::mpz_srcptr,
45 );
46 }
47 }
48}
49
50impl Clone for MPZEl {
51 fn clone(&self) -> Self { MPZ::RING.clone_el(self) }
52}
53
54unsafe impl Send for MPZEl {}
57unsafe impl Sync for MPZEl {}
60
61impl Drop for MPZEl {
62 fn drop(&mut self) { unsafe { mpir_bindings::__gmpz_clear(&mut self.integer as mpir_bindings::mpz_ptr) } }
63}
64
65impl std::fmt::Debug for MPZEl {
66 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { MPZ::RING.get_ring().dbg(self, f) }
67}
68
69#[derive(Clone, Copy, PartialEq, Eq)]
74pub struct MPZBase;
75
76pub type MPZ = RingValue<MPZBase>;
78
79impl MPZ {
80 pub const RING: MPZ = RingValue::from(MPZBase);
81}
82
83impl MPZBase {
84 pub fn from_le_bytes(&self, dst: &mut MPZEl, input: &[u8]) {
87 unsafe {
88 assert_eq!(
89 std::mem::size_of::<mpir_bindings::mpir_ui>(),
90 std::mem::size_of::<u64>()
91 );
92 if input.len() == 0 {
93 mpir_bindings::__gmpz_set_ui(&mut dst.integer as mpir_bindings::mpz_ptr, 0);
94 return;
95 }
96 assert!(input.len() > 0);
97 mpir_bindings::__gmpz_import(
98 &mut dst.integer as mpir_bindings::mpz_ptr,
99 input.len(),
100 -1i32, 1 as libc::size_t,
102 -1, 0,
104 input.as_ptr() as *const libc::c_void,
105 );
106 }
107 }
108
109 pub fn from_base_u64_repr(&self, dst: &mut MPZEl, input: &[u64]) {
112 unsafe {
113 assert_eq!(
114 std::mem::size_of::<mpir_bindings::mpir_ui>(),
115 std::mem::size_of::<u64>()
116 );
117 if input.len() == 0 {
118 mpir_bindings::__gmpz_set_ui(&mut dst.integer as mpir_bindings::mpz_ptr, 0);
119 return;
120 }
121 assert!(input.len() > 0);
122 mpir_bindings::__gmpz_import(
123 &mut dst.integer as mpir_bindings::mpz_ptr,
124 input.len(),
125 -1i32, (u64::BITS / 8) as libc::size_t,
127 0, 0,
129 input.as_ptr() as *const libc::c_void,
130 );
131 }
132 }
133
134 pub fn abs_base_u64_repr_len(&self, src: &MPZEl) -> usize {
135 self.abs_highest_set_bit(src)
136 .map(|n| (n / u64::BITS as usize) + 1)
137 .unwrap_or(0)
138 }
139
140 pub fn abs_base_u64_repr(&self, src: &MPZEl, out: &mut [u64]) {
142 unsafe {
143 if self.abs_base_u64_repr_len(src) > 0 {
144 assert!(out.len() >= self.abs_base_u64_repr_len(src));
145 let mut size = 0;
146
147 let result_ptr = mpir_bindings::__gmpz_export(
148 out.as_mut_ptr() as *mut libc::c_void,
149 &mut size,
150 -1, (u64::BITS / 8) as libc::size_t,
152 0, 0,
154 &src.integer as mpir_bindings::mpz_srcptr,
155 );
156 assert_eq!(result_ptr as *const libc::c_void, out.as_ptr() as *const libc::c_void);
157 for i in size..out.len() {
158 out[i] = 0;
159 }
160 } else {
161 for i in 0..out.len() {
162 out[i] = 0;
163 }
164 }
165 }
166 }
167
168 pub fn to_le_bytes_len(&self, src: &MPZEl) -> usize {
169 self.abs_highest_set_bit(src)
170 .map(|n| (n / u8::BITS as usize) + 1)
171 .unwrap_or(0)
172 }
173
174 pub fn to_le_bytes(&self, src: &MPZEl, out: &mut [u8]) {
176 unsafe {
177 if self.to_le_bytes_len(src) > 0 {
178 assert!(out.len() >= self.to_le_bytes_len(src));
179 let mut size = 0;
180
181 let result_ptr = mpir_bindings::__gmpz_export(
182 out.as_mut_ptr() as *mut libc::c_void,
183 &mut size,
184 -1, 1 as libc::size_t,
186 -1, 0,
188 &src.integer as mpir_bindings::mpz_srcptr,
189 );
190 assert_eq!(result_ptr as *const libc::c_void, out.as_ptr() as *const libc::c_void);
191 for i in size..out.len() {
192 out[i] = 0;
193 }
194 } else {
195 for i in 0..out.len() {
196 out[i] = 0;
197 }
198 }
199 }
200 }
201}
202
203impl Debug for MPZBase {
204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Z") }
205}
206
207impl RingBase for MPZBase {
208 type Element = MPZEl;
209
210 fn clone_el(&self, val: &Self::Element) -> Self::Element {
211 unsafe {
212 let mut result = MPZEl::new();
213 mpir_bindings::__gmpz_set(
214 &mut result.integer as mpir_bindings::mpz_ptr,
215 &val.integer as mpir_bindings::mpz_srcptr,
216 );
217 return result;
218 }
219 }
220
221 fn mul_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
222 unsafe {
223 let mut result = MPZEl::new();
224 mpir_bindings::__gmpz_mul(
225 &mut result.integer as mpir_bindings::mpz_ptr,
226 &lhs.integer as mpir_bindings::mpz_srcptr,
227 &rhs.integer as mpir_bindings::mpz_srcptr,
228 );
229 return result;
230 }
231 }
232
233 fn negate_inplace(&self, lhs: &mut Self::Element) {
234 unsafe {
235 mpir_bindings::__gmpz_neg(
236 &mut lhs.integer as mpir_bindings::mpz_ptr,
237 &lhs.integer as mpir_bindings::mpz_srcptr,
238 )
239 }
240 }
241
242 fn zero(&self) -> Self::Element { MPZEl::new() }
243
244 fn one(&self) -> Self::Element { self.from_int(1) }
245
246 fn sub_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
247 unsafe {
248 mpir_bindings::__gmpz_sub(
249 &mut rhs.integer as mpir_bindings::mpz_ptr,
250 &lhs.integer as mpir_bindings::mpz_srcptr,
251 &rhs.integer as mpir_bindings::mpz_srcptr,
252 );
253 return rhs;
254 }
255 }
256
257 fn sub_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
258 unsafe {
259 mpir_bindings::__gmpz_sub(
260 &mut lhs.integer as mpir_bindings::mpz_ptr,
261 &lhs.integer as mpir_bindings::mpz_srcptr,
262 &rhs.integer as mpir_bindings::mpz_srcptr,
263 );
264 return lhs;
265 }
266 }
267
268 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { self.add_assign_ref(lhs, &rhs); }
269
270 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
271 unsafe {
272 mpir_bindings::__gmpz_add(
273 &mut lhs.integer as mpir_bindings::mpz_ptr,
274 &lhs.integer as mpir_bindings::mpz_srcptr,
275 &rhs.integer as mpir_bindings::mpz_srcptr,
276 );
277 }
278 }
279
280 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { self.mul_assign_ref(lhs, &rhs) }
281
282 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
283 unsafe {
284 mpir_bindings::__gmpz_mul(
285 &mut lhs.integer as mpir_bindings::mpz_ptr,
286 &lhs.integer as mpir_bindings::mpz_srcptr,
287 &rhs.integer as mpir_bindings::mpz_srcptr,
288 );
289 }
290 }
291
292 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
293 unsafe {
294 mpir_bindings::__gmpz_mul_ui(
295 &mut lhs.integer as mpir_bindings::mpz_ptr,
296 &lhs.integer as mpir_bindings::mpz_srcptr,
297 rhs.abs() as u64,
298 );
299 if rhs < 0 {
300 mpir_bindings::__gmpz_neg(
301 &mut lhs.integer as mpir_bindings::mpz_ptr,
302 &lhs.integer as mpir_bindings::mpz_srcptr,
303 )
304 }
305 }
306 }
307
308 fn sub(&self, lhs: Self::Element, rhs: Self::Element) -> Self::Element { self.sub_ref_snd(lhs, &rhs) }
309
310 fn from_int(&self, value: i32) -> Self::Element {
311 unsafe {
312 let mut result = MPZEl::new();
313 mpir_bindings::__gmpz_set_ui(&mut result.integer as mpir_bindings::mpz_ptr, value.abs() as u64);
314 if value < 0 {
315 return self.negate(result);
316 } else {
317 return result;
318 }
319 }
320 }
321
322 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
323 unsafe {
324 mpir_bindings::__gmpz_cmp(
325 &lhs.integer as mpir_bindings::mpz_srcptr,
326 &rhs.integer as mpir_bindings::mpz_srcptr,
327 ) == 0
328 }
329 }
330
331 fn is_zero(&self, val: &Self::Element) -> bool {
332 unsafe { mpir_bindings::__gmpz_cmp_si(&val.integer as mpir_bindings::mpz_srcptr, 0) == 0 }
333 }
334
335 fn is_one(&self, val: &Self::Element) -> bool {
336 unsafe { mpir_bindings::__gmpz_cmp_si(&val.integer as mpir_bindings::mpz_srcptr, 1) == 0 }
337 }
338
339 fn is_neg_one(&self, val: &Self::Element) -> bool {
340 unsafe { mpir_bindings::__gmpz_cmp_si(&val.integer as mpir_bindings::mpz_srcptr, -1) == 0 }
341 }
342
343 fn is_noetherian(&self) -> bool { true }
344
345 fn is_commutative(&self) -> bool { true }
346
347 fn is_approximate(&self) -> bool { false }
348
349 fn dbg_within<'a>(
350 &self,
351 value: &Self::Element,
352 out: &mut std::fmt::Formatter<'a>,
353 _env: EnvBindingStrength,
354 ) -> std::fmt::Result {
355 RustBigintRing::RING.get_ring().dbg(
356 &self.map_out(RustBigintRing::RING.get_ring(), self.clone_el(value), &()),
357 out,
358 )
359 }
360
361 fn characteristic<I: IntegerRingStore + Copy>(&self, other_ZZ: I) -> Option<El<I>>
362 where
363 I::Type: IntegerRing,
364 {
365 Some(other_ZZ.zero())
366 }
367}
368
369impl OrderedRing for MPZBase {
370 fn cmp(&self, lhs: &Self::Element, rhs: &Self::Element) -> std::cmp::Ordering {
371 unsafe {
372 let res = mpir_bindings::__gmpz_cmp(
373 &lhs.integer as mpir_bindings::mpz_srcptr,
374 &rhs.integer as mpir_bindings::mpz_srcptr,
375 );
376 if res < 0 {
377 return std::cmp::Ordering::Less;
378 } else if res > 0 {
379 return std::cmp::Ordering::Greater;
380 } else {
381 return std::cmp::Ordering::Equal;
382 }
383 }
384 }
385
386 fn is_neg(&self, value: &Self::Element) -> bool {
387 unsafe { mpir_bindings::mpz_is_neg(&value.integer as mpir_bindings::mpz_srcptr) }
388 }
389}
390
391impl Serialize for MPZBase {
392 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
393 where
394 S: Serializer,
395 {
396 SerializableNewtypeStruct::new("IntegerRing(MPZ)", ()).serialize(serializer)
397 }
398}
399
400impl<'de> Deserialize<'de> for MPZBase {
401 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
402 where
403 D: Deserializer<'de>,
404 {
405 DeserializeSeedNewtypeStruct::new("IntegerRing(MPZ)", PhantomData::<()>)
406 .deserialize(deserializer)
407 .map(|()| MPZ::RING.into())
408 }
409}
410
411impl SerializableElementRing for MPZBase {
412 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
413 where
414 D: Deserializer<'de>,
415 {
416 if deserializer.is_human_readable() {
417 return DeserializeWithRing::new(RustBigintRing::RING)
418 .deserialize(deserializer)
419 .map(|n| int_cast(n, RingRef::new(self), RustBigintRing::RING));
420 } else {
421 let (negative, mut result) = deserialize_bigint_from_bytes(deserializer, |data| {
422 let mut result = self.zero();
423 self.from_le_bytes(&mut result, data);
424 return result;
425 })?;
426 if negative {
427 self.negate_inplace(&mut result);
428 }
429 return Ok(result);
430 }
431 }
432
433 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
434 where
435 S: Serializer,
436 {
437 if serializer.is_human_readable() {
438 SerializableNewtypeStruct::new("BigInt", format!("{}", RingRef::new(self).format(el)).as_str())
439 .serialize(serializer)
440 } else {
441 let len = self.to_le_bytes_len(el);
442 let mut data = Vec::with_capacity(len);
443 data.resize(len, 0u8);
444 self.to_le_bytes(el, &mut data);
445 let mut seq = serializer.serialize_tuple(2)?;
446 seq.serialize_element(&self.is_neg(el))?;
447 seq.serialize_element(serde_bytes::Bytes::new(&data[..]))?;
448 return seq.end();
449 }
450 }
451}
452
453impl DivisibilityRing for MPZBase {
454 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
455 if self.is_zero(rhs) {
456 if self.is_zero(lhs) {
457 return Some(self.zero());
458 } else {
459 return None;
460 }
461 }
462 let (quo, rem) = self.euclidean_div_rem(self.clone_el(lhs), rhs);
463 if self.is_zero(&rem) {
464 return Some(quo);
465 } else {
466 return None;
467 }
468 }
469
470 fn balance_factor<'a, I>(&self, elements: I) -> Option<Self::Element>
471 where
472 I: Iterator<Item = &'a Self::Element>,
473 Self: 'a,
474 {
475 Some(elements.fold(self.zero(), |a, b| self.ideal_gen(&a, b)))
476 }
477}
478
479impl PrincipalIdealRing for MPZBase {
480 fn extended_ideal_gen(
481 &self,
482 lhs: &Self::Element,
483 rhs: &Self::Element,
484 ) -> (Self::Element, Self::Element, Self::Element) {
485 algorithms::eea::eea(self.clone_el(lhs), self.clone_el(rhs), MPZ::RING)
486 }
487
488 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
489 if self.is_zero(lhs) && self.is_zero(rhs) {
490 return Some(self.one());
491 }
492 self.checked_left_div(lhs, rhs)
493 }
494}
495
496impl EuclideanRing for MPZBase {
497 fn euclidean_div_rem(&self, mut lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
498 unsafe {
499 assert!(!self.is_zero(rhs));
500 let mut quo = MPZEl::new();
501 mpir_bindings::__gmpz_tdiv_qr(
502 &mut quo.integer as mpir_bindings::mpz_ptr,
503 &mut lhs.integer as mpir_bindings::mpz_ptr,
504 &lhs.integer as mpir_bindings::mpz_srcptr,
505 &rhs.integer as mpir_bindings::mpz_srcptr,
506 );
507 return (quo, lhs);
508 }
509 }
510
511 fn euclidean_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
512 unsafe {
513 assert!(!self.is_zero(rhs));
514 let mut rem = MPZEl::new();
515 mpir_bindings::__gmpz_tdiv_r(
516 &mut rem.integer as mpir_bindings::mpz_ptr,
517 &lhs.integer as mpir_bindings::mpz_srcptr,
518 &rhs.integer as mpir_bindings::mpz_srcptr,
519 );
520 return rem;
521 }
522 }
523
524 fn euclidean_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
525 unsafe {
526 assert!(!self.is_zero(rhs));
527 let mut rem = MPZEl::new();
528 mpir_bindings::__gmpz_tdiv_q(
529 &mut rem.integer as mpir_bindings::mpz_ptr,
530 &lhs.integer as mpir_bindings::mpz_srcptr,
531 &rhs.integer as mpir_bindings::mpz_srcptr,
532 );
533 return rem;
534 }
535 }
536
537 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
538 if self.abs_highest_set_bit(val).unwrap_or(0) < usize::BITS as usize {
539 unsafe {
540 mpir_bindings::__gmpz_get_ui(&val.integer as mpir_bindings::mpz_srcptr)
541 .try_into()
542 .ok()
543 }
544 } else {
545 None
546 }
547 }
548}
549
550impl Default for MPZBase {
551 fn default() -> Self { MPZ::RING.into() }
552}
553
554impl Domain for MPZBase {}
555
556impl IntegerRing for MPZBase {
557 fn to_float_approx(&self, el: &Self::Element) -> f64 {
558 unsafe { mpir_bindings::__gmpz_get_d(&el.integer as mpir_bindings::mpz_srcptr) }
559 }
560
561 fn from_float_approx(&self, el: f64) -> Option<Self::Element> {
562 unsafe {
563 let mut result = MPZEl::new();
564 mpir_bindings::__gmpz_set_d(&mut result.integer as mpir_bindings::mpz_ptr, el);
565 return Some(result);
566 }
567 }
568
569 fn mul_pow_2(&self, el: &mut Self::Element, power: usize) {
570 unsafe {
571 mpir_bindings::__gmpz_mul_2exp(
572 &mut el.integer as mpir_bindings::mpz_ptr,
573 &el.integer as mpir_bindings::mpz_srcptr,
574 power as u64,
575 )
576 }
577 }
578
579 fn euclidean_div_pow_2(&self, el: &mut Self::Element, power: usize) {
580 unsafe {
581 mpir_bindings::__gmpz_tdiv_q_2exp(
582 &mut el.integer as mpir_bindings::mpz_ptr,
583 &el.integer as mpir_bindings::mpz_srcptr,
584 power as u64,
585 )
586 }
587 }
588
589 fn abs_is_bit_set(&self, el: &Self::Element, bit: usize) -> bool {
590 unsafe {
591 if mpir_bindings::mpz_is_neg(&el.integer as mpir_bindings::mpz_srcptr) {
592 let value = mpir_bindings::__gmpz_tstbit(&el.integer as mpir_bindings::mpz_srcptr, bit as u64) == 1;
593 let least_significant_zero = mpir_bindings::__gmpz_scan1(&el.integer as mpir_bindings::mpz_srcptr, 0);
594 if bit <= least_significant_zero as usize {
595 value
596 } else {
597 !value
598 }
599 } else {
600 mpir_bindings::__gmpz_tstbit(&el.integer as mpir_bindings::mpz_srcptr, bit as u64) == 1
601 }
602 }
603 }
604
605 fn abs_highest_set_bit(&self, value: &Self::Element) -> Option<usize> {
606 unsafe {
607 if self.is_zero(value) {
608 return None;
609 }
610 Some(mpir_bindings::__gmpz_sizeinbase(&value.integer as mpir_bindings::mpz_srcptr, 2) - 1)
611 }
612 }
613
614 fn abs_lowest_set_bit(&self, value: &Self::Element) -> Option<usize> {
615 unsafe {
616 let result = mpir_bindings::__gmpz_scan1(&value.integer as mpir_bindings::mpz_srcptr, 0);
617 if result == mpir_bindings::mpir_ui::MAX {
618 return None;
619 } else {
620 return Some(result as usize);
621 }
622 }
623 }
624
625 fn rounded_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
626 let mut rhs_half = self.abs(self.clone_el(rhs));
627 self.euclidean_div_pow_2(&mut rhs_half, 1);
628 if self.is_neg(&lhs) {
629 return self.euclidean_div(self.sub(lhs, rhs_half), rhs);
630 } else {
631 return self.euclidean_div(self.add(lhs, rhs_half), rhs);
632 }
633 }
634
635 fn get_uniformly_random_bits<G: FnMut() -> u64>(&self, log2_bound_exclusive: usize, rng: G) -> Self::Element {
636 unsafe {
637 let mut result = MPZEl::new();
638 let len = (log2_bound_exclusive - 1) / u64::BITS as usize + 1;
639 let mut data = Vec::new();
640 data.resize_with(len, rng);
641
642 mpir_bindings::__gmpz_import(
643 &mut result.integer as mpir_bindings::mpz_ptr,
644 data.len(),
645 -1i32,
646 (u64::BITS / 8) as libc::size_t,
647 0,
648 0,
649 (data.as_ptr() as *const mpir_bindings::mpir_ui) as *const libc::c_void,
650 );
651
652 self.euclidean_div_pow_2(&mut result, len * u64::BITS as usize - log2_bound_exclusive);
653 return result;
654 }
655 }
656
657 fn representable_bits(&self) -> Option<usize> { None }
658}
659
660impl_interpolation_base_ring_char_zero! { InterpolationBaseRing for MPZBase }
661
662impl_poly_gcd_locally_for_ZZ! { IntegerPolyGCDRing for MPZBase }
663
664impl_eval_poly_locally_for_ZZ! { EvalPolyLocallyRing for MPZBase }
665
666impl FiniteRingSpecializable for MPZBase {
667 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output { op.fallback() }
668}
669
670impl HashableElRing for MPZBase {
671 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
672 unsafe {
673 <_ as std::hash::Hash>::hash(
674 &(
675 self.is_neg(&el),
676 self.abs_highest_set_bit(&el),
677 mpir_bindings::__gmpz_get_ui(&el.integer as mpir_bindings::mpz_srcptr),
678 ),
679 h,
680 )
681 }
682 }
683}
684
685impl IntCast<RustBigintRingBase> for MPZBase {
686 fn cast(&self, _: &RustBigintRingBase, el: RustBigint) -> Self::Element {
687 let mut result = MPZEl::new();
688 self.from_base_u64_repr(
689 &mut result,
690 &RustBigintRing::RING
691 .get_ring()
692 .abs_base_u64_repr(&el)
693 .collect::<Vec<_>>()[..],
694 );
695 if RustBigintRing::RING.is_neg(&el) {
696 self.negate_inplace(&mut result);
697 }
698 return result;
699 }
700}
701
702impl IntCast<MPZBase> for RustBigintRingBase {
703 fn cast(&self, from: &MPZBase, el: MPZEl) -> RustBigint {
704 let mut result = (0..from.abs_base_u64_repr_len(&el)).map(|_| 0u64).collect::<Vec<_>>();
705 from.abs_base_u64_repr(&el, &mut result[..]);
706 let result = RustBigintRing::RING.get_ring().from_base_u64_repr(result.into_iter());
707 if from.is_neg(&el) {
708 return RustBigintRing::RING.negate(result);
709 } else {
710 return result;
711 }
712 }
713}
714
715impl IntCast<MPZBase> for MPZBase {
716 fn cast(&self, _from: &MPZBase, el: MPZEl) -> MPZEl { el }
717}
718
719impl IntCast<StaticRingBase<i64>> for MPZBase {
720 fn cast(&self, _: &StaticRingBase<i64>, el: i64) -> Self::Element {
721 unsafe {
722 let mut result = MPZEl::new();
723 mpir_bindings::__gmpz_set_si(&mut result.integer as *mut _, el);
724 return result;
725 }
726 }
727}
728
729impl IntCast<MPZBase> for StaticRingBase<i64> {
730 fn cast(&self, from: &MPZBase, el: MPZEl) -> i64 {
731 assert!(from.abs_highest_set_bit(&el).unwrap_or(0) < u64::BITS as usize);
732 let negative = from.is_neg(&el);
733 unsafe {
734 let result = mpir_bindings::__gmpz_get_ui(&el.integer as mpir_bindings::mpz_srcptr);
735 if !negative {
736 result.try_into().unwrap()
737 } else if result == i64::MAX as u64 + 1 {
738 i64::MIN
739 } else {
740 -i64::try_from(result).unwrap()
741 }
742 }
743 }
744}
745
746impl IntCast<StaticRingBase<i128>> for MPZBase {
747 fn cast(&self, _: &StaticRingBase<i128>, el: i128) -> MPZEl {
748 let el_abs = el.unsigned_abs();
749 let data = [(el_abs & u64::MAX as u128) as u64, (el_abs >> u64::BITS) as u64];
750 let mut result = MPZEl::new();
751 self.from_base_u64_repr(&mut result, &data[..]);
752 if el < 0 {
753 self.negate_inplace(&mut result);
754 }
755 return result;
756 }
757}
758
759impl IntCast<MPZBase> for StaticRingBase<i128> {
760 fn cast(&self, from: &MPZBase, el: MPZEl) -> i128 {
761 assert!(from.abs_base_u64_repr_len(&el) <= 2);
762 let mut data = [0u64; 2];
763 from.abs_base_u64_repr(&el, &mut data);
764 let result = data[0] as u128 + ((data[1] as u128) << u64::BITS);
765 if from.is_neg(&el) {
766 if result == i128::MIN.unsigned_abs() {
767 return i128::MIN;
768 } else {
769 return -i128::try_from(result).unwrap();
770 }
771 } else {
772 return result.try_into().unwrap();
773 }
774 }
775}
776
777macro_rules! specialize_int_cast {
778 ($($from:ty),*) => {
779 $(
780 impl IntCast<StaticRingBase<$from>> for MPZBase {
781
782 fn cast(&self, _: &StaticRingBase<$from>, el: $from) -> MPZEl {
783 int_cast(el.try_into().unwrap(), &RingRef::new(self), StaticRing::<i64>::RING)
784 }
785 }
786
787 impl IntCast<MPZBase> for StaticRingBase<$from> {
788
789 fn cast(&self, _: &MPZBase, el: MPZEl) -> $from {
790 int_cast(el, &StaticRing::<i64>::RING, &MPZ::RING) as $from
791 }
792 }
793 )*
794 }
795}
796
797specialize_int_cast! { i8, i16, i32 }
798
799#[cfg(test)]
800use crate::pid::EuclideanRingStore;
801use crate::serialization::{DeserializeWithRing, SerializableElementRing};
802
803#[cfg(test)]
804fn edge_case_elements_bigint() -> impl Iterator<Item = RustBigint> {
805 [
806 RustBigintRing::RING.int_hom().map(0),
807 RustBigintRing::RING.int_hom().map(1),
808 RustBigintRing::RING.int_hom().map(-1),
809 RustBigintRing::RING.int_hom().map(7),
810 RustBigintRing::RING.int_hom().map(-7),
811 RustBigintRing::RING.int_hom().map(i32::MAX),
812 RustBigintRing::RING.int_hom().map(i32::MIN),
813 RustBigintRing::RING.power_of_two(64),
814 RustBigintRing::RING.negate(RustBigintRing::RING.power_of_two(64)),
815 RustBigintRing::RING.sub(RustBigintRing::RING.power_of_two(64), RustBigintRing::RING.one()),
816 RustBigintRing::RING.power_of_two(128),
817 RustBigintRing::RING.negate(RustBigintRing::RING.power_of_two(128)),
818 RustBigintRing::RING.sub(RustBigintRing::RING.power_of_two(128), RustBigintRing::RING.one()),
819 RustBigintRing::RING.power_of_two(192),
820 RustBigintRing::RING.negate(RustBigintRing::RING.power_of_two(192)),
821 RustBigintRing::RING.sub(RustBigintRing::RING.power_of_two(192), RustBigintRing::RING.one()),
822 ]
823 .into_iter()
824}
825
826#[cfg(test)]
827fn edge_case_elements() -> impl Iterator<Item = MPZEl> {
828 edge_case_elements_bigint().map(|n| MPZ::RING.coerce(&RustBigintRing::RING, n))
829}
830
831#[test]
832fn test_negate_inplace() {
833 let mut a = MPZ::RING.power_of_two(64);
834 MPZ::RING.negate_inplace(&mut a);
835 assert!(MPZ::RING.is_neg(&a));
836
837 for a in edge_case_elements() {
838 let mut b = MPZ::RING.clone_el(&a);
839 MPZ::RING.negate_inplace(&mut b);
840 assert!(MPZ::RING.is_zero(&a) || (MPZ::RING.is_neg(&a) ^ MPZ::RING.is_neg(&b)));
841 }
842}
843
844#[test]
845fn test_ring_axioms() { crate::ring::generic_tests::test_ring_axioms(MPZ::RING, edge_case_elements()) }
846
847#[test]
848fn test_hash_axioms() { crate::ring::generic_tests::test_hash_axioms(MPZ::RING, edge_case_elements()); }
849
850#[test]
851fn test_divisibility_ring_axioms() {
852 crate::divisibility::generic_tests::test_divisibility_axioms(MPZ::RING, edge_case_elements())
853}
854
855#[test]
856fn test_euclidean_ring_axioms() {
857 crate::pid::generic_tests::test_euclidean_ring_axioms(MPZ::RING, edge_case_elements())
858}
859
860#[test]
861fn test_integer_ring_axioms() { crate::integer::generic_tests::test_integer_axioms(MPZ::RING, edge_case_elements()) }
862
863#[test]
864fn test_canonical_iso_axioms_i32() {
865 crate::ring::generic_tests::test_hom_axioms(
866 StaticRing::<i32>::RING,
867 MPZ::RING,
868 [0, -1, 1, i16::MAX as i32, i16::MIN as i32].into_iter(),
869 );
870 crate::ring::generic_tests::test_iso_axioms(
871 StaticRing::<i32>::RING,
872 MPZ::RING,
873 [0, -1, 1, i16::MIN as i32, i16::MAX as i32].into_iter(),
874 );
875}
876
877#[test]
878fn test_canonical_iso_axioms_i64() {
879 crate::ring::generic_tests::test_hom_axioms(
880 StaticRing::<i64>::RING,
881 MPZ::RING,
882 [0, -1, 1, i32::MAX as i64, i32::MIN as i64].into_iter(),
883 );
884 crate::ring::generic_tests::test_iso_axioms(
885 StaticRing::<i64>::RING,
886 MPZ::RING,
887 [0, -1, 1, i32::MIN as i64, i32::MAX as i64].into_iter(),
888 );
889
890 assert_el_eq!(
891 MPZ::RING,
892 MPZ::RING.sub(MPZ::RING.power_of_two(63), MPZ::RING.one()),
893 &MPZ::RING.coerce(&StaticRing::<i64>::RING, i64::MAX)
894 );
895 assert_el_eq!(
896 MPZ::RING,
897 MPZ::RING.negate(MPZ::RING.power_of_two(63)),
898 MPZ::RING.coerce(&StaticRing::<i64>::RING, i64::MIN)
899 );
900 assert_eq!(
901 i64::MAX,
902 int_cast(
903 MPZ::RING.sub(MPZ::RING.power_of_two(63), MPZ::RING.one()),
904 &StaticRing::<i64>::RING,
905 MPZ::RING
906 )
907 );
908 assert_eq!(
909 i64::MIN,
910 int_cast(
911 MPZ::RING.negate(MPZ::RING.power_of_two(63)),
912 &StaticRing::<i64>::RING,
913 MPZ::RING
914 )
915 );
916}
917
918#[test]
919fn test_canonical_iso_axioms_i128() {
920 crate::ring::generic_tests::test_hom_axioms(
921 StaticRing::<i128>::RING,
922 MPZ::RING,
923 [0, -1, 1, i64::MAX as i128, i64::MIN as i128].into_iter(),
924 );
925 crate::ring::generic_tests::test_iso_axioms(
926 StaticRing::<i128>::RING,
927 MPZ::RING,
928 [0, -1, 1, i64::MIN as i128, i64::MAX as i128].into_iter(),
929 );
930
931 assert_el_eq!(
932 MPZ::RING,
933 MPZ::RING.sub(MPZ::RING.power_of_two(127), MPZ::RING.one()),
934 &MPZ::RING.coerce(&StaticRing::<i128>::RING, i128::MAX)
935 );
936 assert_el_eq!(
937 MPZ::RING,
938 MPZ::RING.negate(MPZ::RING.power_of_two(127)),
939 MPZ::RING.coerce(&StaticRing::<i128>::RING, i128::MIN)
940 );
941 assert_eq!(
942 i128::MAX,
943 int_cast(
944 MPZ::RING.sub(MPZ::RING.power_of_two(127), MPZ::RING.one()),
945 &StaticRing::<i128>::RING,
946 MPZ::RING
947 )
948 );
949 assert_eq!(
950 i128::MIN,
951 int_cast(
952 MPZ::RING.negate(MPZ::RING.power_of_two(127)),
953 &StaticRing::<i128>::RING,
954 MPZ::RING
955 )
956 );
957}
958
959#[test]
960fn test_canonical_iso_axioms_bigint() {
961 crate::ring::generic_tests::test_hom_axioms(RustBigintRing::RING, MPZ::RING, edge_case_elements_bigint());
962 crate::ring::generic_tests::test_iso_axioms(RustBigintRing::RING, MPZ::RING, edge_case_elements_bigint());
963}
964
965#[test]
966fn test_abs_is_bit_set() {
967 let a = MPZ::RING.int_hom().map(1 << 15);
968 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 15));
969 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 16));
970 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 14));
971
972 let a = MPZ::RING.int_hom().map(-7);
973 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 0));
974 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 1));
975 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 2));
976 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 3));
977
978 let a = MPZ::RING.int_hom().map(-1 << 15);
979 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 15));
980 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 16));
981 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 14));
982}
983
984#[test]
985fn test_highest_set_bit() {
986 assert_eq!(None, MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(0)));
987 assert_eq!(Some(0), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(1)));
988 assert_eq!(Some(0), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-1)));
989 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(2)));
990 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-2)));
991 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(3)));
992 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-3)));
993 assert_eq!(Some(2), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(4)));
994 assert_eq!(Some(2), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-4)));
995}
996
997#[test]
998fn test_lowest_set_bit() {
999 assert_eq!(None, MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(0)));
1000 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(1)));
1001 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-1)));
1002 assert_eq!(Some(1), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(2)));
1003 assert_eq!(Some(1), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-2)));
1004 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(3)));
1005 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-3)));
1006 assert_eq!(Some(2), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(4)));
1007 assert_eq!(Some(2), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-4)));
1008}
1009
1010#[test]
1011fn from_to_float_approx() {
1012 let x: f64 = 83465209236517892563478156042389675783219532497861237985328563.0;
1013 let y = MPZ::RING.to_float_approx(&MPZ::RING.from_float_approx(x).unwrap());
1014 assert!(x * 0.99 < y);
1015 assert!(y < x * 1.01);
1016}
1017
1018#[bench]
1019fn bench_mul_300_bits(bencher: &mut test::Bencher) {
1020 let x = MPZ::RING.coerce(
1021 &RustBigintRing::RING,
1022 RustBigintRing::RING
1023 .get_ring()
1024 .parse(
1025 "2382385687561872365981723456981723456987134659834659813491964132897159283746918732563498628754",
1026 10,
1027 )
1028 .unwrap(),
1029 );
1030 let y = MPZ::RING.coerce(
1031 &RustBigintRing::RING,
1032 RustBigintRing::RING
1033 .get_ring()
1034 .parse("48937502893645789234569182735646324895723409587234", 10)
1035 .unwrap(),
1036 );
1037 let z = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("116588006478839442056346504147013274749794691549803163727888681858469844569693215953808606899770104590589390919543097259495176008551856143726436", 10).unwrap());
1038 bencher.iter(|| {
1039 let p = MPZ::RING.mul_ref(&x, &y);
1040 assert_el_eq!(MPZ::RING, z, p);
1041 })
1042}
1043
1044#[bench]
1045fn bench_div_300_bits(bencher: &mut test::Bencher) {
1046 let x = MPZ::RING.coerce(
1047 &RustBigintRing::RING,
1048 RustBigintRing::RING
1049 .get_ring()
1050 .parse(
1051 "2382385687561872365981723456981723456987134659834659813491964132897159283746918732563498628754",
1052 10,
1053 )
1054 .unwrap(),
1055 );
1056 let y = MPZ::RING.coerce(
1057 &RustBigintRing::RING,
1058 RustBigintRing::RING
1059 .get_ring()
1060 .parse("48937502893645789234569182735646324895723409587234", 10)
1061 .unwrap(),
1062 );
1063 let z = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("116588006478839442056346504147013274749794691549803163727888681858469844569693215953808606899770104590589390919543097259495176008551856143726436", 10).unwrap());
1064 bencher.iter(|| {
1065 let q = MPZ::RING.euclidean_div(MPZ::RING.clone_el(&z), &y);
1066 assert_el_eq!(MPZ::RING, x, q);
1067 })
1068}
1069
1070#[test]
1071fn test_serialization() { crate::serialization::generic_tests::test_serialization(MPZ::RING, edge_case_elements()); }