-
-
Notifications
You must be signed in to change notification settings - Fork 47.1k
Adding doctests to improve Test Coverage for dynamic_programming/fibonacci.py #12831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Achintya47
wants to merge
6
commits into
TheAlgorithms:master
Choose a base branch
from
Achintya47:Improve-test-coverage-fibonacci,py
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
dda8aab
Improved Test Coverage for dynamic_programming/fibonacci.py
Achintya47 74826f0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 6cc951a
Update dynamic_programming/fibonacci.py
Achintya47 631037d
Update dynamic_programming/fibonacci.py
Achintya47 c04269f
Update dynamic_programming/fibonacci.py
Achintya47 19c6381
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,236 @@ | ||
""" | ||
This is a pure Python implementation of Dynamic Programming solution to the fibonacci | ||
This is a pure Python implementation of Dynamic Programming solution to the Fibonacci | ||
sequence problem. | ||
|
||
The Fibonacci sequence is a series of numbers where each number is the sum of the | ||
two preceding ones, usually starting with 0 and 1. The sequence begins: | ||
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... | ||
|
||
Reference: https://en.wikipedia.org/wiki/Fibonacci_number | ||
|
||
Time Complexity: O(n) for first calculation, O(1) for subsequent calls with memoization | ||
Space Complexity: O(n) for storing the sequence | ||
""" | ||
|
||
|
||
class Fibonacci: | ||
""" | ||
Dynamic Programming implementation of Fibonacci sequence generator. | ||
|
||
This class maintains a memoized sequence of Fibonacci numbers and can efficiently | ||
generate new numbers by building on previously calculated values. | ||
|
||
Attributes: | ||
sequence (list[int]): Memoized Fibonacci sequence starting with [0, 1] | ||
""" | ||
|
||
def __init__(self) -> None: | ||
"""Initialize the Fibonacci sequence with the first two numbers.""" | ||
self.sequence = [0, 1] | ||
|
||
def get(self, index: int) -> list: | ||
def get(self, index: int) -> list[int]: | ||
""" | ||
Get the Fibonacci number of `index`. If the number does not exist, | ||
calculate all missing numbers leading up to the number of `index`. | ||
Get the first `index` Fibonacci numbers. If numbers don't exist in the sequence, | ||
calculate all missing numbers leading up to the required index. | ||
|
||
Args: | ||
index (int): Number of Fibonacci numbers to return (must be non-negative) | ||
|
||
Returns: | ||
list[int]: List containing the first `index` Fibonacci numbers | ||
|
||
Raises: | ||
ValueError: If index is negative | ||
|
||
Examples: | ||
>>> fib = Fibonacci() | ||
>>> fib.get(0) | ||
[] | ||
>>> fib.get(1) | ||
[0] | ||
>>> fib.get(2) | ||
[0, 1] | ||
>>> fib.get(5) | ||
[0, 1, 1, 2, 3] | ||
>>> fib.get(10) | ||
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] | ||
>>> fib.get(1) # Test memoization - should not recalculate | ||
[0] | ||
>>> fib.get(15) # Test extending existing sequence | ||
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377] | ||
|
||
# Test edge cases | ||
>>> fib_new = Fibonacci() | ||
>>> fib_new.get(0) | ||
[] | ||
>>> fib_new.get(1) | ||
[0] | ||
>>> fib_new.get(2) | ||
[0, 1] | ||
|
||
>>> Fibonacci().get(10) | ||
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] | ||
>>> Fibonacci().get(5) | ||
[0, 1, 1, 2, 3] | ||
# Test error handling | ||
>>> fib_error = Fibonacci() | ||
>>> fib_error.get(-1) | ||
Traceback (most recent call last): | ||
... | ||
ValueError: Index must be non-negative, got -1 | ||
>>> fib_error.get(-5) | ||
Traceback (most recent call last): | ||
... | ||
ValueError: Index must be non-negative, got -5 | ||
|
||
# Test large numbers | ||
>>> fib_large = Fibonacci() | ||
>>> result = fib_large.get(20) | ||
>>> len(result) | ||
20 | ||
>>> result[-1] # 20th Fibonacci number (0-indexed, so 19th position) | ||
4181 | ||
>>> result[0], result[1], result[2] | ||
(0, 1, 1) | ||
|
||
# Test sequence correctness | ||
>>> fib_test = Fibonacci() | ||
>>> seq = fib_test.get(8) | ||
>>> all(seq[i] == seq[i-1] + seq[i-2] for i in range(2, len(seq))) | ||
True | ||
""" | ||
if (difference := index - (len(self.sequence) - 2)) >= 1: | ||
if index < 0: | ||
error_msg = f"Index must be non-negative, got {index}" | ||
raise ValueError(error_msg) | ||
|
||
if index == 0: | ||
return [] | ||
|
||
# Calculate missing numbers if needed | ||
if (difference := index - len(self.sequence)) > 0: | ||
for _ in range(difference): | ||
self.sequence.append(self.sequence[-1] + self.sequence[-2]) | ||
|
||
return self.sequence[:index] | ||
|
||
def get_nth(self, n: int) -> int: | ||
""" | ||
Get the nth Fibonacci number (0-indexed). | ||
|
||
Args: | ||
n (int): The index of the Fibonacci number to retrieve | ||
|
||
Returns: | ||
int: The nth Fibonacci number | ||
|
||
Raises: | ||
ValueError: If n is negative | ||
|
||
Examples: | ||
>>> fib = Fibonacci() | ||
>>> fib.get_nth(0) | ||
0 | ||
>>> fib.get_nth(1) | ||
1 | ||
>>> fib.get_nth(2) | ||
1 | ||
>>> fib.get_nth(5) | ||
5 | ||
>>> fib.get_nth(10) | ||
55 | ||
>>> fib.get_nth(-1) | ||
Traceback (most recent call last): | ||
... | ||
ValueError: Index must be non-negative, got -1 | ||
""" | ||
if n < 0: | ||
error_msg = f"Index must be non-negative, got {n}" | ||
raise ValueError(error_msg) | ||
|
||
# Extend sequence if needed | ||
if n >= len(self.sequence): | ||
difference = n - len(self.sequence) + 1 | ||
for _ in range(difference): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This generation is repeated (lines 107–108), I recommend creating a method to generate the sequence. |
||
self.sequence.append(self.sequence[-1] + self.sequence[-2]) | ||
|
||
return self.sequence[n] | ||
|
||
def reset(self) -> None: | ||
""" | ||
Reset the sequence to its initial state. | ||
|
||
Examples: | ||
>>> fib = Fibonacci() | ||
>>> fib.get(10) | ||
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] | ||
>>> len(fib.sequence) | ||
10 | ||
>>> fib.reset() | ||
>>> fib.sequence | ||
[0, 1] | ||
""" | ||
self.sequence = [0, 1] | ||
|
||
|
||
def main() -> None: | ||
""" | ||
Interactive CLI for generating Fibonacci numbers. | ||
|
||
Allows users to input indices and get the corresponding Fibonacci sequence. | ||
Supports commands: 'exit', 'quit', 'reset', 'help' | ||
""" | ||
print( | ||
"Fibonacci Series Using Dynamic Programming\n", | ||
"Enter the index of the Fibonacci number you want to calculate ", | ||
"in the prompt below. (To exit enter exit or Ctrl-C)\n", | ||
sep="", | ||
"Fibonacci Series Using Dynamic Programming\n" | ||
"Enter the index of the Fibonacci number you want to calculate\n" | ||
"Commands: 'exit'/'quit' to exit, 'reset' to clear cache, 'help' for help\n" | ||
) | ||
|
||
fibonacci = Fibonacci() | ||
|
||
while True: | ||
prompt: str = input(">> ") | ||
if prompt in {"exit", "quit"}: | ||
break | ||
|
||
try: | ||
index: int = int(prompt) | ||
except ValueError: | ||
print("Enter a number or 'exit'") | ||
continue | ||
prompt: str = input(">> ").strip().lower() | ||
|
||
if prompt in {"exit", "quit"}: | ||
print("Goodbye!") | ||
break | ||
elif prompt == "reset": | ||
fibonacci.reset() | ||
print("Fibonacci sequence cache cleared.") | ||
continue | ||
elif prompt == "help": | ||
print( | ||
"Commands:\n" | ||
" <number> - Get first N Fibonacci numbers\n" | ||
" reset - Clear the memoized sequence\n" | ||
" help - Show this help message\n" | ||
" exit/quit - Exit the program\n" | ||
) | ||
continue | ||
elif prompt == "": | ||
continue | ||
|
||
print(fibonacci.get(index)) | ||
try: | ||
index: int = int(prompt) | ||
if index < 0: | ||
print("Please enter a non-negative number.") | ||
continue | ||
|
||
result = fibonacci.get(index) | ||
if not result: | ||
print("[]") | ||
else: | ||
print(f"First {index} Fibonacci numbers: {result}") | ||
if index > 0: | ||
print( | ||
f"The {index}th Fibonacci number is: {fibonacci.get_nth(index)}" | ||
) | ||
|
||
except ValueError: | ||
print("Invalid input. Enter a number or use 'help' for commands.") | ||
|
||
except KeyboardInterrupt: | ||
print("\nGoodbye!") | ||
break | ||
except EOFError: | ||
print("\nGoodbye!") | ||
break | ||
|
||
|
||
if __name__ == "__main__": | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.