From 527ea435dc2b5ddbf320e78099c66c49a0211461 Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Fri, 2 Oct 2020 10:47:36 -0500 Subject: [PATCH 01/13] Fix: Multiple errors in fibonacci search. - Test lists were not ordered, this is required for Fibonacci search - Place documentation of function inside function - Create multiple different tests including, float, char and negatives - Add type hints in line with #2128 --- searches/fibonacci_search.py | 126 ++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 38 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 67f2df505d4e..0d2ff17d5266 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -1,51 +1,101 @@ -# run using python fibonacci_search.py -v - """ -@params -arr: input array -val: the value to be searched -output: the index of element in the array or -1 if not found -return 0 if input array is empty +This is pure Python implementation of fibonacci search. + +Resources used: +https://en.wikipedia.org/wiki/Fibonacci_search_technique + +For doctests run following command: +python3 -m doctest -v fibonacci_search.py + +For manual testing run: +python3 fibonacci_search.py """ +from __future__ import annotations +from functools import lru_cache +import sys + + +@lru_cache() +def fibonacci(k: int) -> int: + """Finds fibonacci number in index k. + Parameters + ---------- + k : int + Index of fibonacci. -def fibonacci_search(arr, val): + Returns + ------- + int + Fibonacci number in position k. + >>> print(fibonacci(0)) + 0 + >>> print(fibonacci(2)) + 1 + >>> print(fibonacci(5)) + 5 + >>> print(fibonacci(15)) + 610 """ - >>> fibonacci_search([1,6,7,0,0,0], 6) + if k == 0: + return 0 + elif k == 1: + return 1 + else: + return fibonacci(k - 1) + fibonacci(k - 2) + + +def fibonacci_search(arr: List[int], val: int) -> int: + """A pure Python implementation of a fibonacci search algorithm. + + Parameters + ---------- + arr : List[int] + List of sorted elements. + val : int + Element to search in list. + + Returns + ------- + int + The index of the element in the array. + -1 if the element is not found. + + >>> print(fibonacci_search([4, 5, 6, 7], 4)) + 0 + >>> print(fibonacci_search([4, 5, 6, 7], -10)) + -1 + >>> print(fibonacci_search([-18, 2], -18)) + 0 + >>> print(fibonacci_search([5], 5)) + 0 + >>> print(fibonacci_search(['a', 'c', 'd'], 'c')) 1 - >>> fibonacci_search([1,-1, 5, 2, 9], 10) + >>> print(fibonacci_search(['a', 'c', 'd'], 'f')) -1 + >>> print(fibonacci_search([], 1)) + -1 + >>> print(fibonacci_search([.1, .4 , 7], .4)) + 1 >>> fibonacci_search([], 9) - 0 + -1 """ - fib_N_2 = 0 - fib_N_1 = 1 - fibNext = fib_N_1 + fib_N_2 - length = len(arr) - if length == 0: - return 0 - while fibNext < len(arr): - fib_N_2 = fib_N_1 - fib_N_1 = fibNext - fibNext = fib_N_1 + fib_N_2 - index = -1 - while fibNext > 1: - i = min(index + fib_N_2, (length - 1)) - if arr[i] < val: - fibNext = fib_N_1 - fib_N_1 = fib_N_2 - fib_N_2 = fibNext - fib_N_1 - index = i - elif arr[i] > val: - fibNext = fib_N_2 - fib_N_1 = fib_N_1 - fib_N_2 - fib_N_2 = fibNext - fib_N_1 - else: - return i - if (fib_N_1 and index < length - 1) and (arr[index + 1] == val): - return index + 1 - return -1 + n = len(arr) + # Find m such that F_m >= n where F_i is the i_th fibonacci number. + m = next(x for x in range(sys.maxsize ** 10) if fibonacci(x) >= n) + k = m + offset = 0 + while k != 0: + if arr[offset + fibonacci(k - 1)] == val: + return fibonacci(k - 1) + elif val < arr[offset + fibonacci(k - 1)]: + k = k - 1 + elif val > arr[offset + fibonacci(k - 1)]: + offset += fibonacci(k - 2) + k = k - 2 + else: + return -1 if __name__ == "__main__": From 78883cc8258c8fede30ece634651124ee0a4a167 Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Fri, 2 Oct 2020 14:18:53 -0500 Subject: [PATCH 02/13] Fix: sort of modules and delete typehint. --- searches/fibonacci_search.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 0d2ff17d5266..2d65e98e8c3b 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -10,12 +10,11 @@ For manual testing run: python3 fibonacci_search.py """ -from __future__ import annotations -from functools import lru_cache import sys +from functools import lru_cache -@lru_cache() +@lru_cache def fibonacci(k: int) -> int: """Finds fibonacci number in index k. @@ -46,12 +45,12 @@ def fibonacci(k: int) -> int: return fibonacci(k - 1) + fibonacci(k - 2) -def fibonacci_search(arr: List[int], val: int) -> int: +def fibonacci_search(arr: list, val: int) -> int: """A pure Python implementation of a fibonacci search algorithm. Parameters ---------- - arr : List[int] + arr : list List of sorted elements. val : int Element to search in list. From 3164b154b3f61ba295bf2f955b211d92860eca43 Mon Sep 17 00:00:00 2001 From: poloso Date: Sun, 4 Oct 2020 16:04:48 -0500 Subject: [PATCH 03/13] Apply suggestions from code review Co-authored-by: Dhruv --- searches/fibonacci_search.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 2d65e98e8c3b..a77db1e315e4 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -20,8 +20,7 @@ def fibonacci(k: int) -> int: Parameters ---------- - k : int - Index of fibonacci. + k : Index of fibonacci. Returns ------- @@ -89,10 +88,10 @@ def fibonacci_search(arr: list, val: int) -> int: if arr[offset + fibonacci(k - 1)] == val: return fibonacci(k - 1) elif val < arr[offset + fibonacci(k - 1)]: - k = k - 1 + k -= 1 elif val > arr[offset + fibonacci(k - 1)]: offset += fibonacci(k - 2) - k = k - 2 + k -= 2 else: return -1 From e8f5133425963f60a56ab4e3a855f96f17f2767a Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Sun, 4 Oct 2020 16:23:31 -0500 Subject: [PATCH 04/13] Correct invocation of lru_cache. --- searches/fibonacci_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index a77db1e315e4..5f69707df8f0 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -14,7 +14,7 @@ from functools import lru_cache -@lru_cache +@lru_cache() def fibonacci(k: int) -> int: """Finds fibonacci number in index k. From 64cc42b6ce9925556888fd85ffcfa3bfcb4090b5 Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Sun, 4 Oct 2020 16:26:46 -0500 Subject: [PATCH 05/13] Add check for input in fibonacci and doctest. --- searches/fibonacci_search.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 5f69707df8f0..20ecde6779c7 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -35,7 +35,17 @@ def fibonacci(k: int) -> int: 5 >>> print(fibonacci(15)) 610 + >>> print(fibonacci('a')) + Traceback (most recent call last): + ValueError: k must be an integer. + >>> print(fibonacci(-5)) + Traceback (most recent call last): + ValueError: k integer must be greater or equal to zero. """ + if not isinstance(k, int): + raise ValueError("k must be an integer.") + if k < 0: + raise ValueError("k integer must be greater or equal to zero.") if k == 0: return 0 elif k == 1: From 15700ddbfeb7034834ce8c7059b5ddcc6a5a6e63 Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Sun, 4 Oct 2020 16:27:53 -0500 Subject: [PATCH 06/13] Correct typehints to comply to numpy style. --- searches/fibonacci_search.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 20ecde6779c7..552e014ac0fd 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -20,7 +20,8 @@ def fibonacci(k: int) -> int: Parameters ---------- - k : Index of fibonacci. + k : + Index of fibonacci. Returns ------- @@ -59,9 +60,9 @@ def fibonacci_search(arr: list, val: int) -> int: Parameters ---------- - arr : list + arr List of sorted elements. - val : int + val Element to search in list. Returns From d7fad2a772b495a6767d8a857a45a52eaba948a9 Mon Sep 17 00:00:00 2001 From: poloso Date: Wed, 7 Oct 2020 08:17:10 -0500 Subject: [PATCH 07/13] Correct ValueError to TypeError. Co-authored-by: Dhruv --- searches/fibonacci_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 552e014ac0fd..94502637f7ff 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -44,7 +44,7 @@ def fibonacci(k: int) -> int: ValueError: k integer must be greater or equal to zero. """ if not isinstance(k, int): - raise ValueError("k must be an integer.") + raise TypeError("k must be an integer.") if k < 0: raise ValueError("k integer must be greater or equal to zero.") if k == 0: From 5c224ebbbc3595af8db8e5936505229d0f7135d5 Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Wed, 7 Oct 2020 08:23:53 -0500 Subject: [PATCH 08/13] Correct doctest for TypeError. --- searches/fibonacci_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 94502637f7ff..fc4ffbfb0f7e 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -38,7 +38,7 @@ def fibonacci(k: int) -> int: 610 >>> print(fibonacci('a')) Traceback (most recent call last): - ValueError: k must be an integer. + TypeError: k must be an integer. >>> print(fibonacci(-5)) Traceback (most recent call last): ValueError: k integer must be greater or equal to zero. From 96a5b6ad38c37a2879b585807c61dc1b6375476d Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Wed, 7 Oct 2020 08:25:19 -0500 Subject: [PATCH 09/13] Rename single letter names as mentioned in CONTRIBUTING.md. --- searches/fibonacci_search.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index fc4ffbfb0f7e..205f3bc05f5a 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -90,19 +90,21 @@ def fibonacci_search(arr: list, val: int) -> int: >>> fibonacci_search([], 9) -1 """ - n = len(arr) + len_list = len(arr) # Find m such that F_m >= n where F_i is the i_th fibonacci number. - m = next(x for x in range(sys.maxsize ** 10) if fibonacci(x) >= n) - k = m + greater_fibb_index = next( + x for x in range(sys.maxsize ** 10) if fibonacci(x) >= len_list + ) + fibb_k = greater_fibb_index offset = 0 - while k != 0: - if arr[offset + fibonacci(k - 1)] == val: - return fibonacci(k - 1) - elif val < arr[offset + fibonacci(k - 1)]: - k -= 1 - elif val > arr[offset + fibonacci(k - 1)]: - offset += fibonacci(k - 2) - k -= 2 + while fibb_k != 0: + if arr[offset + fibonacci(fibb_k - 1)] == val: + return fibonacci(fibb_k - 1) + elif val < arr[offset + fibonacci(fibb_k - 1)]: + fibb_k -= 1 + elif val > arr[offset + fibonacci(fibb_k - 1)]: + offset += fibonacci(fibb_k - 2) + fibb_k -= 2 else: return -1 From c32346298103719fa10699558a0f7a77e4d84a59 Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Wed, 7 Oct 2020 11:39:12 -0500 Subject: [PATCH 10/13] Fix: Bug in big lists. --- searches/fibonacci_search.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 205f3bc05f5a..506bb347fef2 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -89,6 +89,18 @@ def fibonacci_search(arr: list, val: int) -> int: 1 >>> fibonacci_search([], 9) -1 + >>> fibonacci_search(list(range(100)), 63) + 63 + >>> fibonacci_search(list(range(100)), 99) + 99 + >>> fibonacci_search(list(range(-100, 100, 3)), -97) + 1 + >>> fibonacci_search(list(range(-100, 100, 3)), 0) + -1 + >>> fibonacci_search(list(range(-100, 100, 5)), 0) + 20 + >>> fibonacci_search(list(range(-100, 100, 5)), 95) + 39 """ len_list = len(arr) # Find m such that F_m >= n where F_i is the i_th fibonacci number. @@ -97,13 +109,17 @@ def fibonacci_search(arr: list, val: int) -> int: ) fibb_k = greater_fibb_index offset = 0 - while fibb_k != 0: - if arr[offset + fibonacci(fibb_k - 1)] == val: - return fibonacci(fibb_k - 1) - elif val < arr[offset + fibonacci(fibb_k - 1)]: + while fibb_k > 0: + index_k = min( + offset + fibonacci(fibb_k - 1), len_list - 1 + ) # Prevent out of range + item_k_1 = arr[index_k] + if item_k_1 == val: + return index_k + elif val < item_k_1: fibb_k -= 1 - elif val > arr[offset + fibonacci(fibb_k - 1)]: - offset += fibonacci(fibb_k - 2) + elif val > item_k_1: + offset += fibonacci(fibb_k - 1) fibb_k -= 2 else: return -1 From 5bdc2dfde27e235d0315e9cb957d85a71d62cd44 Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Wed, 7 Oct 2020 11:41:07 -0500 Subject: [PATCH 11/13] Remove print(.) in doctests. --- searches/fibonacci_search.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 506bb347fef2..60cea31d7676 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -28,18 +28,18 @@ def fibonacci(k: int) -> int: int Fibonacci number in position k. - >>> print(fibonacci(0)) + >>> fibonacci(0) 0 - >>> print(fibonacci(2)) + >>> fibonacci(2) 1 - >>> print(fibonacci(5)) + >>> fibonacci(5) 5 - >>> print(fibonacci(15)) + >>> fibonacci(15) 610 - >>> print(fibonacci('a')) + >>> fibonacci('a') Traceback (most recent call last): TypeError: k must be an integer. - >>> print(fibonacci(-5)) + >>> fibonacci(-5) Traceback (most recent call last): ValueError: k integer must be greater or equal to zero. """ @@ -71,21 +71,21 @@ def fibonacci_search(arr: list, val: int) -> int: The index of the element in the array. -1 if the element is not found. - >>> print(fibonacci_search([4, 5, 6, 7], 4)) + >>> fibonacci_search([4, 5, 6, 7], 4) 0 - >>> print(fibonacci_search([4, 5, 6, 7], -10)) + >>> fibonacci_search([4, 5, 6, 7], -10) -1 - >>> print(fibonacci_search([-18, 2], -18)) + >>> fibonacci_search([-18, 2], -18) 0 - >>> print(fibonacci_search([5], 5)) + >>> fibonacci_search([5], 5) 0 - >>> print(fibonacci_search(['a', 'c', 'd'], 'c')) + >>> fibonacci_search(['a', 'c', 'd'], 'c') 1 - >>> print(fibonacci_search(['a', 'c', 'd'], 'f')) + >>> fibonacci_search(['a', 'c', 'd'], 'f') -1 - >>> print(fibonacci_search([], 1)) + >>> fibonacci_search([], 1) -1 - >>> print(fibonacci_search([.1, .4 , 7], .4)) + >>> fibonacci_search([.1, .4 , 7], .4) 1 >>> fibonacci_search([], 9) -1 From e941ec0c51dcf379b4fc95e9289a422ad03eaf4c Mon Sep 17 00:00:00 2001 From: Pablo Osorio Lopez Date: Wed, 7 Oct 2020 11:47:01 -0500 Subject: [PATCH 12/13] Refactor iterator to while loop. --- searches/fibonacci_search.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 60cea31d7676..6bff54c015c6 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -10,7 +10,6 @@ For manual testing run: python3 fibonacci_search.py """ -import sys from functools import lru_cache @@ -104,9 +103,12 @@ def fibonacci_search(arr: list, val: int) -> int: """ len_list = len(arr) # Find m such that F_m >= n where F_i is the i_th fibonacci number. - greater_fibb_index = next( - x for x in range(sys.maxsize ** 10) if fibonacci(x) >= len_list - ) + i = 0 + while True: + if fibonacci(i) >= len_list: + greater_fibb_index = i + break + i += 1 fibb_k = greater_fibb_index offset = 0 while fibb_k > 0: From 91c885a5be31126d091a7a608c6f766044bc019d Mon Sep 17 00:00:00 2001 From: Dhruv Date: Thu, 8 Oct 2020 08:59:06 +0530 Subject: [PATCH 13/13] Update searches/fibonacci_search.py --- searches/fibonacci_search.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/searches/fibonacci_search.py b/searches/fibonacci_search.py index 6bff54c015c6..ac8ecc99a187 100644 --- a/searches/fibonacci_search.py +++ b/searches/fibonacci_search.py @@ -106,10 +106,9 @@ def fibonacci_search(arr: list, val: int) -> int: i = 0 while True: if fibonacci(i) >= len_list: - greater_fibb_index = i + fibb_k = i break i += 1 - fibb_k = greater_fibb_index offset = 0 while fibb_k > 0: index_k = min(