#!/usr/bin/ruby

# Tests for the built-in prime factorization methods.

# Timings:
#   07 March 2023: 1.136s (with MPU)

do {
    {|n| assert_eq(mbe_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(flt_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(fibonacci_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(dop_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(cop_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(fermat_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(phi_finder_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(pell_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(miller_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(lucas_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(holf_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(pm1_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(pp1_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(chebyshev_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(ecm_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(squfof_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(qs_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(trial_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(cyclotomic_factor(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(special_factors(n).prod, n||1) }.each(0..30)
    {|n| assert_eq(Math.gcd_factors(n, n.isqrt.primes).prod, n||1) }.each(0..30)
}

do {
    func verify_factors(f,n) {
        assert_eq(f.prod, n)
        assert(f.len >= 2)
        assert(f.all { n % _ == 0})
    }

    for n in ([10**120 - 10**40, 2**128 - 1]) {

        verify_factors(n.factor { .squfof_factor(1e4) }, n)
        verify_factors(n.factor { .trial_factor }, n)
        verify_factors(n.factor { .pell_factor }, n)
        verify_factors(n.factor { .flt_factor }, n)
        verify_factors(n.factor { .fibonacci_factor }, n)
        verify_factors(n.factor { .holf_factor }, n)
        verify_factors(n.factor { .mbe_factor }, n)
        verify_factors(n.factor { .fermat_factor }, n)
        verify_factors(n.factor { .cyclotomic_factor }, n)
        verify_factors(n.factor { .chebyshev_factor(1e4) }, n)
        verify_factors(n.factor { .ecm_factor }, n)
        verify_factors(n.factor { .pm1_factor(1e4) }, n)
        verify_factors(n.factor { .pp1_factor(1e4) }, n)

        verify_factors(n.special_factors, n)
        verify_factors(n.dop_factor, n)
        verify_factors(n.cop_factor, n)

        if (n.is_odd) {
        verify_factors(n.factor { .phi_finder_factor }, n)
            verify_factors(n.factor { .miller_factor }, n)
            verify_factors(n.factor { .lucas_factor }, n)
        }
    }

    verify_factors(phi_finder_factor(43*97), 43*97)
    verify_factors(phi_finder_factor(503*863), 503*863)
    verify_factors(phi_finder_factor(622882096110539), 622882096110539)
    verify_factors(phi_finder_factor(132750061135361, 1e5), 132750061135361)

    with (283874509653487424333753053009549245120760303237063459589551) {|n|
        verify_factors(n.phi_finder_factor, n)
        verify_factors(n.fermat_factor(1e5), n)
    }

    verify_factors(fibonacci_factor(480.fib), 480.fib)
    verify_factors(fibonacci_factor(480.lucas), 480.lucas)

    with (58571442634534443082821160508299574798027946748324125518533225605795841) {|n|
        verify_factors(miller_factor(n), n)
        verify_factors(lucas_factor(n), n)
        verify_factors(lucas_factor(n, -1), n)
        verify_factors(lucas_factor(n, +1), n)
    }
}

assert_eq(cyclotomic_factor(((10**258 - 1)/9 - 10**(258/2) - 1)),     %n[2, 5, 7, 11, 11, 13, 17, 73, 101, 137, 353, 449, 641, 1409, 69857, 5882353, 100000000000000000000000000000001, 909090909090909090909090909090909090909091, 10000000000000000000000000000000000000000000000000000000000000001, 1098901098901098901098901098901098901098900989010989010989010989010989010989010989011])
assert_eq(cyclotomic_factor(((10**258 - 1)/9 - 10**(258/2) - 1), 10), %n[10, 11, 11, 91, 101, 10001, 100000001, 10000000000000001, 100000000000000000000000000000001, 909090909090909090909090909090909090909091, 10000000000000000000000000000000000000000000000000000000000000001, 1098901098901098901098901098901098901098900989010989010989010989010989010989010989011])

say "** Tests passed!"
