From 757c5b30fa61f01f03d4c26cfd5c90677fc4a062 Mon Sep 17 00:00:00 2001 From: Rohit Date: Mon, 31 Oct 2022 00:44:24 +0530 Subject: [PATCH 1/6] Added pascals_triangle.py program to maths directory --- maths/pascals_triangle.py | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 maths/pascals_triangle.py diff --git a/maths/pascals_triangle.py b/maths/pascals_triangle.py new file mode 100644 index 000000000000..cc491416a490 --- /dev/null +++ b/maths/pascals_triangle.py @@ -0,0 +1,64 @@ +""" +This module contains functions for and helpful for generating pascals triangle +""" + + +def pascals_triangle(num_rows: int) -> list: + """ + 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. + The function has O(n^2) time complexity. + :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 + >>> pascals_triangle(3) + [[1], [1, 1], [1, 2, 1]] + >>> pascals_triangle(1) + [[1]] + >>> pascals_triangle(0) + [] + >>> pascals_triangle(-5) + Traceback (most recent call last): + ... + ValueError: The input value of 'num_rows' should be greater than or equal to 0 + >>> pascals_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" + ) + + result = [[1]] + + for i in range(1, num_rows): + temp_row = [0] + result[-1] + [0] + + # unique length calculates the len of pascal's triangle row + # that has distinct elements + # Calculating unique length will be helpful in reducing + # redundant calculations + unique_length = (i + 1) // 2 if (i + 1) % 2 == 0 else (i + 1) // 2 + 1 + row_first_half = [ + temp_row[x - 1] + temp_row[x] for x in range(1, unique_length + 1) + ] + row_second_half = row_first_half[: (i + 1) // 2] + row_second_half.reverse() + row = row_first_half + row_second_half + result.append(row) + + return result + + +if __name__ == "__main__": + from doctest import testmod + testmod() From 6f485ac304e473ef9b65efc2e0d628a9a2b44317 Mon Sep 17 00:00:00 2001 From: Rohit Date: Mon, 31 Oct 2022 11:57:37 +0530 Subject: [PATCH 2/6] Deleted 'pascals_triangle.py' because of duplication. Added a optimized function to generate pascal's triangle to 'pascal_triangle.py' program. Added some aadditional doctests to the existing function. Added some type check functionality to the existing function. --- maths/pascals_triangle.py | 64 ------------------------------ other/pascal_triangle.py | 82 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 64 deletions(-) delete mode 100644 maths/pascals_triangle.py diff --git a/maths/pascals_triangle.py b/maths/pascals_triangle.py deleted file mode 100644 index cc491416a490..000000000000 --- a/maths/pascals_triangle.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -This module contains functions for and helpful for generating pascals triangle -""" - - -def pascals_triangle(num_rows: int) -> list: - """ - 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. - The function has O(n^2) time complexity. - :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 - >>> pascals_triangle(3) - [[1], [1, 1], [1, 2, 1]] - >>> pascals_triangle(1) - [[1]] - >>> pascals_triangle(0) - [] - >>> pascals_triangle(-5) - Traceback (most recent call last): - ... - ValueError: The input value of 'num_rows' should be greater than or equal to 0 - >>> pascals_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" - ) - - result = [[1]] - - for i in range(1, num_rows): - temp_row = [0] + result[-1] + [0] - - # unique length calculates the len of pascal's triangle row - # that has distinct elements - # Calculating unique length will be helpful in reducing - # redundant calculations - unique_length = (i + 1) // 2 if (i + 1) % 2 == 0 else (i + 1) // 2 + 1 - row_first_half = [ - temp_row[x - 1] + temp_row[x] for x in range(1, unique_length + 1) - ] - row_second_half = row_first_half[: (i + 1) // 2] - row_second_half.reverse() - row = row_first_half + row_second_half - result.append(row) - - return result - - -if __name__ == "__main__": - from doctest import testmod - testmod() diff --git a/other/pascal_triangle.py b/other/pascal_triangle.py index 5cc3cee8af56..299111a24f0d 100644 --- a/other/pascal_triangle.py +++ b/other/pascal_triangle.py @@ -38,6 +38,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) @@ -48,7 +50,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) @@ -90,7 +111,68 @@ 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: + """ + 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 + + # It calculates the number of distinct elements in a row + distinct_elements = ( + row_length // 2 if row_length % 2 == 0 else row_length // 2 + 1 + ) + + row_first_half = [ + temp_row[x - 1] + temp_row[x] for x 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 + + if __name__ == "__main__": import doctest + print(generate_pascal_triangle_optimized(5)) doctest.testmod() From 59bffe42618a11d888d25308a66414f808f9ab31 Mon Sep 17 00:00:00 2001 From: Rohit Date: Mon, 31 Oct 2022 12:10:52 +0530 Subject: [PATCH 3/6] Modified type check hints in 'generate_pascal_triangle_optimized' function' q --- other/pascal_triangle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/pascal_triangle.py b/other/pascal_triangle.py index 299111a24f0d..63422b1763e1 100644 --- a/other/pascal_triangle.py +++ b/other/pascal_triangle.py @@ -111,7 +111,7 @@ 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: +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. From 88fa497162205c6d47855295569f08c80437f556 Mon Sep 17 00:00:00 2001 From: Rohit Date: Mon, 31 Oct 2022 12:12:58 +0530 Subject: [PATCH 4/6] Modified 'pascal_triangle' prgram --- other/pascal_triangle.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/other/pascal_triangle.py b/other/pascal_triangle.py index 63422b1763e1..4555c099319f 100644 --- a/other/pascal_triangle.py +++ b/other/pascal_triangle.py @@ -173,6 +173,4 @@ def generate_pascal_triangle_optimized(num_rows: int) -> list[list[int]]: if __name__ == "__main__": import doctest - - print(generate_pascal_triangle_optimized(5)) doctest.testmod() From 4fa2b70dd95db9a8621e631666abf5275498f121 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 06:47:39 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- other/pascal_triangle.py | 1 + 1 file changed, 1 insertion(+) diff --git a/other/pascal_triangle.py b/other/pascal_triangle.py index 4555c099319f..43c477d45750 100644 --- a/other/pascal_triangle.py +++ b/other/pascal_triangle.py @@ -173,4 +173,5 @@ def generate_pascal_triangle_optimized(num_rows: int) -> list[list[int]]: if __name__ == "__main__": import doctest + doctest.testmod() From c90d92ac1fba55dde207264f4d33d40e675a4bd3 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Mon, 31 Oct 2022 17:53:07 +0100 Subject: [PATCH 6/6] Update pascal_triangle.py --- other/pascal_triangle.py | 44 +++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/other/pascal_triangle.py b/other/pascal_triangle.py index 43c477d45750..7f6555f9c8b9 100644 --- a/other/pascal_triangle.py +++ b/other/pascal_triangle.py @@ -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 """ @@ -153,16 +150,11 @@ def generate_pascal_triangle_optimized(num_rows: int) -> list[list[int]]: for row_index in range(1, num_rows): temp_row = [0] + result[-1] + [0] row_length = row_index + 1 - - # It calculates the number of distinct elements in a row - distinct_elements = ( - row_length // 2 if row_length % 2 == 0 else row_length // 2 + 1 - ) - + # Calculate the number of distinct elements in a row + distinct_elements = sum(divmod(row_length, 2)) row_first_half = [ - temp_row[x - 1] + temp_row[x] for x in range(1, distinct_elements + 1) + 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 @@ -171,7 +163,27 @@ def generate_pascal_triangle_optimized(num_rows: int) -> list[list[int]]: 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()