#!/usr/bin/ruby

# Tests for Lucas sequences U_n(P, Q) and V_n(P, Q).

func is(Number a, b) {

    if (a.is_nan) {
        return __FUNC__(a.to_s, b.to_s)
    }

    assert_eq(a, b)
}

func is(a, b){
    assert_eq(a, b)
}

is(lucas(-1),  NaN)
is(lucas(0),     2)
is(lucas(1),     1)
is(lucas(15), 1364)
is(lucas(15), 1364)
is(lucas(-4),  NaN)

is(lucasU(4, 4, 13), 53248)
is(lucasV(4, 4, 13), 16384)

is(lucasV(-4, 4,  24), 33554432)
is(lucasV(4,  -4, 24), 25783171895263232)
is(lucasV(4,  -4, 25), 124492166541082624)
is(lucasV(-4, 4,  25), -67108864)
is(lucasV(-4, 4,  26), 134217728)
is(lucasV(-4, -4, 16), 87275208704)
is(lucasV(-4, -4, 48), 664771952980691802270648617664512)

is(lucasU(4,  -4, 24), 4557863921909760)
is(lucasU(-4, 4,  24), -201326592)
is(lucasU(4,  -4, 25), 22007313791451136)
is(lucasU(-4, 4,  25), 419430400)
is(lucasU(-4, 4,  26), -872415232)
is(lucasU(-4, -4, 16), -15428222976)
is(lucasU(-4, -4, 48), -117516188973817974394087349944320)

is(lucasUmod(-4, -4, 48,    700237709),  424976705)
is(lucasUmod(4,  -4, 4171,  619442071),  93411036)
is(lucasUmod(4,  -4, 54223, 1238884142), 793124222)

is(lucasUmod(5, 3, 1234, 789347),  134939)
is(lucasUmod(5, 3, 1234, -789347), 134939)   # maybe this should be: 134939 - 789347 = -654408

is({ lucasUmod(3, -2, _, 24) }.map(0 .. 9), [0, 1, 3, 11, 15, 19, 15, 11, 15, 19])
is({ lucasVmod(3, -2, _, 24) }.map(0 .. 9), [2, 3, 13, 21, 17, 21, 1, 21, 17, 21])

is({ [lucasUVmod(3, -2, _, 24)] }.map(0 .. 9),
    [0, 1, 3, 11, 15, 19, 15, 11, 15, 19] ~Z
    [2, 3, 13, 21, 17, 21, 1, 21, 17, 21])

is({ lucasUmod(4, 4, _, 25) }.map(0 .. 9), [0, 1, 4, 12, 7, 5, 17, 23, 24, 4])
is({ lucasVmod(4, 4, _, 25) }.map(0 .. 9), [2, 4, 8, 16, 7, 14, 3, 6, 12, 24])

is({ [lucasUVmod(4, 4, _, 25)] }.map(0 .. 9),
    [0, 1, 4, 12, 7, 5, 17, 23, 24, 4] ~Z
    [2, 4, 8, 16, 7, 14, 3, 6, 12, 24])

is({ lucasUmod(-5, -3, _, 48) }.map(0 .. 9), [0, 1, 43, 28, 37, 43, 40, 25, 43, 4])
is({ lucasVmod(-5, -3, _, 48) }.map(0 .. 9), [2, 43, 31, 22, 31, 7, 10, 19, 31, 46])

is({ [lucasUVmod(-5, -3, _, 48)] }.map(0 .. 9),
    [0, 1, 43, 28, 37, 43, 40, 25, 43, 4] ~Z
    [2, 43, 31, 22, 31, 7, 10, 19, 31, 46])

is({ lucasUmod( 5, 3, _, 789347) }.map(0 .. 14), [0, 1, 5, 22, 95, 409, 1760, 7573, 32585, 140206, 603275, 227716, 118102, 696709, 761198])
is({ lucasUmod(-5, 3, _, 789347) }.map(0 .. 14), [0, 1, 789342, 22, 789252, 409, 787587, 7573, 756762, 140206, 186072, 227716, 671245, 696709, 28149])

is({ lucasUmod( 5, 3, _, 789347) }.map(0 .. 14), { lucasU( 5, 3, _) % 789347 }.map(0 .. 14))
is({ lucasUmod(-5, 3, _, 789347) }.map(0 .. 14), { lucasU(-5, 3, _) % 789347 }.map(0 .. 14))

is({ lucasVmod( 5, 3, _, 789347) }.map(0 .. 14), { lucasV( 5, 3, _) % 789347 }.map(0 .. 14))
is({ lucasVmod(-5, 3, _, 789347) }.map(0 .. 14), { lucasV(-5, 3, _) % 789347 }.map(0 .. 14))

is(fibmod(0, 100), 0)
is(fibmod(1, 100), 1)
is(lucasmod(0, 100), 2)
is(lucasmod(1, 100), 1)

is(lucasUmod(1, -1, 0, 100), 0)
is(lucasUmod(1, -1, 1, 100), 1)

is(lucasVmod(1, -1, 0, 100), 2)
is(lucasVmod(1, -1, 1, 100), 1)

is(lucasUmod(4, 4, 0, 100), 0)
is(lucasUmod(4, 4, 1, 100), 1)

is(lucasUmod(4,  4, 50, 1000), lucasU(4,  4, 50) % 1000)
is(lucasUmod(4, -4, 50, 1000), lucasU(4, -4, 50) % 1000)

is(lucasVmod(4, 4, 0, 100), 2)
is(lucasVmod(4, 4, 1, 100), 4)

is(lucasVmod(4, 4, 0, 100), lucasV(4, 4, 0) % 100)
is(lucasVmod(4, 4, 1, 100), lucasV(4, 4, 1) % 100)

is(lucasVmod( 4, 4, 50, 1000), 248)
is(lucasVmod(-4, 4, 50, 1000), 248)

is(lucasVmod( 4, 4, 50, 1000), lucasV(4, 4, 50) % 1000)
is(lucasVmod(-4, 4, 50, 1000), lucasV(4, 4, 50) % 1000)

is(lucasVmod( 4, 4, 50, 1001), lucasV( 4, 4, 50) % 1001)
is(lucasVmod(-4, 4, 50, 1001), lucasV(-4, 4, 50) % 1001)

is(lucasVmod( 4, -4, 50, 1000), 624)
is(lucasVmod(-4, -4, 50, 1000), 624)

is(lucasVmod( 4, -4, 50, 1000), lucasV( 4, -4, 50) % 1000)
is(lucasVmod(-4, -4, 50, 1000), lucasV(-4, -4, 50) % 1000)

is(fibmod(1234, 987654), fibonacci(1234) % 987654)
is(lucasmod(1234, 987654), lucas(1234) % 987654)

is(lucasUmod(1, -1, -43, 42), NaN)
is(lucasUmod(1, -1, -2, 43), NaN)

is(lucasVmod(1, -1, -43, 42), NaN)
is(lucasVmod(1, -1, -2, 43), NaN)

is([lucasUVmod(1, -1, -41, 97)].join(' '), [NaN, NaN].join(' '))
is([lucasUVmod(1, -1, -12, 42)].join(' '), [NaN, NaN].join(' '))

is(fibmod(-1, 1234), NaN)
is(lucasmod(-1, 1234), NaN)

is(fibmod(42, 0), NaN)
is(lucasmod(42, 0), NaN)

is(lucasUmod(2**95 + 1, 2**75 - 1, 1234, 98765), 35621)
is(lucasVmod(2**95 + 1, 2**75 - 1, 1234, 98765), 3022)

is(lucasUmod(2**95 + 1, 2**75 - 1, 98765, 1234), 477)
is(lucasVmod(2**95 + 1, 2**75 - 1, 98765, 1234), 29)

is([lucasUVmod(2**95 + 1, 2**75 - 1, 1234, 98765)], [35621, 3022])
is([lucasUVmod(2**95 + 1, 2**75 - 1, 98765, 1234)], [477, 29])

say "** Test passed!"