#!/usr/bin/ruby

# Tests for some Number methods.

assert_eq(inverse_usigma(120), 1..120 -> grep { .usigma == 120 })
assert_eq(inverse_usigma(5040).len, 38)
assert_eq(inverse_usigma(5040).map { .usigma }.uniq, [5040])

assert_eq(inverse_sigma(120), 1..120 -> grep { .sigma == 120 })
assert_eq(inverse_sigma(240), 1..240 -> grep { .sigma == 240 })
assert_eq(inverse_sigma(5040).len, 33)
assert_eq(inverse_sigma(5040).map{.sigma}.uniq, [5040])

assert_eq(inverse_sigma(22100, 2), [120, 130, 141])

assert_eq(inverse_phi(120), [143, 155, 175, 183, 225, 231, 244, 248, 286, 308, 310, 350, 366, 372, 396, 450, 462])
assert_eq(inverse_phi(5040).len, 93)
assert_eq(inverse_phi(5040).map{ .phi }.uniq, [5040])

assert_eq(inverse_psi(240), 1..240 -> grep { .psi == 240 })
assert_eq(inverse_psi(5040).len, 38)
assert_eq(inverse_psi(5040).map{.psi}.uniq, [5040])

assert_eq(inverse_uphi(120), [121, 143, 144, 155, 164, 183, 220, 231, 240, 242, 286, 310, 366, 462])
assert_eq(inverse_uphi(5040).len, 90)
assert_eq(inverse_uphi(5040).map{.uphi}.uniq, [5040])

assert_eq(20.of { .omega },  20.of { .factor_exp.len })
assert_eq(20.of { .Omega },  20.of { .factor.len })

assert_eq(20.of { .tau },       20.of { .divisors.len })
assert_eq(20.of { .sigma },     20.of { .divisors.sum })
assert_eq(20.of { .sigma(2) },  20.of { .divisors.sum { _*_ } })

assert_eq(20.of { .phi },    20.of {|n| 1..n -> count_by { |k| is_coprime(n,k) } })
assert_eq(20.of { .usigma }, 20.of { _ ? .factor_map { |p,e| p**e + 1 }.prod : 0 })
assert_eq(20.of { .uphi },   20.of { _ ? .factor_map { |p,e| p**e - 1 }.prod : 0 })

assert_eq(1..100 -> grep { .is_smooth(5) }, 1..100 -> grep { .gpf <= 5 })
assert_eq(2..100 -> grep { .is_rough(5)  }, 2..100 -> grep { .lpf >= 5 })

assert_eq(50.of { .inverse_phi.len }, 50.of { .inverse_phi_len })
assert_eq(50.of { .inverse_psi.len }, 50.of { .inverse_psi_len })
assert_eq(50.of { .inverse_sigma.len }, 50.of { .inverse_sigma_len })
assert_eq(50.of { .inverse_sigma(2).len }, 50.of { .inverse_sigma_len(2) })

assert_eq(inverse_phi(2**64).len, inverse_phi_len(2**64))
assert_eq(inverse_psi(2**64).len, inverse_psi_len(2**64))
assert_eq(inverse_sigma(2**64).len, inverse_sigma_len(2**64))

do {
    var a = Math.smooth_numbers(2,3,5,7)    # 7-smooth numbers
    var b = Math.smooth_numbers(2,5,7)      # 7-smooth numbers not divisible by 3

    assert_eq(a.first(30), 30.by { .is_smooth(7) })
    assert_eq(b.first(30), 30.by {!.is_div(3) && .is_smooth(7) })

    # Iteration is also supported
    a.each {|k|
        if (k > 1e5) {
            assert_eq(k, 100352)
            break
        }
    }
}

say "** Tests passed!"