#!/usr/bin/ruby

# Tests for squarefree related functions.

assert_eq(
    squarefree(2**64 - 100, 2**64 - 1),
    range(2**64 - 100, 2**64 - 1).grep{.is_squarefree}
)

assert_eq(
    squarefree(2**64 - 50, 2**64 + 1),
    range(2**64 - 50, 2**64 + 1).grep{.is_squarefree}
)

assert_eq(
    squarefree(2**65 - 100, 2**65 - 1),
    range(2**65 - 100, 2**65 - 1).grep{.is_squarefree}
)

assert_eq(
    squarefree(2**63 - 100, 2**63 - 1),
    range(2**63 - 100, 2**63 - 1).grep{.is_squarefree}
)

assert_eq(
    squarefree(2**32 - 100, 2**32 - 1),
    range(2**32 - 100, 2**32 - 1).grep{.is_squarefree}
)

assert_eq(
    squarefree(2**31 - 100, 2**31 - 1),
    range(2**31 - 100, 2**31 - 1).grep{.is_squarefree}
)

assert_eq(
    squarefree(100),
    1..100 -> grep{.is_squarefree}
)

assert_eq(
    gather {
        each_squarefree(2**64 - 100, 2**64 - 1, {|k|
            take(k)
        }),
    },
    squarefree(2**64 - 100, 2**64 - 1),
)

assert_eq(
    gather {
        each_squarefree(2**64 - 100, 2**64 - 50, {|k|
            take(k)
        }),
    },
    range(2**64 - 100, 2**64 - 50).grep{.is_squarefree}
)

assert_eq(
    gather {
        each_squarefree(2**64 - 100, 2**64 - 49, {|k|
            take(k)
        }),
    },
    range(2**64 - 100, 2**64 - 49).grep{.is_squarefree}
)

assert_eq(
    gather {
        each_squarefree(2**64 - 100, 2**64 - 50, {|k|
            take(k)
        })
    },
    squarefree(2**64 - 100, 2**64 - 50),
)

assert_eq(
    gather {
        each_squarefree(2**64 - 50, 2**64 + 1, {|k|
            take(k)
        }),
    },
    range(2**64 - 50, 2**64 + 1).grep{.is_squarefree}
)

assert_eq(
    Math.seq(next_squarefree(0), { .tail.next_squarefree }).while { _ <= 100 },
    squarefree(1..100)
)

assert_eq(
    Math.seq(next_powerfree(0,3), { .tail.next_powerfree(3) }).while { _ <= 100 },
    1..100 -> grep { .is_powerfree(3) }
)

for n in (31, 32, 63, 64) {

    assert_eq(
        Math.seq(next_squarefree(2**n - 11), { .tail.next_squarefree }).while { _ <= (2**n + 100) },
        squarefree(range(2**n - 10, 2**n + 100))
    )

    assert_eq(
        Math.seq(next_powerfree(2**n - 11, 3), { .tail.next_powerfree(3) }).while { _ <= (2**n + 100) },
        range(2**n - 10, 2**n + 100).grep { .is_powerfree(3) }
    )
}

assert_eq(next_powerfree(2**120 - 1e3),    1329227995784915872903807060280343578)
assert_eq(next_powerfree(2**120 - 1e3, 3), 1329227995784915872903807060280343577)
assert_eq(next_powerfree(2**120 - 1e3, 4), 1329227995784915872903807060280343577)

assert_eq(
    10.of { .next_squarefree },
    %n[1, 2, 3, 5, 5, 6, 7, 10, 10, 10]
)

assert_eq(next_squarefree(0), 1)
assert(next_squarefree(-50).is_nan)

assert_eq(next_squarefree(2**64), 2**64 + 1)
assert_eq(next_squarefree(2**32), 2**32 + 1)
assert_eq(next_squarefree(2**16), 2**16 + 1)

assert_eq(next_powerfree(2**64, 3), 2**64 + 1)
assert_eq(next_powerfree(2**32, 3), 2**32 + 1)
assert_eq(next_powerfree(2**16, 3), 2**16 + 1)

assert_eq(next_squarefree(2**16 - 1), 2**16 + 1)
assert_eq(next_squarefree(2**32 - 1), 2**32 + 1)
assert_eq(next_squarefree(2**64 - 1), 2**64 + 1)

assert_eq(next_squarefree(2**16 - 2), 2**16 - 1)
assert_eq(next_squarefree(2**32 - 2), 2**32 - 1)
assert_eq(next_squarefree(2**64 - 2), 2**64 - 1)
assert_eq(next_squarefree(2**128 - 2), 2**128 - 1)

assert_eq(next_squarefree(2**64 + 3), 2**64 + 5)

assert_eq(43.square_free_count, 29)
assert_eq(square_free_count(-10, 43), 29)
assert_eq(square_free_count(2, 43), 28)
assert_eq(square_free_count(4, 43), 26)
assert_eq(square_free_count(1e6), 607926)
assert_eq(square_free_count(1e5, 1e6), 547132)
assert_eq(square_free_count(1e5 - 2, 1e6 - 3), 547133)
assert_eq(square_free_count(1e5 - 1, 1e6 - 3), 547132)
assert_eq(square_free_count(1e5 - 2, 1e6 - 1), 547133)

for n in (1..8), k in (2..15 -> map{|b| b**n }) {
    var t = nth_squarefree(k)
    assert(t.is_squarefree)
    assert_eq(t.squarefree_count, k)
}

assert_eq(3000.of{.nth_squarefree}.ft(1), 3000.dec.by{.is_squarefree})

say "** Test passed!"
