Created
June 30, 2017 04:52
-
-
Save nhomble/faf08174a5f27aa3ebfd7917e38742f4 to your computer and use it in GitHub Desktop.
the G suggested I do this: https://en.wikipedia.org/wiki/Fibonacci_coding
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
class FibCoder: | |
''' | |
https://en.wikipedia.org/wiki/Fibonacci_coding | |
''' | |
def __init__(self, seed: int = 2): | |
self._fib = [] | |
self._fibonacci(seed) | |
def _next_fib(self, n: int): | |
i = 0 | |
while self._fibonacci(i) <= n: | |
i += 1 | |
return i - 1 | |
def _fibonacci(self, n: int): | |
self._fib.extend([None for i in range(1 + n - len(self._fib))]) | |
def f(n: int, mem: list): | |
if n == 0: | |
mem[n] = 0 | |
return mem | |
if n == 1: | |
mem[n] = 1 | |
return mem | |
else: | |
if mem[n - 1] is not None: | |
n1 = mem[n - 1] | |
else: | |
n1 = f(n - 1, mem)[n - 1] | |
if mem[n - 2] is not None: | |
n2 = mem[n - 2] | |
else: | |
n2 = f(n - 2, mem)[n - 2] | |
mem[n] = n1 + n2 | |
return mem | |
self._fib = f(n, self._fib) | |
return self._fib[n] | |
def encode(self, to_encode: int) -> str: | |
nums = ["0" for i in range(self._next_fib(to_encode))] | |
while to_encode > 0: | |
nf = self._next_fib(to_encode) | |
to_encode -= self._fibonacci(nf) | |
nums[nf - 2] = "1" | |
nums[-1] = "1" | |
return "".join(nums) | |
def decode(self, to_decode: str) -> int: | |
assert (to_decode.isnumeric()) | |
to_decode = to_decode[:len(to_decode) - 1] | |
ret = 0 | |
for (n, v) in enumerate(to_decode): | |
factor = int(v) | |
ret += factor * self._fibonacci(n + 2) | |
return ret |
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 unittest | |
from fib import FibCoder | |
class TestFibGeneration(unittest.TestCase): | |
def test_up_to_8(self): | |
f = FibCoder(seed=8) | |
assert (f._fib == [0, 1, 1, 2, 3, 5, 8, 13, 21]) | |
class TestClosestFib(unittest.TestCase): | |
def test_on_the_dot(self): | |
f = FibCoder(seed=5) | |
assert (f._next_fib(2) == 3) | |
def test_need_to_grow(self): | |
f = FibCoder(seed=2) | |
assert (f._next_fib(2) == 3) | |
def test_a_little_ess(self): | |
f = FibCoder(seed=8) | |
assert (f._next_fib(14) == 7) | |
class TestCoding(unittest.TestCase): | |
cases = [ | |
[1, "11"], | |
[2, "011"], | |
[14, "1000011"], | |
[65, "0100100011"] | |
] | |
def test_cases(self): | |
f = FibCoder() | |
for case in TestCoding.cases: | |
assert (f.encode(case[0]) == case[1]) | |
assert (f.decode(case[1]) == case[0]) | |
def test_random(self): | |
import random | |
f = FibCoder() | |
randoms = [random.randint(1, 100) for x in range(100)] | |
for r in randoms: | |
assert (f.decode(f.encode(r)) == r) | |
if __name__ == "__main__": | |
unittest.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment