Data update
This commit is contained in:
parent
8e4e15fa56
commit
72eb4943cb
1853 changed files with 35514 additions and 9441 deletions
|
|
@ -1,19 +1,19 @@
|
|||
from itertools import islice, cycle
|
||||
|
||||
def fiblike(tail):
|
||||
for x in tail:
|
||||
yield x
|
||||
for i in cycle(xrange(len(tail))):
|
||||
def fiblike(init_values=(0, 1)):
|
||||
tail = list(init_values)
|
||||
yield from tail
|
||||
for i in cycle(range(len(tail))):
|
||||
tail[i] = x = sum(tail)
|
||||
yield x
|
||||
|
||||
fibo = fiblike([1, 1])
|
||||
print list(islice(fibo, 10))
|
||||
print([*islice(fiblike(), 10)])
|
||||
lucas = fiblike([2, 1])
|
||||
print list(islice(lucas, 10))
|
||||
print([*islice(lucas, 10)])
|
||||
|
||||
suffixes = "fibo tribo tetra penta hexa hepta octo nona deca"
|
||||
for n, name in zip(xrange(2, 11), suffixes.split()):
|
||||
fib = fiblike([1] + [2 ** i for i in xrange(n - 1)])
|
||||
suffixes = dict(enumerate('fibo tribo tetra penta hexa hepta octo nona deca'.split(), start=2))
|
||||
|
||||
for name, n in suffixes.items():
|
||||
fib = fiblike([1] + [2 ** i for i in range(n-1)])
|
||||
items = list(islice(fib, 15))
|
||||
print "n=%2i, %5snacci -> %s ..." % (n, name, items)
|
||||
print(f'n={n:>2}, {name:>5}nacci -> {items} ...')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
from itertools import chain
|
||||
|
||||
def A000032():
|
||||
'''Non finite sequence of Lucas numbers.
|
||||
'''
|
||||
return unfoldr(recurrence, [0, 1])
|
||||
|
||||
def n_step_fibonacci(n):
|
||||
'''Non-finite series of N-step Fibonacci numbers,
|
||||
defined by a recurrence relation.
|
||||
'''
|
||||
return unfoldr(
|
||||
recurrence,
|
||||
chain(
|
||||
(0,),
|
||||
(2 ** i for i in range(0, n-1))))
|
||||
|
||||
def recurrence(xs):
|
||||
'''Recurrence relation in Fibonacci and related series.
|
||||
'''
|
||||
h, *t = xs
|
||||
return h, t + [sum(xs)]
|
||||
|
||||
def unfoldr(f, residue):
|
||||
'''Generic anamorphism.
|
||||
A lazy (generator) list unfolded from a seed value by
|
||||
repeated application of f until no residue remains.
|
||||
Dual to fold/reduce.
|
||||
f returns either None, or just (value, residue).
|
||||
For a strict output value, wrap in list().
|
||||
'''
|
||||
while residue is not None:
|
||||
value, residue = f(residue)
|
||||
yield value
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
from itertools import chain
|
||||
|
||||
def f_rec_tailfail(values=[0, 1], combine=sum):
|
||||
"""
|
||||
This fails with `RecursionError: maximum recursion depth exceeded`
|
||||
when the number of consumed elements surpasses maximum stack size
|
||||
(by default 1000 call frames -- `sys.getrecursionlimit()`),
|
||||
due to the fact that Python does not have tail call optimization.
|
||||
"""
|
||||
yield values[0]
|
||||
yield from f_rec_tailfail(values[1:] + [combine(values)], combine)
|
||||
|
||||
|
||||
def f_rec_gen_func(values=[0, 1], combine=sum):
|
||||
"""
|
||||
This function does not suffer from `RecursionError` per se, but stack overflow
|
||||
nevertheless does happen in the underlying C code when too many elements are
|
||||
consumed from the generator.
|
||||
|
||||
One possible reason for this is because `chain` is implemented in C,
|
||||
and the chain consists of another `chain` object, which in turn contains
|
||||
another `chain` object, etc. The effect of this is that all the recursive
|
||||
calls happen on the C call stack (where recursion depth is not checked
|
||||
against the limit), not on the Python call stack. As a result, it is possible
|
||||
to achieve much greater recursion depth -- over 40,000 recursive calls
|
||||
instead of mere 1000. When a stack overflow eventually happens, the Python
|
||||
interpreter crashes quietly without any error message (CPython 3.11.3 AMD64).
|
||||
"""
|
||||
def generate_values():
|
||||
yield [values[0]]
|
||||
yield f_rec_gen_func(values[1:] + [combine(values)], combine)
|
||||
return chain.from_iterable(generate_values())
|
||||
|
||||
|
||||
def f_rec_gen_lambdas(values=[0, 1], combine=sum):
|
||||
"""
|
||||
Similar to `f_rec_gen_func`; also does not suffer from `RecursionError`
|
||||
but crashes when many values are consumed.
|
||||
"""
|
||||
return chain.from_iterable(
|
||||
f()
|
||||
for f in (
|
||||
lambda: [values[0]],
|
||||
lambda: f_rec_gen_lambdas(values[1:] + [combine(values)], combine),
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
from dataclasses import dataclass, field
|
||||
from functools import wraps
|
||||
from typing import Callable, Generator
|
||||
|
||||
GeneratorFunc = Callable[..., Generator]
|
||||
|
||||
@dataclass
|
||||
class RecursiveCall:
|
||||
args: tuple = ()
|
||||
kwargs: dict = field(default_factory=dict)
|
||||
|
||||
def tail_recursive_generator(fun: GeneratorFunc) -> GeneratorFunc:
|
||||
@wraps(fun)
|
||||
def decorated(*args, **kwargs):
|
||||
while True:
|
||||
it = fun(*args, **kwargs)
|
||||
try:
|
||||
while True:
|
||||
yield next(it)
|
||||
except StopIteration as e:
|
||||
if not isinstance(res := e.value, RecursiveCall):
|
||||
return res
|
||||
args, kwargs = res.args, res.kwargs
|
||||
|
||||
return decorated
|
||||
|
||||
@tail_recursive_generator
|
||||
def f_rec_tail(values=(0, 1), combine=sum):
|
||||
"""
|
||||
Does not crash or throw RecursionError! Yay!
|
||||
"""
|
||||
yield values[0]
|
||||
# determining why we cannot call `f_rec_tail` directly
|
||||
# is left as an exercise for the reader...
|
||||
return RecursiveCall(args=(values[1:] + (combine(values),), combine))
|
||||
Loading…
Add table
Add a link
Reference in a new issue