devela 0.28.0

A development substrate of coherence.
Documentation
// devela::num::dom::int::wrapper::impl_factors_alloc
//
//! Implements factors-related allocating methods for [`Int`].
//
// TOC
// - signed|unsigned:
//   - allocating:
//     - factors
//     - factors_proper
//     - factors_prime
//     - factors_prime_unique
//     - factors_prime_unique_exp

use crate::{BTreeSet, Hook, Int, Vec, is, paste, vec_ as vec};

/// Implements factors-related methods for [`Int`].
///
/// # Args.
/// $t:   the input/output type
///
/// $d:   the doclink suffix for the method name
macro_rules! __impl_int_factors_alloc {
    () => {
        __impl_int_factors_alloc![signed
            i8    |"",
            i16   |"-1",
            i32   |"-2",
            i64   |"-3",
            i128  |"-4",
            isize |"-5"
        ];
        __impl_int_factors_alloc![unsigned
            u8    |"-6",
            u16   |"-7",
            u32   |"-8",
            u64   |"-9",
            u128  |"-10",
            usize |"-11"
        ];
    };
    (signed $( $t:ty | $d:literal ),+) => {
        $( __impl_int_factors_alloc![@signed $t|$d]; )+
    };
    (unsigned $( $t:ty | $d:literal ),+) => {
        $( __impl_int_factors_alloc![@unsigned $t|$d]; )+
    };
    (
    // implements signed ops
    @signed $t:ty | $d:literal) => { paste! {
        ///
        #[doc = "# Integer factors related methods for `" $t "`\n\n"]
        #[doc = "   - [factors](#method.factors" $d ")"]
        #[doc = "   - [factors_proper](#method.factors_proper" $d ")"]
        #[doc = "   - [factors_prime](#method.factors_prime" $d ")"]
        #[doc = "   - [factors_prime_unique](#method.factors_prime_unique" $d ")"]
        ///
        impl Int<$t> {
            /* signed factors alloc */

            /// Returns the factors (including 1 and self).
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t
                ").factors(), vec![1, 2, 3, 4, 6, 8, 12, 24]];"]
            #[doc = "assert_eq![Int(-24_" $t
                ").factors(), vec![1, 2, 3, 4, 6, 8, 12, 24]];"]
            #[doc = "assert![Int(0_" $t ").factors().is_empty()];"]
            #[doc = "assert_eq![Int(1_" $t ").factors(), vec![1]];"]
            #[doc = "assert_eq![Int(7_" $t ").factors(), vec![1, 7]];"]
            /// ```
            #[must_use]
            pub fn factors(self) -> Vec<$t> {
                let n = self.0.abs();
                is![n == 0, return vec![],
                    is![n == 1, return vec![1]]];
                let mut set = BTreeSet::new();
                set.insert(1);
                for p in self.factors_prime_unique() {
                    let temp = set.clone();
                    let mut x = p;
                    while x <= n {
                        for &num in &temp {
                            let new_num = num * x;
                            is!{n % new_num == 0, {set.insert(new_num);} }
                        }
                        x *= p;
                    }
                }
                set.into_iter().collect()
            }

            /// Returns the proper factors.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t
                ").factors_proper(), vec![2, 3, 4, 6, 8, 12]];"]
            #[doc = "assert_eq![Int(-24_" $t
                ").factors_proper(), vec![2, 3, 4, 6, 8, 12]];"]
            #[doc = "assert![Int(0_" $t ").factors_proper().is_empty()];"]
            #[doc = "assert![Int(1_" $t ").factors_proper().is_empty()];"]

            #[doc = "assert![Int(7_" $t ").factors_proper().is_empty()];"]
            /// ```
            #[must_use]
            pub fn factors_proper(self) -> Vec<$t> {
                let n = self.0.abs();
                is![n == 0, return vec![]];
                let mut set = BTreeSet::new();
                set.insert(1);
                for p in self.factors_prime_unique() {
                    let temp = set.clone();
                    let mut x = p;
                    while x <= n {
                        for &num in &temp {
                            let new_num = num * x;
                            if n % new_num == 0 { set.insert(new_num); }
                        }
                        x *= p;
                    }
                }
                set.remove(&1);
                set.remove(&n);
                set.into_iter().collect()
            }

            /// Returns the prime factors.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t ").factors_prime(), vec![2, 2, 2, 3]];"]
            #[doc = "assert_eq![Int(-24_" $t ").factors_prime(), vec![2, 2, 2, 3]];"]
            #[doc = "assert![Int(0_" $t ").factors_prime().is_empty()];"]
            #[doc = "assert![Int(1_" $t ").factors_prime().is_empty()];"]
            #[doc = "assert_eq![Int(7_" $t ").factors_prime(), vec![7]];"]
            /// ```
            #[must_use]
            pub fn factors_prime(self) -> Vec<$t> {
                let mut factors = Vec::new();
                let mut n = self.0.abs();
                is![n == 0, return factors];

                // Divide by 2 until the number is odd
                while n % 2 == 0 {
                    factors.push(2);
                    n /= 2;
                }
                // Divide by odd numbers starting from 3
                let mut i = 3;
                while i * i <= n {
                    while n % i == 0 {
                        factors.push(i);
                        n /= i;
                    }
                    i += 2;
                }
                // If the remaining number is greater than 2, it's a prime factor
                is![n > 2, factors.push(n)];
                factors
            }

            /// Returns the unique prime factors.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t ").factors_prime_unique(), vec![2, 3]];"]
            #[doc = "assert_eq![Int(-24_" $t ").factors_prime_unique(), vec![2, 3]];"]
            /// ```
            #[must_use]
            pub fn factors_prime_unique(self) -> Vec<$t> {
                self.factors_prime().hook(|v| v.dedup())
            }

            /// Returns the unique prime factors with its exponent.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
                #[doc = "assert_eq![Int(24_" $t
            ").factors_prime_unique_exp(), vec![(2, 3), (3, 1)]];"]
            #[doc = "assert_eq![Int(-24_" $t
                ").factors_prime_unique_exp(), vec![(2, 3), (3, 1)]];"]
            #[doc = "assert![Int(0_" $t ").factors_prime_unique_exp().is_empty()];"]
            #[doc = "assert![Int(1_" $t ").factors_prime_unique_exp().is_empty()];"]
            #[doc = "assert_eq![Int(7_" $t ").factors_prime_unique_exp(), vec![(7, 1)]];"]
            /// ```
            #[must_use]
            pub fn factors_prime_unique_exp(self) -> Vec<($t, u32)> {
                let mut factors = Vec::new();
                let mut current = None;
                let mut count = 0;

                for prime in self.factors_prime() {
                    match current {
                        Some(f) if f == prime => count += 1,
                        _ => {
                            is![let Some(f) = current, factors.push((f, count))];
                            current = Some(prime);
                            count = 1;
                        },
                    }
                }
                if let Some(f) = current { factors.push((f, count)); }
                factors
            }
        }
    }};
    (
    // implements unsigned ops
    @unsigned $t:ty | $d:literal) => { paste! {
        ///
        #[doc = "# Integer factors related methods for `" $t "`\n\n"]
        #[doc = "   - [factors](#method.factors" $d ")"]
        #[doc = "   - [factors_proper](#method.factors_proper" $d ")"]
        #[doc = "   - [factors_prime](#method.factors_prime" $d ")"]
        #[doc = "   - [factors_prime_unique](#method.factors_prime_unique" $d ")"]
        ///
        impl Int<$t> {
            /* unsigned factors alloc */

            /// Returns the factors (including 1 and self).
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t
                ").factors(), vec![1, 2, 3, 4, 6, 8, 12, 24]];"]
            #[doc = "assert![Int(0_" $t ").factors().is_empty()];"]
            #[doc = "assert_eq![Int(1_" $t ").factors(), vec![1]];"]
            #[doc = "assert_eq![Int(7_" $t ").factors(), vec![1, 7]];"]
            /// ```
            #[must_use]
            pub fn factors(self) -> Vec<$t> {
                let n = self.0;
                is![n == 0, return vec![], is![n == 1, return vec![1]]];
                let mut set = BTreeSet::new();
                set.insert(1);
                for p in self.factors_prime_unique() {
                    let temp = set.clone();
                    let mut x = p;
                    while x <= n {
                        for &num in &temp {
                            let new_num = num * x;
                            if n % new_num == 0 { set.insert(new_num); }
                        }
                        x *= p;
                    }
                }
                set.into_iter().collect()
            }

            /// Returns the proper factors.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t
                ").factors_proper(), vec![2, 3, 4, 6, 8, 12]];"]
            #[doc = "assert![Int(0_" $t ").factors_proper().is_empty()];"]
            #[doc = "assert![Int(1_" $t ").factors_proper().is_empty()];"]
            #[doc = "assert![Int(7_" $t ").factors_proper().is_empty()];"]
            /// ```
            #[must_use]
            pub fn factors_proper(self) -> Vec<$t> {
                let n = self.0;
                is![n == 0, return vec![]];
                let mut set = BTreeSet::new();
                set.insert(1);
                for p in self.factors_prime_unique() {
                    let temp = set.clone();
                    let mut x = p;
                    while x <= n {
                        for &num in &temp {
                            let new_num = num * x;
                            if n % new_num == 0 { set.insert(new_num); }
                        }
                        x *= p;
                    }
                }
                set.remove(&1);
                set.remove(&n);
                set.into_iter().collect()
            }

            /// Returns the prime factors.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t ").factors_prime(), vec![2, 2, 2, 3]];"]
            #[doc = "assert![Int(0_" $t ").factors_prime().is_empty()];"]
            #[doc = "assert![Int(1_" $t ").factors_prime().is_empty()];"]
            #[doc = "assert_eq![Int(7_" $t ").factors_prime(), vec![7]];"]
            /// ```
            #[must_use]
            pub fn factors_prime(self) -> Vec<$t> {
                let mut factors = Vec::new();
                let mut n = self.0;
                is![n == 0, return factors];

                // Divide by 2 until the number is odd
                while n % 2 == 0 {
                    factors.push(2);
                    n /= 2;
                }
                // Divide by odd numbers starting from 3
                let mut i = 3;
                while i * i <= n {
                    while n % i == 0 {
                        factors.push(i);
                        n /= i;
                    }
                    i += 2;
                }
                // If the remaining number is greater than 2, it's a prime factor
                is![n > 2, factors.push(n)];
                factors
            }

            /// Returns the unique prime factors.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t ").factors_prime_unique(), vec![2, 3]];"]
            /// ```
            #[must_use]
            pub fn factors_prime_unique(self) -> Vec<$t> {
                self.factors_prime().hook(|v| v.dedup())
            }

            /// Returns the unique prime factors with its exponent.
            ///
            /// # Examples
            /// ```
            /// # use devela::Int;
            #[doc = "assert_eq![Int(24_" $t
                ").factors_prime_unique_exp(), vec![(2, 3), (3, 1)]];"]
            #[doc = "assert![Int(0_" $t ").factors_prime_unique_exp().is_empty()];"]
            #[doc = "assert![Int(1_" $t ").factors_prime_unique_exp().is_empty()];"]
            #[doc = "assert_eq![Int(7_" $t ").factors_prime_unique_exp(), vec![(7, 1)]];"]
            /// ```
            #[must_use]
            #[cfg(feature = "alloc")]
            #[cfg_attr(nightly_doc, doc(cfg(feature = "alloc")))]
            pub fn factors_prime_unique_exp(self) -> Vec<($t, u32)> {
                let mut factors = Vec::new();
                let mut current = None;
                let mut count = 0;

                for prime in self.factors_prime() {
                    match current {
                        Some(f) if f == prime => count += 1,
                        _ => {
                            if let Some(f) = current { factors.push((f, count)); }
                            current = Some(prime);
                            count = 1;
                        },
                    }
                }
                if let Some(f) = current { factors.push((f, count)); }
                factors
            }
        }
    }};
}
__impl_int_factors_alloc!();