127 lines
2.5 KiB
Python
127 lines
2.5 KiB
Python
'''Fusc sequence'''
|
|
|
|
from itertools import chain, count, islice
|
|
from operator import itemgetter
|
|
|
|
|
|
# As an infinite stream of terms,
|
|
|
|
# infiniteFusc :: [Int]
|
|
def infiniteFusc():
|
|
'''Fusc sequence.
|
|
OEIS A2487
|
|
'''
|
|
def go(step):
|
|
isEven, n, xxs = step
|
|
x, xs = xxs[0], xxs[1:]
|
|
if isEven:
|
|
nxt = n + x
|
|
return not isEven, nxt, xxs + [nxt]
|
|
else:
|
|
return not isEven, x, xs + [x]
|
|
|
|
return chain(
|
|
[0, 1],
|
|
map(
|
|
itemgetter(1),
|
|
iterate(go)(
|
|
(True, 1, [1])
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
# Or as a function over an integer:
|
|
|
|
# fusc :: Int -> Int
|
|
def fusc(i):
|
|
'''Fusc sequence'''
|
|
def go(n):
|
|
if 0 == n:
|
|
return (1, 0)
|
|
else:
|
|
x, y = go(n // 2)
|
|
return (x + y, y) if 0 == n % 2 else (
|
|
x, x + y
|
|
)
|
|
return 0 if 1 > i else (
|
|
go(i - 1)[0]
|
|
)
|
|
|
|
|
|
# firstFuscOfEachMagnitude ::
|
|
def firstFuscOfEachMagnitude():
|
|
'''Non-finite stream of each term
|
|
in OEIS A2487 that requires an
|
|
unprecedented quantity of decimal digits.
|
|
'''
|
|
a2487 = enumerate(map(fusc, count()))
|
|
|
|
def go(e):
|
|
limit = 10 ** e
|
|
return next(
|
|
(i, x) for i, x in a2487
|
|
if limit <= x
|
|
)
|
|
return (
|
|
chain([(0, 0)], map(go, count(1)))
|
|
)
|
|
|
|
|
|
# --------------------------TEST---------------------------
|
|
# main :: IO ()
|
|
def main():
|
|
'''Tests'''
|
|
|
|
print('First 61 terms:')
|
|
print(showList(
|
|
take(61)(
|
|
map(fusc, count())
|
|
)
|
|
))
|
|
|
|
print('\nFirst term of each decimal magnitude:')
|
|
print('(Index, Term):')
|
|
ixs = firstFuscOfEachMagnitude()
|
|
for _ in range(0, 5):
|
|
print(next(ixs))
|
|
|
|
|
|
# -------------------------GENERIC-------------------------
|
|
|
|
# iterate :: (a -> a) -> a -> Gen [a]
|
|
def iterate(f):
|
|
'''An infinite list of repeated
|
|
applications of f to x.
|
|
'''
|
|
def go(x):
|
|
v = x
|
|
while True:
|
|
yield v
|
|
v = f(v)
|
|
return lambda x: go(x)
|
|
|
|
|
|
# showList :: [a] -> String
|
|
def showList(xs):
|
|
'''Compact stringification of a list.'''
|
|
return '[' + ','.join(repr(x) for x in xs) + ']'
|
|
|
|
|
|
# take :: Int -> [a] -> [a]
|
|
# take :: Int -> String -> String
|
|
def take(n):
|
|
'''The prefix of xs of length n,
|
|
or xs itself if n > length xs.
|
|
'''
|
|
return lambda xs: (
|
|
xs[0:n]
|
|
if isinstance(xs, (list, tuple))
|
|
else list(islice(xs, n))
|
|
)
|
|
|
|
|
|
# MAIN ---
|
|
if __name__ == '__main__':
|
|
main()
|