From cb04a9388cc96c36735ca795eb64bcecf26d2d13 Mon Sep 17 00:00:00 2001 From: bluedistro Date: Wed, 25 Dec 2019 12:11:43 +0000 Subject: [PATCH 1/6] added dijkstra's bankers algorithm implementation to 'other' directory --- other/dijkstra_bankers_algorithm.py | 184 ++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 other/dijkstra_bankers_algorithm.py diff --git a/other/dijkstra_bankers_algorithm.py b/other/dijkstra_bankers_algorithm.py new file mode 100644 index 000000000000..0fc88454b439 --- /dev/null +++ b/other/dijkstra_bankers_algorithm.py @@ -0,0 +1,184 @@ +# A python implementation of the Banker's Algorithm in Operating Systems using +# Processes and Resources +# { +# "Author: "Biney Kingsley (bluedistro@github.io)", +# "Date": 28-10-2018 +# } +''' +The Banker's algorithm is a resource allocation and deadlock avoidance algorithm +developed by Edsger Dijkstra that tests for safety by simulating the allocation of +predetermined maximum possible amounts of all resources, and then makes a "s-state" +check to test for possible deadlock conditions for all other pending activities, +before deciding whether allocation should be allowed to continue. +[Source] Wikipedia +[Credit] Rosetta Code C implementation helped very much. + (https://rosettacode.org/wiki/Banker%27s_algorithm) +''' + +from __future__ import print_function +import numpy as np +import time + + +class Bankers_algorithm: + + def __init__(self, claim_vector, allocated_resources_table, maximum_claim_table): + ''' + :param claim_vector: The maximum (in values) amount of each resources + (eg. memory, interface, semaphores, etc.) available. + :param allocated_resources_table: How much (in value) of each resource + each process is currently holding + :param maximum_claim_table: How much of each resource the system + currently has available + ''' + self.__claim_vector = claim_vector + self.__allocated_resources_table = allocated_resources_table + self.__maximum_claim_table = maximum_claim_table + + # check for allocated resources in line with each resource in the claim vector + def __processes_resource_summation(self): + allocated_resources = list() + for i in range(len(self.__allocated_resources_table[0])): + # dummy to perform addition of specific resources + sum = 0 + for p_item in self.__allocated_resources_table: + sum += p_item[i] + allocated_resources.append(sum) + return allocated_resources + + # check for available resources in line with each resource in the claim vector + def __available_resources(self): + return np.array(self.__claim_vector) - np.array(self.__processes_resource_summation()) + + # implement safety checker by ensuring that max_claim[i][j] - alloc_table[i][j] <= avail[j] + # in order words, calculating for the needs + def __need(self): + need = list() + for i in range(len(self.__allocated_resources_table)): + need.append(list(np.array(self.__maximum_claim_table[i]) + - np.array(self.__allocated_resources_table[i]))) + return need + + # build an index control dictionary to track original ids/indices + # of processes during removals in core operation + def __need_index_manager(self): + ni_manager = dict() + for i in self.__need(): + ni_manager.update({self.__need().index(i): i}) + return ni_manager + + # core operation of the banker's algorithm + def main(self, **kwargs): + need_list = self.__need() + alloc_resources_table = self.__allocated_resources_table + available_resources = self.__available_resources() + need_index_manager = self.__need_index_manager() + # display information if needed + # get the parameter that handles display + for kw, val in kwargs.items(): + if kw and val is True: + self.__pretty_data() + elif kw and val is False: + print ("[Warning] Muting data description.\n") + else: + print ("[Warning] Muting data description.\n") + print("{:_^50}\n".format("_")) + while len(need_list) != 0: + safe = False + for each_need in need_list: + execution = True + for i in range(len(each_need)): + if each_need[i] > available_resources[i]: + execution = False + break + + if execution: + safe = True + # get the original index of the process from ind_ctrl db + for original_need_index, need_clone in need_index_manager.items(): + if each_need == need_clone: + process_number = original_need_index + # display the process id based on entry + print('Process {} is executing.'.format(process_number + 1)) + # remove the process run from stack + need_list.remove(each_need) + # update available/freed resources stack + available_resources = np.array(available_resources) + \ + np.array(alloc_resources_table[process_number]) + # display available memory + print("Updated available resource stack for processes: {}" + .format(" ".join([str(x) for x in available_resources]))) + break + else: + pass + + if safe: + print("The process is in a safe state.\n") + + if not safe: + print("System in unsafe state. Aborting...\n") + break + + # pretty display description of the allocated, maximum and claim + # vector of the resources available + def __pretty_data(self): + + # Information on Allocation Resource Table + print("{:>8}".format(" Allocated Resource Table")) + # print("{:^11} {:^8} {:^8} {:^8} {:^8}".format(" A", "B", "C", "D", "E")) + # print("{:_^11} {:_^8} {:_^8} {:_^8} {:_^8}".format(" ", "_", "_", "_", "_")) + for item in self.__allocated_resources_table: + print("P{}".format(str(self.__allocated_resources_table.index(item) + 1)), end=" ") + for it in item: + print("{:^8}".format(it), end=" ") + print("\n") + + # Information on Current System Resources + print("{:>8}".format(" System Resource Table")) + # print("{:^11} {:^8} {:^8} {:^8} {:^8}".format(" A", "B", "C", "D", "E")) + # print("{:_^11} {:_^8} {:_^8} {:_^8} {:_^8}".format(" ", "_", "_", "_", "_")) + for item in self.__maximum_claim_table: + print("P{}".format(str(self.__maximum_claim_table.index(item) + 1)), end=" ") + for it in item: + print("{:^8}".format(it), end=" ") + print("\n") + + # Information on Current Resource Usage by processes + print("Current Usage by Active Processes: {:>11}" + .format(str(" ".join([str(x) for x in self.__claim_vector])))) + # Information on Current Resource Usage by processes + print("Initial Available Resources: {:>15}" + .format(str(" ".join([str(x) for x in + self.__available_resources()])))) + # make table visible during display + time.sleep(1) + + +# test algorithm +def main(): + # test 1 + test_1_claim_vector = [8, 5, 9, 7] + test_1_allocated_res_table = [[2, 0, 1, 1], + [0, 1, 2, 1], + [4, 0, 0, 3], + [0, 2, 1, 0], + [1, 0, 3, 0]] + test_1_maximum_claim_table = [[3, 2, 1, 4], + [0, 2, 5, 2], + [5, 1, 0, 5], + [1, 5, 3, 0], + [3, 0, 3, 3]] + # test 2 + test_2_claim_vector = [6, 5, 7, 6] + test_2_allocated_res_table = [[1, 2, 2, 1], + [1, 0, 3, 3], + [1, 2, 1, 0]] + test_2_maximum_claim_table = [[3, 3, 2, 2], + [1, 2, 3, 4], + [1, 3, 5, 0]] + + Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, + test_1_maximum_claim_table).main(describe=True) + +if __name__ == "__main__": + main() \ No newline at end of file From 23476c483a153075f1bd15c81a200b9da9a8942d Mon Sep 17 00:00:00 2001 From: bluedistro Date: Wed, 25 Dec 2019 20:37:17 +0000 Subject: [PATCH 2/6] Applied all requested changes --- other/dijkstra_bankers_algorithm.py | 147 ++++++++++++++++++---------- 1 file changed, 98 insertions(+), 49 deletions(-) diff --git a/other/dijkstra_bankers_algorithm.py b/other/dijkstra_bankers_algorithm.py index 0fc88454b439..893c6eda341b 100644 --- a/other/dijkstra_bankers_algorithm.py +++ b/other/dijkstra_bankers_algorithm.py @@ -1,7 +1,7 @@ -# A python implementation of the Banker's Algorithm in Operating Systems using +# A Python implementation of the Banker's Algorithm in Operating Systems using # Processes and Resources # { -# "Author: "Biney Kingsley (bluedistro@github.io)", +# "Author: "Biney Kingsley (bluedistro@github.io), bineykingsley36@gmail.com", # "Date": 28-10-2018 # } ''' @@ -15,80 +15,143 @@ (https://rosettacode.org/wiki/Banker%27s_algorithm) ''' -from __future__ import print_function import numpy as np import time class Bankers_algorithm: - def __init__(self, claim_vector, allocated_resources_table, maximum_claim_table): + def __init__(self, claim_vector: list, allocated_resources_table: list, maximum_claim_table: list) -> None: ''' - :param claim_vector: The maximum (in values) amount of each resources + :param claim_vector: A nxn/nxm list depicting the amount of each resources (eg. memory, interface, semaphores, etc.) available. - :param allocated_resources_table: How much (in value) of each resource + :param allocated_resources_table: A nxn/nxm list depicting the amount of each resource each process is currently holding - :param maximum_claim_table: How much of each resource the system + :param maximum_claim_table: A nxn/nxm list depicting how much of each resource the system currently has available ''' self.__claim_vector = claim_vector self.__allocated_resources_table = allocated_resources_table self.__maximum_claim_table = maximum_claim_table - # check for allocated resources in line with each resource in the claim vector - def __processes_resource_summation(self): + def __processes_resource_summation(self) -> list: + ''' + This method checks for allocated resources in line with each resource in the claim vector + ''' allocated_resources = list() for i in range(len(self.__allocated_resources_table[0])): - # dummy to perform addition of specific resources sum = 0 for p_item in self.__allocated_resources_table: sum += p_item[i] allocated_resources.append(sum) return allocated_resources - # check for available resources in line with each resource in the claim vector - def __available_resources(self): + def __available_resources(self) -> list: + ''' + This method checks for available resources in line with each resource in the claim vector + ''' return np.array(self.__claim_vector) - np.array(self.__processes_resource_summation()) - # implement safety checker by ensuring that max_claim[i][j] - alloc_table[i][j] <= avail[j] - # in order words, calculating for the needs - def __need(self): + def __need(self) -> list: + ''' + This method implements safety checker by ensuring that + max_claim[i][j] - alloc_table[i][j] <= avail[j] + In order words, calculating for the needs + ''' need = list() for i in range(len(self.__allocated_resources_table)): need.append(list(np.array(self.__maximum_claim_table[i]) - np.array(self.__allocated_resources_table[i]))) return need - # build an index control dictionary to track original ids/indices - # of processes during removals in core operation - def __need_index_manager(self): + def __need_index_manager(self) -> dict: + ''' + This function builds an index control dictionary to track original ids/indices + of processes when altered during execution of method "main" + Return: {0: [a: int, b: int], 1: [c: int, d: int]} + >>> __need_index_manager([[1, 2, 0, 3], [0, 1, 3, 1], [1, 1, 0, 2], [1, 3, 2, 0], [2, 0, 0, 3]]) + {0: [1, 2, 0, 3], 1: [0, 1, 3, 1], 2: [1, 1, 0, 2], 3: [1, 3, 2, 0], 4: [2, 0, 0, 3]} + >>> __need_index_manager([[1, 3, 0, 1], [2, 0, 3, 1], [1, 0, 3, 2], [1, 1, 2, 3], [2, 1, 2, 3]]) + {0: [1, 3, 0, 1], 1: [2, 0, 3, 1], 2: [1, 0, 3, 2], 3: [1, 1, 2, 3], 4: [2, 1, 2, 3]} + ''' ni_manager = dict() for i in self.__need(): ni_manager.update({self.__need().index(i): i}) return ni_manager - # core operation of the banker's algorithm - def main(self, **kwargs): + def main(self, **kwargs) -> None: + ''' + This method utilized the various methods in this class to simulate the Banker's algorithm + Return: None + >>> Bankers_algorithm([8, 5, 9, 7], [[2, 0, 1, 1], + [0, 1, 2, 1], + [4, 0, 0, 3], + [0, 2, 1, 0], + [1, 0, 3, 0]], [[3, 2, 1, 4], + [0, 2, 5, 2], + [5, 1, 0, 5], + [1, 5, 3, 0], + [3, 0, 3, 3]]).main(describe=true) + Allocated Resource Table + P1 2 0 1 1 + + P2 0 1 2 1 + + P3 4 0 0 3 + + P4 0 2 1 0 + + P5 1 0 3 0 + + System Resource Table + P1 3 2 1 4 + + P2 0 2 5 2 + + P3 5 1 0 5 + + P4 1 5 3 0 + + P5 3 0 3 3 + + Current Usage by Active Processes: 8 5 9 7 + Initial Available Resources: 1 2 2 2 + __________________________________________________ + + Process 3 is executing. + Updated available resource stack for processes: 5 2 2 5 + The process is in a safe state. + + Process 1 is executing. + Updated available resource stack for processes: 7 2 3 6 + The process is in a safe state. + + Process 2 is executing. + Updated available resource stack for processes: 7 3 5 7 + The process is in a safe state. + + Process 4 is executing. + Updated available resource stack for processes: 7 5 6 7 + The process is in a safe state. + + Process 5 is executing. + Updated available resource stack for processes: 8 5 9 7 + The process is in a safe state. + ''' need_list = self.__need() alloc_resources_table = self.__allocated_resources_table available_resources = self.__available_resources() need_index_manager = self.__need_index_manager() - # display information if needed - # get the parameter that handles display for kw, val in kwargs.items(): if kw and val is True: self.__pretty_data() - elif kw and val is False: - print ("[Warning] Muting data description.\n") - else: - print ("[Warning] Muting data description.\n") print("{:_^50}\n".format("_")) while len(need_list) != 0: safe = False for each_need in need_list: execution = True - for i in range(len(each_need)): - if each_need[i] > available_resources[i]: + for index, need in enumerate(each_need): + if need > available_resources[index]: execution = False break @@ -98,64 +161,50 @@ def main(self, **kwargs): for original_need_index, need_clone in need_index_manager.items(): if each_need == need_clone: process_number = original_need_index - # display the process id based on entry print('Process {} is executing.'.format(process_number + 1)) # remove the process run from stack need_list.remove(each_need) # update available/freed resources stack available_resources = np.array(available_resources) + \ np.array(alloc_resources_table[process_number]) - # display available memory print("Updated available resource stack for processes: {}" .format(" ".join([str(x) for x in available_resources]))) break - else: - pass - if safe: print("The process is in a safe state.\n") - - if not safe: + else: print("System in unsafe state. Aborting...\n") break - # pretty display description of the allocated, maximum and claim - # vector of the resources available def __pretty_data(self): - - # Information on Allocation Resource Table + ''' + Properly align display of the algorithm's solution + ''' print("{:>8}".format(" Allocated Resource Table")) - # print("{:^11} {:^8} {:^8} {:^8} {:^8}".format(" A", "B", "C", "D", "E")) - # print("{:_^11} {:_^8} {:_^8} {:_^8} {:_^8}".format(" ", "_", "_", "_", "_")) for item in self.__allocated_resources_table: print("P{}".format(str(self.__allocated_resources_table.index(item) + 1)), end=" ") for it in item: print("{:^8}".format(it), end=" ") print("\n") - # Information on Current System Resources print("{:>8}".format(" System Resource Table")) - # print("{:^11} {:^8} {:^8} {:^8} {:^8}".format(" A", "B", "C", "D", "E")) - # print("{:_^11} {:_^8} {:_^8} {:_^8} {:_^8}".format(" ", "_", "_", "_", "_")) for item in self.__maximum_claim_table: print("P{}".format(str(self.__maximum_claim_table.index(item) + 1)), end=" ") for it in item: print("{:^8}".format(it), end=" ") print("\n") - # Information on Current Resource Usage by processes print("Current Usage by Active Processes: {:>11}" .format(str(" ".join([str(x) for x in self.__claim_vector])))) - # Information on Current Resource Usage by processes + print("Initial Available Resources: {:>15}" .format(str(" ".join([str(x) for x in self.__available_resources()])))) - # make table visible during display time.sleep(1) # test algorithm -def main(): +def test(): # test 1 test_1_claim_vector = [8, 5, 9, 7] test_1_allocated_res_table = [[2, 0, 1, 1], @@ -181,4 +230,4 @@ def main(): test_1_maximum_claim_table).main(describe=True) if __name__ == "__main__": - main() \ No newline at end of file + test() From e82875b36c6c881f5476773a0543548bf82e07a6 Mon Sep 17 00:00:00 2001 From: bluedistro Date: Wed, 25 Dec 2019 20:43:41 +0000 Subject: [PATCH 3/6] fixed indentation bug --- other/dijkstra_bankers_algorithm.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/other/dijkstra_bankers_algorithm.py b/other/dijkstra_bankers_algorithm.py index 893c6eda341b..917adec79951 100644 --- a/other/dijkstra_bankers_algorithm.py +++ b/other/dijkstra_bankers_algorithm.py @@ -53,15 +53,15 @@ def __available_resources(self) -> list: return np.array(self.__claim_vector) - np.array(self.__processes_resource_summation()) def __need(self) -> list: - ''' - This method implements safety checker by ensuring that - max_claim[i][j] - alloc_table[i][j] <= avail[j] - In order words, calculating for the needs - ''' + ''' + This method implements safety checker by ensuring that + max_claim[i][j] - alloc_table[i][j] <= avail[j] + In order words, calculating for the needs + ''' need = list() for i in range(len(self.__allocated_resources_table)): need.append(list(np.array(self.__maximum_claim_table[i]) - - np.array(self.__allocated_resources_table[i]))) + - np.array(self.__allocated_resources_table[i]))) return need def __need_index_manager(self) -> dict: From 783f0fa96f5ad9f0fb370a3c1a690d1a6c593be7 Mon Sep 17 00:00:00 2001 From: bluedistro Date: Wed, 25 Dec 2019 21:35:31 +0000 Subject: [PATCH 4/6] included passing doctests --- other/dijkstra_bankers_algorithm.py | 69 +++++++++++++++++------------ 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/other/dijkstra_bankers_algorithm.py b/other/dijkstra_bankers_algorithm.py index 917adec79951..b264e7b4193d 100644 --- a/other/dijkstra_bankers_algorithm.py +++ b/other/dijkstra_bankers_algorithm.py @@ -69,10 +69,11 @@ def __need_index_manager(self) -> dict: This function builds an index control dictionary to track original ids/indices of processes when altered during execution of method "main" Return: {0: [a: int, b: int], 1: [c: int, d: int]} - >>> __need_index_manager([[1, 2, 0, 3], [0, 1, 3, 1], [1, 1, 0, 2], [1, 3, 2, 0], [2, 0, 0, 3]]) + >>> test_1_claim_vector = [8, 5, 9, 7] + >>> test_1_allocated_res_table = [[2, 0, 1, 1],[0, 1, 2, 1],[4, 0, 0, 3],[0, 2, 1, 0],[1, 0, 3, 0]] + >>> test_1_maximum_claim_table = [[3, 2, 1, 4],[0, 2, 5, 2],[5, 1, 0, 5],[1, 5, 3, 0],[3, 0, 3, 3]] + >>> Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, test_1_maximum_claim_table)._Bankers_algorithm__need_index_manager() {0: [1, 2, 0, 3], 1: [0, 1, 3, 1], 2: [1, 1, 0, 2], 3: [1, 3, 2, 0], 4: [2, 0, 0, 3]} - >>> __need_index_manager([[1, 3, 0, 1], [2, 0, 3, 1], [1, 0, 3, 2], [1, 1, 2, 3], [2, 1, 2, 3]]) - {0: [1, 3, 0, 1], 1: [2, 0, 3, 1], 2: [1, 0, 3, 2], 3: [1, 1, 2, 3], 4: [2, 1, 2, 3]} ''' ni_manager = dict() for i in self.__need(): @@ -83,60 +84,56 @@ def main(self, **kwargs) -> None: ''' This method utilized the various methods in this class to simulate the Banker's algorithm Return: None - >>> Bankers_algorithm([8, 5, 9, 7], [[2, 0, 1, 1], - [0, 1, 2, 1], - [4, 0, 0, 3], - [0, 2, 1, 0], - [1, 0, 3, 0]], [[3, 2, 1, 4], - [0, 2, 5, 2], - [5, 1, 0, 5], - [1, 5, 3, 0], - [3, 0, 3, 3]]).main(describe=true) + >>> test_1_claim_vector = [8, 5, 9, 7] + >>> test_1_allocated_res_table = [[2, 0, 1, 1],[0, 1, 2, 1],[4, 0, 0, 3],[0, 2, 1, 0],[1, 0, 3, 0]] + >>> test_1_maximum_claim_table = [[3, 2, 1, 4],[0, 2, 5, 2],[5, 1, 0, 5],[1, 5, 3, 0],[3, 0, 3, 3]] + >>> Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, test_1_maximum_claim_table).main(describe=True) Allocated Resource Table P1 2 0 1 1 - + P2 0 1 2 1 - + P3 4 0 0 3 - + P4 0 2 1 0 - + P5 1 0 3 0 - - System Resource Table + + System Resource Table P1 3 2 1 4 - + P2 0 2 5 2 - + P3 5 1 0 5 - + P4 1 5 3 0 - + P5 3 0 3 3 - + Current Usage by Active Processes: 8 5 9 7 Initial Available Resources: 1 2 2 2 __________________________________________________ - + Process 3 is executing. Updated available resource stack for processes: 5 2 2 5 The process is in a safe state. - + Process 1 is executing. Updated available resource stack for processes: 7 2 3 6 The process is in a safe state. - + Process 2 is executing. Updated available resource stack for processes: 7 3 5 7 The process is in a safe state. - + Process 4 is executing. Updated available resource stack for processes: 7 5 6 7 The process is in a safe state. - + Process 5 is executing. Updated available resource stack for processes: 8 5 9 7 - The process is in a safe state. + The process is in a safe state. + ''' need_list = self.__need() alloc_resources_table = self.__allocated_resources_table @@ -230,4 +227,18 @@ def test(): test_1_maximum_claim_table).main(describe=True) if __name__ == "__main__": + import doctest + test_1_claim_vector = [8, 5, 9, 7] + test_1_allocated_res_table = [[2, 0, 1, 1], + [0, 1, 2, 1], + [4, 0, 0, 3], + [0, 2, 1, 0], + [1, 0, 3, 0]] + test_1_maximum_claim_table = [[3, 2, 1, 4], + [0, 2, 5, 2], + [5, 1, 0, 5], + [1, 5, 3, 0], + [3, 0, 3, 3]] + doctest.testmod(extraglobs={'m': Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, + test_1_maximum_claim_table).main(describe=True)}) test() From f0aa6f30d8794d6ad42be3d1343182133cc050f2 Mon Sep 17 00:00:00 2001 From: bluedistro Date: Wed, 25 Dec 2019 22:04:48 +0000 Subject: [PATCH 5/6] replaced backslashes in print statements with empty print statements and changed class naming convention to CamelCase --- other/dijkstra_bankers_algorithm.py | 51 ++++++++--------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/other/dijkstra_bankers_algorithm.py b/other/dijkstra_bankers_algorithm.py index b264e7b4193d..5c0ccaba40ca 100644 --- a/other/dijkstra_bankers_algorithm.py +++ b/other/dijkstra_bankers_algorithm.py @@ -19,7 +19,7 @@ import time -class Bankers_algorithm: +class BankersAlgorithm: def __init__(self, claim_vector: list, allocated_resources_table: list, maximum_claim_table: list) -> None: ''' @@ -72,7 +72,7 @@ def __need_index_manager(self) -> dict: >>> test_1_claim_vector = [8, 5, 9, 7] >>> test_1_allocated_res_table = [[2, 0, 1, 1],[0, 1, 2, 1],[4, 0, 0, 3],[0, 2, 1, 0],[1, 0, 3, 0]] >>> test_1_maximum_claim_table = [[3, 2, 1, 4],[0, 2, 5, 2],[5, 1, 0, 5],[1, 5, 3, 0],[3, 0, 3, 3]] - >>> Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, test_1_maximum_claim_table)._Bankers_algorithm__need_index_manager() + >>> BankersAlgorithm(test_1_claim_vector, test_1_allocated_res_table, test_1_maximum_claim_table)._BankersAlgorithm__need_index_manager() {0: [1, 2, 0, 3], 1: [0, 1, 3, 1], 2: [1, 1, 0, 2], 3: [1, 3, 2, 0], 4: [2, 0, 0, 3]} ''' ni_manager = dict() @@ -87,7 +87,7 @@ def main(self, **kwargs) -> None: >>> test_1_claim_vector = [8, 5, 9, 7] >>> test_1_allocated_res_table = [[2, 0, 1, 1],[0, 1, 2, 1],[4, 0, 0, 3],[0, 2, 1, 0],[1, 0, 3, 0]] >>> test_1_maximum_claim_table = [[3, 2, 1, 4],[0, 2, 5, 2],[5, 1, 0, 5],[1, 5, 3, 0],[3, 0, 3, 3]] - >>> Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, test_1_maximum_claim_table).main(describe=True) + >>> BankersAlgorithm(test_1_claim_vector, test_1_allocated_res_table, test_1_maximum_claim_table).main(describe=True) Allocated Resource Table P1 2 0 1 1 @@ -142,7 +142,8 @@ def main(self, **kwargs) -> None: for kw, val in kwargs.items(): if kw and val is True: self.__pretty_data() - print("{:_^50}\n".format("_")) + print("{:_^50}".format("_")) + print() while len(need_list) != 0: safe = False for each_need in need_list: @@ -168,9 +169,11 @@ def main(self, **kwargs) -> None: .format(" ".join([str(x) for x in available_resources]))) break if safe: - print("The process is in a safe state.\n") + print("The process is in a safe state.") + print() else: - print("System in unsafe state. Aborting...\n") + print("System in unsafe state. Aborting...") + print() break def __pretty_data(self): @@ -182,14 +185,16 @@ def __pretty_data(self): print("P{}".format(str(self.__allocated_resources_table.index(item) + 1)), end=" ") for it in item: print("{:^8}".format(it), end=" ") - print("\n") + print() + print() print("{:>8}".format(" System Resource Table")) for item in self.__maximum_claim_table: print("P{}".format(str(self.__maximum_claim_table.index(item) + 1)), end=" ") for it in item: print("{:^8}".format(it), end=" ") - print("\n") + print() + print() print("Current Usage by Active Processes: {:>11}" .format(str(" ".join([str(x) for x in self.__claim_vector])))) @@ -199,33 +204,6 @@ def __pretty_data(self): self.__available_resources()])))) time.sleep(1) - -# test algorithm -def test(): - # test 1 - test_1_claim_vector = [8, 5, 9, 7] - test_1_allocated_res_table = [[2, 0, 1, 1], - [0, 1, 2, 1], - [4, 0, 0, 3], - [0, 2, 1, 0], - [1, 0, 3, 0]] - test_1_maximum_claim_table = [[3, 2, 1, 4], - [0, 2, 5, 2], - [5, 1, 0, 5], - [1, 5, 3, 0], - [3, 0, 3, 3]] - # test 2 - test_2_claim_vector = [6, 5, 7, 6] - test_2_allocated_res_table = [[1, 2, 2, 1], - [1, 0, 3, 3], - [1, 2, 1, 0]] - test_2_maximum_claim_table = [[3, 3, 2, 2], - [1, 2, 3, 4], - [1, 3, 5, 0]] - - Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, - test_1_maximum_claim_table).main(describe=True) - if __name__ == "__main__": import doctest test_1_claim_vector = [8, 5, 9, 7] @@ -239,6 +217,5 @@ def test(): [5, 1, 0, 5], [1, 5, 3, 0], [3, 0, 3, 3]] - doctest.testmod(extraglobs={'m': Bankers_algorithm(test_1_claim_vector, test_1_allocated_res_table, + doctest.testmod(extraglobs={'m': BankersAlgorithm(test_1_claim_vector, test_1_allocated_res_table, test_1_maximum_claim_table).main(describe=True)}) - test() From 00c250ac05a1e85abcda8fdb6de38785ee2a33b0 Mon Sep 17 00:00:00 2001 From: bluedistro Date: Sat, 28 Dec 2019 14:22:03 +0000 Subject: [PATCH 6/6] formatted code with black --- dynamic_programming/FloydWarshall.py | 49 ++++---- dynamic_programming/coin_change.py | 5 +- dynamic_programming/edit_distance.py | 67 ++++++----- dynamic_programming/fibonacci.py | 10 +- dynamic_programming/integer_partition.py | 69 +++++------ .../k_means_clustering_tensorflow.py | 110 +++++++++--------- dynamic_programming/knapsack.py | 46 ++++---- .../longest_common_subsequence.py | 14 ++- .../longest_increasing_subsequence.py | 70 +++++------ ...longest_increasing_subsequence_O(nlogn).py | 61 +++++----- dynamic_programming/longest_sub_array.py | 22 ++-- dynamic_programming/matrix_chain_order.py | 66 ++++++----- dynamic_programming/max_sub_array.py | 90 +++++++------- dynamic_programming/minimum_partition.py | 24 ++-- 14 files changed, 375 insertions(+), 328 deletions(-) diff --git a/dynamic_programming/FloydWarshall.py b/dynamic_programming/FloydWarshall.py index 038499ca03b6..a4b6c6a82568 100644 --- a/dynamic_programming/FloydWarshall.py +++ b/dynamic_programming/FloydWarshall.py @@ -1,37 +1,42 @@ import math + class Graph: - - def __init__(self, N = 0): # a graph with Node 0,1,...,N-1 + def __init__(self, N=0): # a graph with Node 0,1,...,N-1 self.N = N - self.W = [[math.inf for j in range(0,N)] for i in range(0,N)] # adjacency matrix for weight - self.dp = [[math.inf for j in range(0,N)] for i in range(0,N)] # dp[i][j] stores minimum distance from i to j + self.W = [ + [math.inf for j in range(0, N)] for i in range(0, N) + ] # adjacency matrix for weight + self.dp = [ + [math.inf for j in range(0, N)] for i in range(0, N) + ] # dp[i][j] stores minimum distance from i to j def addEdge(self, u, v, w): self.dp[u][v] = w def floyd_warshall(self): - for k in range(0,self.N): - for i in range(0,self.N): - for j in range(0,self.N): + for k in range(0, self.N): + for i in range(0, self.N): + for j in range(0, self.N): self.dp[i][j] = min(self.dp[i][j], self.dp[i][k] + self.dp[k][j]) def showMin(self, u, v): return self.dp[u][v] - -if __name__ == '__main__': + + +if __name__ == "__main__": graph = Graph(5) - graph.addEdge(0,2,9) - graph.addEdge(0,4,10) - graph.addEdge(1,3,5) - graph.addEdge(2,3,7) - graph.addEdge(3,0,10) - graph.addEdge(3,1,2) - graph.addEdge(3,2,1) - graph.addEdge(3,4,6) - graph.addEdge(4,1,3) - graph.addEdge(4,2,4) - graph.addEdge(4,3,9) + graph.addEdge(0, 2, 9) + graph.addEdge(0, 4, 10) + graph.addEdge(1, 3, 5) + graph.addEdge(2, 3, 7) + graph.addEdge(3, 0, 10) + graph.addEdge(3, 1, 2) + graph.addEdge(3, 2, 1) + graph.addEdge(3, 4, 6) + graph.addEdge(4, 1, 3) + graph.addEdge(4, 2, 4) + graph.addEdge(4, 3, 9) graph.floyd_warshall() - graph.showMin(1,4) - graph.showMin(0,3) + graph.showMin(1, 4) + graph.showMin(0, 3) diff --git a/dynamic_programming/coin_change.py b/dynamic_programming/coin_change.py index 0116df0c024e..ed3fc99a8feb 100644 --- a/dynamic_programming/coin_change.py +++ b/dynamic_programming/coin_change.py @@ -6,6 +6,8 @@ https://www.hackerrank.com/challenges/coin-change/problem """ from __future__ import print_function + + def dp_count(S, m, n): table = [0] * (n + 1) @@ -21,6 +23,7 @@ def dp_count(S, m, n): return table[n] -if __name__ == '__main__': + +if __name__ == "__main__": print(dp_count([1, 2, 3], 3, 4)) # answer 4 print(dp_count([2, 5, 3, 6], 4, 10)) # answer 5 diff --git a/dynamic_programming/edit_distance.py b/dynamic_programming/edit_distance.py index 335e5196ed53..d0d1ab3d8a01 100644 --- a/dynamic_programming/edit_distance.py +++ b/dynamic_programming/edit_distance.py @@ -20,56 +20,61 @@ class EditDistance: def __init__(self): self.__prepare__() - def __prepare__(self, N = 0, M = 0): - self.dp = [[-1 for y in range(0,M)] for x in range(0,N)] + def __prepare__(self, N=0, M=0): + self.dp = [[-1 for y in range(0, M)] for x in range(0, N)] def __solveDP(self, x, y): - if (x==-1): - return y+1 - elif (y==-1): - return x+1 - elif (self.dp[x][y]>-1): + if x == -1: + return y + 1 + elif y == -1: + return x + 1 + elif self.dp[x][y] > -1: return self.dp[x][y] else: - if (self.A[x]==self.B[y]): - self.dp[x][y] = self.__solveDP(x-1,y-1) + if self.A[x] == self.B[y]: + self.dp[x][y] = self.__solveDP(x - 1, y - 1) else: - self.dp[x][y] = 1+min(self.__solveDP(x,y-1), self.__solveDP(x-1,y), self.__solveDP(x-1,y-1)) + self.dp[x][y] = 1 + min( + self.__solveDP(x, y - 1), + self.__solveDP(x - 1, y), + self.__solveDP(x - 1, y - 1), + ) return self.dp[x][y] def solve(self, A, B): - if isinstance(A,bytes): - A = A.decode('ascii') + if isinstance(A, bytes): + A = A.decode("ascii") - if isinstance(B,bytes): - B = B.decode('ascii') + if isinstance(B, bytes): + B = B.decode("ascii") self.A = str(A) self.B = str(B) self.__prepare__(len(A), len(B)) - return self.__solveDP(len(A)-1, len(B)-1) + return self.__solveDP(len(A) - 1, len(B) - 1) -if __name__ == '__main__': - try: - raw_input # Python 2 - except NameError: - raw_input = input # Python 3 - solver = EditDistance() +if __name__ == "__main__": + try: + raw_input # Python 2 + except NameError: + raw_input = input # Python 3 - print("****************** Testing Edit Distance DP Algorithm ******************") - print() + solver = EditDistance() - print("Enter the first string: ", end="") - S1 = raw_input().strip() + print("****************** Testing Edit Distance DP Algorithm ******************") + print() - print("Enter the second string: ", end="") - S2 = raw_input().strip() + print("Enter the first string: ", end="") + S1 = raw_input().strip() - print() - print("The minimum Edit Distance is: %d" % (solver.solve(S1, S2))) - print() - print("*************** End of Testing Edit Distance DP Algorithm ***************") + print("Enter the second string: ", end="") + S2 = raw_input().strip() + + print() + print("The minimum Edit Distance is: %d" % (solver.solve(S1, S2))) + print() + print("*************** End of Testing Edit Distance DP Algorithm ***************") diff --git a/dynamic_programming/fibonacci.py b/dynamic_programming/fibonacci.py index b453ce255853..3cedb72b2471 100644 --- a/dynamic_programming/fibonacci.py +++ b/dynamic_programming/fibonacci.py @@ -5,7 +5,6 @@ class Fibonacci: - def __init__(self, N=None): self.fib_array = [] if N: @@ -20,17 +19,17 @@ def __init__(self, N=None): def get(self, sequence_no=None): if sequence_no != None: if sequence_no < len(self.fib_array): - return print(self.fib_array[:sequence_no + 1]) + return print(self.fib_array[: sequence_no + 1]) else: print("Out of bound.") else: print("Please specify a value") -if __name__ == '__main__': +if __name__ == "__main__": print("\n********* Fibonacci Series Using Dynamic Programming ************\n") try: - raw_input # Python 2 + raw_input # Python 2 except NameError: raw_input = input # Python 3 @@ -39,7 +38,8 @@ def get(self, sequence_no=None): N = eval(raw_input().strip()) fib = Fibonacci(N) print( - "\n********* Enter different values to get the corresponding fibonacci sequence, enter any negative number to exit. ************\n") + "\n********* Enter different values to get the corresponding fibonacci sequence, enter any negative number to exit. ************\n" + ) while True: print("Enter value: ", end=" ") try: diff --git a/dynamic_programming/integer_partition.py b/dynamic_programming/integer_partition.py index 7b27afebaa6c..1b6c6859dac2 100644 --- a/dynamic_programming/integer_partition.py +++ b/dynamic_programming/integer_partition.py @@ -1,45 +1,48 @@ from __future__ import print_function try: - xrange #Python 2 + xrange # Python 2 except NameError: - xrange = range #Python 3 + xrange = range # Python 3 try: - raw_input #Python 2 + raw_input # Python 2 except NameError: - raw_input = input #Python 3 + raw_input = input # Python 3 -''' +""" The number of partitions of a number n into at least k parts equals the number of partitions into exactly k parts plus the number of partitions into at least k-1 parts. Subtracting 1 from each part of a partition of n into k parts gives a partition of n-k into k parts. These two facts together are used for this algorithm. -''' +""" + + def partition(m): - memo = [[0 for _ in xrange(m)] for _ in xrange(m+1)] - for i in xrange(m+1): - memo[i][0] = 1 - - for n in xrange(m+1): - for k in xrange(1, m): - memo[n][k] += memo[n][k-1] - if n-k > 0: - memo[n][k] += memo[n-k-1][k] - - return memo[m][m-1] - -if __name__ == '__main__': - import sys - - if len(sys.argv) == 1: - try: - n = int(raw_input('Enter a number: ')) - print(partition(n)) - except ValueError: - print('Please enter a number.') - else: - try: - n = int(sys.argv[1]) - print(partition(n)) - except ValueError: - print('Please pass a number.') \ No newline at end of file + memo = [[0 for _ in xrange(m)] for _ in xrange(m + 1)] + for i in xrange(m + 1): + memo[i][0] = 1 + + for n in xrange(m + 1): + for k in xrange(1, m): + memo[n][k] += memo[n][k - 1] + if n - k > 0: + memo[n][k] += memo[n - k - 1][k] + + return memo[m][m - 1] + + +if __name__ == "__main__": + import sys + + if len(sys.argv) == 1: + try: + n = int(raw_input("Enter a number: ")) + print(partition(n)) + except ValueError: + print("Please enter a number.") + else: + try: + n = int(sys.argv[1]) + print(partition(n)) + except ValueError: + print("Please pass a number.") diff --git a/dynamic_programming/k_means_clustering_tensorflow.py b/dynamic_programming/k_means_clustering_tensorflow.py index ad495c71a978..622e645d4e61 100644 --- a/dynamic_programming/k_means_clustering_tensorflow.py +++ b/dynamic_programming/k_means_clustering_tensorflow.py @@ -14,24 +14,24 @@ def TFKMeansCluster(vectors, noofclusters): noofclusters = int(noofclusters) assert noofclusters < len(vectors) - #Find out the dimensionality + # Find out the dimensionality dim = len(vectors[0]) - #Will help select random centroids from among the available vectors + # Will help select random centroids from among the available vectors vector_indices = list(range(len(vectors))) shuffle(vector_indices) - #GRAPH OF COMPUTATION - #We initialize a new graph and set it as the default during each run - #of this algorithm. This ensures that as this function is called - #multiple times, the default graph doesn't keep getting crowded with - #unused ops and Variables from previous function calls. + # GRAPH OF COMPUTATION + # We initialize a new graph and set it as the default during each run + # of this algorithm. This ensures that as this function is called + # multiple times, the default graph doesn't keep getting crowded with + # unused ops and Variables from previous function calls. graph = tf.Graph() with graph.as_default(): - #SESSION OF COMPUTATION + # SESSION OF COMPUTATION sess = tf.Session() @@ -39,8 +39,9 @@ def TFKMeansCluster(vectors, noofclusters): ##First lets ensure we have a Variable vector for each centroid, ##initialized to one of the vectors from the available data points - centroids = [tf.Variable((vectors[vector_indices[i]])) - for i in range(noofclusters)] + centroids = [ + tf.Variable((vectors[vector_indices[i]])) for i in range(noofclusters) + ] ##These nodes will assign the centroid Variables the appropriate ##values centroid_value = tf.placeholder("float64", [dim]) @@ -56,26 +57,24 @@ def TFKMeansCluster(vectors, noofclusters): assignment_value = tf.placeholder("int32") cluster_assigns = [] for assignment in assignments: - cluster_assigns.append(tf.assign(assignment, - assignment_value)) + cluster_assigns.append(tf.assign(assignment, assignment_value)) ##Now lets construct the node that will compute the mean - #The placeholder for the input + # The placeholder for the input mean_input = tf.placeholder("float", [None, dim]) - #The Node/op takes the input and computes a mean along the 0th - #dimension, i.e. the list of input vectors + # The Node/op takes the input and computes a mean along the 0th + # dimension, i.e. the list of input vectors mean_op = tf.reduce_mean(mean_input, 0) ##Node for computing Euclidean distances - #Placeholders for input + # Placeholders for input v1 = tf.placeholder("float", [dim]) v2 = tf.placeholder("float", [dim]) - euclid_dist = tf.sqrt(tf.reduce_sum(tf.pow(tf.sub( - v1, v2), 2))) + euclid_dist = tf.sqrt(tf.reduce_sum(tf.pow(tf.sub(v1, v2), 2))) ##This node will figure out which cluster to assign a vector to, ##based on Euclidean distances of the vector from the centroids. - #Placeholder for input + # Placeholder for input centroid_distances = tf.placeholder("float", [noofclusters]) cluster_assignment = tf.argmin(centroid_distances, 0) @@ -87,55 +86,62 @@ def TFKMeansCluster(vectors, noofclusters): ##will be included in the initialization. init_op = tf.initialize_all_variables() - #Initialize all variables + # Initialize all variables sess.run(init_op) ##CLUSTERING ITERATIONS - #Now perform the Expectation-Maximization steps of K-Means clustering - #iterations. To keep things simple, we will only do a set number of - #iterations, instead of using a Stopping Criterion. + # Now perform the Expectation-Maximization steps of K-Means clustering + # iterations. To keep things simple, we will only do a set number of + # iterations, instead of using a Stopping Criterion. noofiterations = 100 for iteration_n in range(noofiterations): ##EXPECTATION STEP ##Based on the centroid locations till last iteration, compute ##the _expected_ centroid assignments. - #Iterate over each vector + # Iterate over each vector for vector_n in range(len(vectors)): vect = vectors[vector_n] - #Compute Euclidean distance between this vector and each - #centroid. Remember that this list cannot be named + # Compute Euclidean distance between this vector and each + # centroid. Remember that this list cannot be named #'centroid_distances', since that is the input to the - #cluster assignment node. - distances = [sess.run(euclid_dist, feed_dict={ - v1: vect, v2: sess.run(centroid)}) - for centroid in centroids] - #Now use the cluster assignment node, with the distances - #as the input - assignment = sess.run(cluster_assignment, feed_dict = { - centroid_distances: distances}) - #Now assign the value to the appropriate state variable - sess.run(cluster_assigns[vector_n], feed_dict={ - assignment_value: assignment}) + # cluster assignment node. + distances = [ + sess.run(euclid_dist, feed_dict={v1: vect, v2: sess.run(centroid)}) + for centroid in centroids + ] + # Now use the cluster assignment node, with the distances + # as the input + assignment = sess.run( + cluster_assignment, feed_dict={centroid_distances: distances} + ) + # Now assign the value to the appropriate state variable + sess.run( + cluster_assigns[vector_n], feed_dict={assignment_value: assignment} + ) ##MAXIMIZATION STEP - #Based on the expected state computed from the Expectation Step, - #compute the locations of the centroids so as to maximize the - #overall objective of minimizing within-cluster Sum-of-Squares + # Based on the expected state computed from the Expectation Step, + # compute the locations of the centroids so as to maximize the + # overall objective of minimizing within-cluster Sum-of-Squares for cluster_n in range(noofclusters): - #Collect all the vectors assigned to this cluster - assigned_vects = [vectors[i] for i in range(len(vectors)) - if sess.run(assignments[i]) == cluster_n] - #Compute new centroid location - new_location = sess.run(mean_op, feed_dict={ - mean_input: array(assigned_vects)}) - #Assign value to appropriate variable - sess.run(cent_assigns[cluster_n], feed_dict={ - centroid_value: new_location}) - - #Return centroids and assignments + # Collect all the vectors assigned to this cluster + assigned_vects = [ + vectors[i] + for i in range(len(vectors)) + if sess.run(assignments[i]) == cluster_n + ] + # Compute new centroid location + new_location = sess.run( + mean_op, feed_dict={mean_input: array(assigned_vects)} + ) + # Assign value to appropriate variable + sess.run( + cent_assigns[cluster_n], feed_dict={centroid_value: new_location} + ) + + # Return centroids and assignments centroids = sess.run(centroids) assignments = sess.run(assignments) return centroids, assignments - diff --git a/dynamic_programming/knapsack.py b/dynamic_programming/knapsack.py index 27d1cfed799b..906b5cd02aee 100644 --- a/dynamic_programming/knapsack.py +++ b/dynamic_programming/knapsack.py @@ -1,42 +1,48 @@ """ Given weights and values of n items, put these items in a knapsack of capacity W to get the maximum total value in the knapsack. """ -def MF_knapsack(i,wt,val,j): - ''' + + +def MF_knapsack(i, wt, val, j): + """ This code involves the concept of memory functions. Here we solve the subproblems which are needed unlike the below example F is a 2D array with -1s filled up - ''' + """ global F # a global dp table for knapsack if F[i][j] < 0: if j < wt[i - 1]: - val = MF_knapsack(i - 1,wt,val,j) + val = MF_knapsack(i - 1, wt, val, j) else: - val = max(MF_knapsack(i - 1,wt,val,j),MF_knapsack(i - 1,wt,val,j - wt[i - 1]) + val[i - 1]) + val = max( + MF_knapsack(i - 1, wt, val, j), + MF_knapsack(i - 1, wt, val, j - wt[i - 1]) + val[i - 1], + ) F[i][j] = val return F[i][j] + def knapsack(W, wt, val, n): - dp = [[0 for i in range(W+1)]for j in range(n+1)] + dp = [[0 for i in range(W + 1)] for j in range(n + 1)] - for i in range(1,n+1): - for w in range(1,W+1): - if(wt[i-1]<=w): - dp[i][w] = max(val[i-1]+dp[i-1][w-wt[i-1]],dp[i-1][w]) + for i in range(1, n + 1): + for w in range(1, W + 1): + if wt[i - 1] <= w: + dp[i][w] = max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]) else: - dp[i][w] = dp[i-1][w] + dp[i][w] = dp[i - 1][w] return dp[n][w] -if __name__ == '__main__': - ''' + +if __name__ == "__main__": + """ Adding test case for knapsack - ''' - val = [3,2,4,4] - wt = [4,3,2,3] + """ + val = [3, 2, 4, 4] + wt = [4, 3, 2, 3] n = 4 w = 6 - F = [[0]*(w + 1)] + [[0] + [-1 for i in range(w + 1)] for j in range(n + 1)] - print(knapsack(w,wt,val,n)) - print(MF_knapsack(n,wt,val,w)) # switched the n and w - + F = [[0] * (w + 1)] + [[0] + [-1 for i in range(w + 1)] for j in range(n + 1)] + print(knapsack(w, wt, val, n)) + print(MF_knapsack(n, wt, val, w)) # switched the n and w diff --git a/dynamic_programming/longest_common_subsequence.py b/dynamic_programming/longest_common_subsequence.py index 0a4771cb2efd..3298d1b2d538 100644 --- a/dynamic_programming/longest_common_subsequence.py +++ b/dynamic_programming/longest_common_subsequence.py @@ -6,10 +6,11 @@ from __future__ import print_function try: - xrange # Python 2 + xrange # Python 2 except NameError: xrange = range # Python 3 + def lcs_dp(x, y): # find the length of strings m = len(x) @@ -23,15 +24,16 @@ def lcs_dp(x, y): for j in range(n + 1): if i == 0 or j == 0: L[i][j] = 0 - elif x[i - 1] == y[ j - 1]: + elif x[i - 1] == y[j - 1]: L[i][j] = L[i - 1][j - 1] + 1 - seq.append(x[i -1]) + seq.append(x[i - 1]) else: L[i][j] = max(L[i - 1][j], L[i][j - 1]) # L[m][n] contains the length of LCS of X[0..n-1] & Y[0..m-1] return L[m][n], seq -if __name__=='__main__': - x = 'AGGTAB' - y = 'GXTXAYB' + +if __name__ == "__main__": + x = "AGGTAB" + y = "GXTXAYB" print(lcs_dp(x, y)) diff --git a/dynamic_programming/longest_increasing_subsequence.py b/dynamic_programming/longest_increasing_subsequence.py index b6d165909e70..0330635ddddb 100644 --- a/dynamic_programming/longest_increasing_subsequence.py +++ b/dynamic_programming/longest_increasing_subsequence.py @@ -1,4 +1,4 @@ -''' +""" Author : Mehdi ALAOUI This is a pure Python implementation of Dynamic Programming solution to the longest increasing subsequence of a given sequence. @@ -6,37 +6,41 @@ The problem is : Given an ARRAY, to find the longest and increasing sub ARRAY in that given ARRAY and return it. Example: [10, 22, 9, 33, 21, 50, 41, 60, 80] as input will return [10, 22, 33, 41, 60, 80] as output -''' +""" from __future__ import print_function -def longestSub(ARRAY): #This function is recursive - - ARRAY_LENGTH = len(ARRAY) - if(ARRAY_LENGTH <= 1): #If the array contains only one element, we return it (it's the stop condition of recursion) - return ARRAY - #Else - PIVOT=ARRAY[0] - isFound=False - i=1 - LONGEST_SUB=[] - while(not isFound and i= ARRAY[i] ] - TEMPORARY_ARRAY = longestSub(TEMPORARY_ARRAY) - if ( len(TEMPORARY_ARRAY) > len(LONGEST_SUB) ): - LONGEST_SUB = TEMPORARY_ARRAY - else: - i+=1 - - TEMPORARY_ARRAY = [ element for element in ARRAY[1:] if element >= PIVOT ] - TEMPORARY_ARRAY = [PIVOT] + longestSub(TEMPORARY_ARRAY) - if ( len(TEMPORARY_ARRAY) > len(LONGEST_SUB) ): - return TEMPORARY_ARRAY - else: - return LONGEST_SUB - -#Some examples - -print(longestSub([4,8,7,5,1,12,2,3,9])) -print(longestSub([9,8,7,6,5,7])) \ No newline at end of file + +def longestSub(ARRAY): # This function is recursive + + ARRAY_LENGTH = len(ARRAY) + if ( + ARRAY_LENGTH <= 1 + ): # If the array contains only one element, we return it (it's the stop condition of recursion) + return ARRAY + # Else + PIVOT = ARRAY[0] + isFound = False + i = 1 + LONGEST_SUB = [] + while not isFound and i < ARRAY_LENGTH: + if ARRAY[i] < PIVOT: + isFound = True + TEMPORARY_ARRAY = [element for element in ARRAY[i:] if element >= ARRAY[i]] + TEMPORARY_ARRAY = longestSub(TEMPORARY_ARRAY) + if len(TEMPORARY_ARRAY) > len(LONGEST_SUB): + LONGEST_SUB = TEMPORARY_ARRAY + else: + i += 1 + + TEMPORARY_ARRAY = [element for element in ARRAY[1:] if element >= PIVOT] + TEMPORARY_ARRAY = [PIVOT] + longestSub(TEMPORARY_ARRAY) + if len(TEMPORARY_ARRAY) > len(LONGEST_SUB): + return TEMPORARY_ARRAY + else: + return LONGEST_SUB + + +# Some examples + +print(longestSub([4, 8, 7, 5, 1, 12, 2, 3, 9])) +print(longestSub([9, 8, 7, 6, 5, 7])) diff --git a/dynamic_programming/longest_increasing_subsequence_O(nlogn).py b/dynamic_programming/longest_increasing_subsequence_O(nlogn).py index 21122a04d69f..1df37af57e86 100644 --- a/dynamic_programming/longest_increasing_subsequence_O(nlogn).py +++ b/dynamic_programming/longest_increasing_subsequence_O(nlogn).py @@ -1,41 +1,42 @@ from __future__ import print_function + ############################# # Author: Aravind Kashyap # File: lis.py # comments: This programme outputs the Longest Strictly Increasing Subsequence in O(NLogN) -# Where N is the Number of elements in the list +# Where N is the Number of elements in the list ############################# -def CeilIndex(v,l,r,key): - while r-l > 1: - m = (l + r)/2 - if v[m] >= key: - r = m - else: - l = m - - return r - +def CeilIndex(v, l, r, key): + while r - l > 1: + m = (l + r) / 2 + if v[m] >= key: + r = m + else: + l = m + + return r + def LongestIncreasingSubsequenceLength(v): - if(len(v) == 0): - return 0 - - tail = [0]*len(v) - length = 1 - - tail[0] = v[0] - - for i in range(1,len(v)): - if v[i] < tail[0]: - tail[0] = v[i] - elif v[i] > tail[length-1]: - tail[length] = v[i] - length += 1 - else: - tail[CeilIndex(tail,-1,length-1,v[i])] = v[i] - - return length - + if len(v) == 0: + return 0 + + tail = [0] * len(v) + length = 1 + + tail[0] = v[0] + + for i in range(1, len(v)): + if v[i] < tail[0]: + tail[0] = v[i] + elif v[i] > tail[length - 1]: + tail[length] = v[i] + length += 1 + else: + tail[CeilIndex(tail, -1, length - 1, v[i])] = v[i] + + return length + v = [2, 5, 3, 7, 11, 8, 10, 13, 6] print(LongestIncreasingSubsequenceLength(v)) diff --git a/dynamic_programming/longest_sub_array.py b/dynamic_programming/longest_sub_array.py index de2c88a8b525..ec9f7550f4b7 100644 --- a/dynamic_programming/longest_sub_array.py +++ b/dynamic_programming/longest_sub_array.py @@ -1,33 +1,33 @@ -''' +""" Auther : Yvonne This is a pure Python implementation of Dynamic Programming solution to the longest_sub_array problem. The problem is : Given an array, to find the longest and continuous sub array and get the max sum of the sub array in the given array. -''' +""" from __future__ import print_function class SubArray: - def __init__(self, arr): # we need a list not a string, so do something to change the type - self.array = arr.split(',') + self.array = arr.split(",") print(("the input array is:", self.array)) def solve_sub_array(self): - rear = [int(self.array[0])]*len(self.array) - sum_value = [int(self.array[0])]*len(self.array) + rear = [int(self.array[0])] * len(self.array) + sum_value = [int(self.array[0])] * len(self.array) for i in range(1, len(self.array)): - sum_value[i] = max(int(self.array[i]) + sum_value[i-1], int(self.array[i])) - rear[i] = max(sum_value[i], rear[i-1]) - return rear[len(self.array)-1] + sum_value[i] = max( + int(self.array[i]) + sum_value[i - 1], int(self.array[i]) + ) + rear[i] = max(sum_value[i], rear[i - 1]) + return rear[len(self.array) - 1] -if __name__ == '__main__': +if __name__ == "__main__": whole_array = input("please input some numbers:") array = SubArray(whole_array) re = array.solve_sub_array() print(("the results is:", re)) - diff --git a/dynamic_programming/matrix_chain_order.py b/dynamic_programming/matrix_chain_order.py index 011e85755d36..6d55290906e4 100644 --- a/dynamic_programming/matrix_chain_order.py +++ b/dynamic_programming/matrix_chain_order.py @@ -1,48 +1,58 @@ from __future__ import print_function import sys -''' + +""" Dynamic Programming Implementation of Matrix Chain Multiplication Time Complexity: O(n^3) Space Complexity: O(n^2) -''' +""" + + def MatrixChainOrder(array): - N=len(array) - Matrix=[[0 for x in range(N)] for x in range(N)] - Sol=[[0 for x in range(N)] for x in range(N)] - for i in range(1,N): - Matrix[i][i]=0 + N = len(array) + Matrix = [[0 for x in range(N)] for x in range(N)] + Sol = [[0 for x in range(N)] for x in range(N)] + for i in range(1, N): + Matrix[i][i] = 0 - for ChainLength in range(2,N): - for a in range(1,N-ChainLength+1): - b = a+ChainLength-1 + for ChainLength in range(2, N): + for a in range(1, N - ChainLength + 1): + b = a + ChainLength - 1 Matrix[a][b] = sys.maxsize - for c in range(a , b): - cost = Matrix[a][c] + Matrix[c+1][b] + array[a-1]*array[c]*array[b] + for c in range(a, b): + cost = ( + Matrix[a][c] + Matrix[c + 1][b] + array[a - 1] * array[c] * array[b] + ) if cost < Matrix[a][b]: Matrix[a][b] = cost Sol[a][b] = c - return Matrix , Sol -#Print order of matrix with Ai as Matrix -def PrintOptimalSolution(OptimalSolution,i,j): - if i==j: - print("A" + str(i),end = " ") + return Matrix, Sol + + +# Print order of matrix with Ai as Matrix +def PrintOptimalSolution(OptimalSolution, i, j): + if i == j: + print("A" + str(i), end=" ") else: - print("(",end = " ") - PrintOptimalSolution(OptimalSolution,i,OptimalSolution[i][j]) - PrintOptimalSolution(OptimalSolution,OptimalSolution[i][j]+1,j) - print(")",end = " ") + print("(", end=" ") + PrintOptimalSolution(OptimalSolution, i, OptimalSolution[i][j]) + PrintOptimalSolution(OptimalSolution, OptimalSolution[i][j] + 1, j) + print(")", end=" ") + def main(): - array=[30,35,15,5,10,20,25] - n=len(array) - #Size of matrix created from above array will be + array = [30, 35, 15, 5, 10, 20, 25] + n = len(array) + # Size of matrix created from above array will be # 30*35 35*15 15*5 5*10 10*20 20*25 - Matrix , OptimalSolution = MatrixChainOrder(array) + Matrix, OptimalSolution = MatrixChainOrder(array) + + print("No. of Operation required: " + str((Matrix[1][n - 1]))) + PrintOptimalSolution(OptimalSolution, 1, n - 1) + - print("No. of Operation required: "+str((Matrix[1][n-1]))) - PrintOptimalSolution(OptimalSolution,1,n-1) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/dynamic_programming/max_sub_array.py b/dynamic_programming/max_sub_array.py index 58711f22ce90..117f1c67050f 100644 --- a/dynamic_programming/max_sub_array.py +++ b/dynamic_programming/max_sub_array.py @@ -6,55 +6,55 @@ import time import matplotlib.pyplot as plt from random import randint -def find_max_sub_array(A,low,high): - if low==high: - return low,high,A[low] - else : - mid=(low+high)//2 - left_low,left_high,left_sum=find_max_sub_array(A,low,mid) - right_low,right_high,right_sum=find_max_sub_array(A,mid+1,high) - cross_left,cross_right,cross_sum=find_max_cross_sum(A,low,mid,high) - if left_sum>=right_sum and left_sum>=cross_sum: - return left_low,left_high,left_sum - elif right_sum>=left_sum and right_sum>=cross_sum : - return right_low,right_high,right_sum + + +def find_max_sub_array(A, low, high): + if low == high: + return low, high, A[low] + else: + mid = (low + high) // 2 + left_low, left_high, left_sum = find_max_sub_array(A, low, mid) + right_low, right_high, right_sum = find_max_sub_array(A, mid + 1, high) + cross_left, cross_right, cross_sum = find_max_cross_sum(A, low, mid, high) + if left_sum >= right_sum and left_sum >= cross_sum: + return left_low, left_high, left_sum + elif right_sum >= left_sum and right_sum >= cross_sum: + return right_low, right_high, right_sum else: - return cross_left,cross_right,cross_sum + return cross_left, cross_right, cross_sum -def find_max_cross_sum(A,low,mid,high): - left_sum,max_left=-999999999,-1 - right_sum,max_right=-999999999,-1 - summ=0 - for i in range(mid,low-1,-1): - summ+=A[i] + +def find_max_cross_sum(A, low, mid, high): + left_sum, max_left = -999999999, -1 + right_sum, max_right = -999999999, -1 + summ = 0 + for i in range(mid, low - 1, -1): + summ += A[i] if summ > left_sum: - left_sum=summ - max_left=i - summ=0 - for i in range(mid+1,high+1): - summ+=A[i] + left_sum = summ + max_left = i + summ = 0 + for i in range(mid + 1, high + 1): + summ += A[i] if summ > right_sum: - right_sum=summ - max_right=i - return max_left,max_right,(left_sum+right_sum) - + right_sum = summ + max_right = i + return max_left, max_right, (left_sum + right_sum) + -if __name__=='__main__': - inputs=[10,100,1000,10000,50000,100000,200000,300000,400000,500000] - tim=[] +if __name__ == "__main__": + inputs = [10, 100, 1000, 10000, 50000, 100000, 200000, 300000, 400000, 500000] + tim = [] for i in inputs: - li=[randint(1,i) for j in range(i)] - strt=time.time() - (find_max_sub_array(li,0,len(li)-1)) - end=time.time() - tim.append(end-strt) - print("No of Inputs Time Taken") - for i in range(len(inputs)): - print((inputs[i],'\t\t',tim[i])) - plt.plot(inputs,tim) - plt.xlabel("Number of Inputs");plt.ylabel("Time taken in seconds ") + li = [randint(1, i) for j in range(i)] + strt = time.time() + (find_max_sub_array(li, 0, len(li) - 1)) + end = time.time() + tim.append(end - strt) + print("No of Inputs Time Taken") + for i in range(len(inputs)): + print((inputs[i], "\t\t", tim[i])) + plt.plot(inputs, tim) + plt.xlabel("Number of Inputs") + plt.ylabel("Time taken in seconds ") plt.show() - - - - diff --git a/dynamic_programming/minimum_partition.py b/dynamic_programming/minimum_partition.py index 18aa1faa2fa6..d5750326fea4 100644 --- a/dynamic_programming/minimum_partition.py +++ b/dynamic_programming/minimum_partition.py @@ -1,28 +1,30 @@ """ Partition a set into two subsets such that the difference of subset sums is minimum """ + + def findMin(arr): n = len(arr) s = sum(arr) - dp = [[False for x in range(s+1)]for y in range(n+1)] + dp = [[False for x in range(s + 1)] for y in range(n + 1)] - for i in range(1, n+1): + for i in range(1, n + 1): dp[i][0] = True - for i in range(1, s+1): + for i in range(1, s + 1): dp[0][i] = False - for i in range(1, n+1): - for j in range(1, s+1): - dp[i][j]= dp[i][j-1] + for i in range(1, n + 1): + for j in range(1, s + 1): + dp[i][j] = dp[i][j - 1] - if (arr[i-1] <= j): - dp[i][j] = dp[i][j] or dp[i-1][j-arr[i-1]] + if arr[i - 1] <= j: + dp[i][j] = dp[i][j] or dp[i - 1][j - arr[i - 1]] - for j in range(int(s/2), -1, -1): + for j in range(int(s / 2), -1, -1): if dp[n][j] == True: - diff = s-2*j - break; + diff = s - 2 * j + break return diff