Created
October 25, 2018 08:36
-
-
Save EngineerCoding/441e99366488f7229122c8a22b5b044c to your computer and use it in GitHub Desktop.
I needed to generate stirling numbers programmatically but couldn't find a proper implementation available in python. Being a non-mathematician, it was quite hard to understand and thus I wrote this script. From my testing, the outputs are correct.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import functools | |
_use_cache = True | |
def set_use_cache(use_cache): | |
global _use_cache | |
_use_cache = bool(use_cache) | |
def optional_cache(func): | |
@functools.wraps(func) | |
def wrapper(*args, **kwargs): | |
if not _use_cache: | |
return func(*args, **kwargs) | |
key = '' | |
if args: | |
key += '@'.join(map(str, args)) | |
if kwargs: | |
kwarg_names = list(kwargs.keys()) | |
kwarg_names.sort() | |
if key: | |
key += '#' | |
key += '@'.join(['{}={}'.format(kwarg_key, kwargs[kwarg_key]) for kwarg_key in kwarg_keys]) | |
if not getattr(func, 'cache', None): | |
setattr(func, 'cache', dict()) | |
if key not in func.cache: | |
func.cache[key] = func(*args, **kwargs) | |
return func.cache[key] | |
return wrapper | |
@optional_cache | |
def first_kind(n, k): | |
if k == 0: | |
return 0 | |
elif n == k: | |
return int(n != 0) | |
return first_kind(n - 1, k - 1) + (n - 1) * first_kind(n - 1, k) | |
@optional_cache | |
def signed_first_kind(n, k): | |
return first_kind(n, k) * pow(-1, n - k) | |
@optional_cache | |
def second_kind(n, k): | |
if n == 0 and k == 0: | |
return 1 | |
elif n == 0 or k == 0: | |
return 0 | |
return second_kind(n - 1, k - 1) + k * second_kind(n - 1, k) | |
if __name__ == '__main__': | |
import sys | |
if len(sys.argv) < 3: | |
print("Usage:") | |
print("{} {} <n:int> <k:int>".format(sys.executable, sys.argv[0])) | |
sys.exit(1) | |
def _get_int(value, name): | |
try: | |
return int(value.strip()) | |
except ValueError: | |
print("argument {} is not an int: {}".format(n, value)) | |
sys.exit(1) | |
n = _get_int(sys.argv[1].strip(), "n") | |
k = _get_int(sys.argv[2].strip(), "k") | |
if n <= 0: | |
print("n > 0 required") | |
sys.exit() | |
print("First kind unsigned: " + str(first_kind(n, k))) | |
print("First kind signed: " + str(signed_first_kind(n, k))) | |
print("Second kind: " + str(second_kind(n, k))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment