Skip to content

Modified 'pascal_triangle.py' program #7901

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

Merged
merged 6 commits into from
Oct 31, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 101 additions & 8 deletions other/pascal_triangle.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
"""
This implementation demonstrates how to generate the
elements of a Pascal's triangle. The element having
a row index of r and column index of c can be derived
as follows:
This implementation demonstrates how to generate the elements of a Pascal's triangle.
The element havingva row index of r and column index of c can be derivedvas follows:
triangle[r][c] = triangle[r-1][c-1]+triangle[r-1][c]
What is Pascal's triangle?
- It is a triangular array containing binomial coefficients.
Refer to (https://en.wikipedia.org/wiki/Pascal%27s_triangle)
for more info about this triangle.

A Pascal's triangle is a triangular array containing binomial coefficients.
https://en.wikipedia.org/wiki/Pascal%27s_triangle
"""


Expand Down Expand Up @@ -38,6 +35,8 @@ def print_pascal_triangle(num_rows: int) -> None:
def generate_pascal_triangle(num_rows: int) -> list[list[int]]:
"""
Create Pascal's triangle for different number of rows
>>> generate_pascal_triangle(0)
[]
>>> generate_pascal_triangle(1)
[[1]]
>>> generate_pascal_triangle(2)
Expand All @@ -48,7 +47,26 @@ def generate_pascal_triangle(num_rows: int) -> list[list[int]]:
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]]
>>> generate_pascal_triangle(5)
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]
>>> generate_pascal_triangle(-5)
Traceback (most recent call last):
...
ValueError: The input value of 'num_rows' should be greater than or equal to 0
>>> generate_pascal_triangle(7.89)
Traceback (most recent call last):
...
TypeError: The input value of 'num_rows' should be 'int'
"""

if not isinstance(num_rows, int):
raise TypeError("The input value of 'num_rows' should be 'int'")

if num_rows == 0:
return []
elif num_rows < 0:
raise ValueError(
"The input value of 'num_rows' should be greater than or equal to 0"
)

triangle: list[list[int]] = []
for current_row_idx in range(num_rows):
current_row = populate_current_row(triangle, current_row_idx)
Expand Down Expand Up @@ -90,7 +108,82 @@ def calculate_current_element(
current_row[current_col_idx] = above_to_left_elt + above_to_right_elt


def generate_pascal_triangle_optimized(num_rows: int) -> list[list[int]]:
"""
This function returns a matrix representing the corresponding pascal's triangle
according to the given input of number of rows of Pascal's triangle to be generated.
It reduces the operations done to generate a row by half
by eliminating redundant calculations.

:param num_rows: Integer specifying the number of rows in the Pascal's triangle
:return: 2-D List (matrix) representing the Pascal's triangle

Return the Pascal's triangle of given rows
>>> generate_pascal_triangle_optimized(3)
[[1], [1, 1], [1, 2, 1]]
>>> generate_pascal_triangle_optimized(1)
[[1]]
>>> generate_pascal_triangle_optimized(0)
[]
>>> generate_pascal_triangle_optimized(-5)
Traceback (most recent call last):
...
ValueError: The input value of 'num_rows' should be greater than or equal to 0
>>> generate_pascal_triangle_optimized(7.89)
Traceback (most recent call last):
...
TypeError: The input value of 'num_rows' should be 'int'
"""

if not isinstance(num_rows, int):
raise TypeError("The input value of 'num_rows' should be 'int'")

if num_rows == 0:
return []
elif num_rows < 0:
raise ValueError(
"The input value of 'num_rows' should be greater than or equal to 0"
)

result: list[list[int]] = [[1]]

for row_index in range(1, num_rows):
temp_row = [0] + result[-1] + [0]
row_length = row_index + 1
# Calculate the number of distinct elements in a row
distinct_elements = sum(divmod(row_length, 2))
row_first_half = [
temp_row[i - 1] + temp_row[i] for i in range(1, distinct_elements + 1)
]
row_second_half = row_first_half[: (row_index + 1) // 2]
row_second_half.reverse()
row = row_first_half + row_second_half
result.append(row)

return result


def benchmark() -> None:
"""
Benchmark multiple functions, with three different length int values.
"""
from collections.abc import Callable
from timeit import timeit

def benchmark_a_function(func: Callable, value: int) -> None:
call = f"{func.__name__}({value})"
timing = timeit(f"__main__.{call}", setup="import __main__")
# print(f"{call:38} = {func(value)} -- {timing:.4f} seconds")
print(f"{call:38} -- {timing:.4f} seconds")

for value in range(15): # (1, 7, 14):
for func in (generate_pascal_triangle, generate_pascal_triangle_optimized):
benchmark_a_function(func, value)
print()


if __name__ == "__main__":
import doctest

doctest.testmod()
benchmark()