From 0b3452c350d8f34749cb4bcf77ba115b7278a359 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Tue, 24 Oct 2023 15:50:19 +0530 Subject: [PATCH 01/12] Readable code, function docstring and doctests --- greedy_methods/fractional_knapsack.py | 38 +++++++++++++++++++-------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 58976d40c02b..593f1532c97d 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -2,23 +2,39 @@ from itertools import accumulate -def frac_knapsack(vl, wt, w, n): +def frac_knapsack(vl: list, wt: list, w: int, n: int) -> float: """ + This function implements fractional knapsack problem. + + Args: + vl: List of values of items. + wt: List of weights of items. + w: Capacity of the knapsack. + n: Number of items. + + Returns: + Maximum value of items that can be put into the knapsack. + >>> frac_knapsack([60, 100, 120], [10, 20, 30], 50, 3) 240.0 + >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 10, 4) + 105.0 + >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 4) + 95.0 """ + # sort in descending order of value/weight ratio r = sorted(zip(vl, wt), key=lambda x: x[0] / x[1], reverse=True) - vl, wt = [i[0] for i in r], [i[1] for i in r] - acc = list(accumulate(wt)) - k = bisect(acc, w) - return ( - 0 - if k == 0 - else sum(vl[:k]) + (w - acc[k - 1]) * (vl[k]) / (wt[k]) - if k != n - else sum(vl[:k]) - ) + + vl, wt = [i[0] for i in r], [i[1] for i in r] # unzip the list + acc = list(accumulate(wt)) # cumulative sum of weights + k = bisect(acc, w) # find the index of the weight just greater than w + + if k == 0: # no item can be put into the knapsack + return 0 + elif k != n: # fractional part of the kth item can be put into the knapsack + return sum(vl[:k]) + (w - acc[k - 1]) * (vl[k]) / (wt[k]) + return sum(vl[:k]) # all items can be put into the knapsack if __name__ == "__main__": From 2fe8657cb75fe3696bc32b5cb86bb9e955ebd797 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Tue, 24 Oct 2023 15:55:04 +0530 Subject: [PATCH 02/12] Add wiki link --- greedy_methods/fractional_knapsack.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 593f1532c97d..99bb46f91aa4 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -1,6 +1,8 @@ from bisect import bisect from itertools import accumulate +# Reference Link: https://en.wikipedia.org/wiki/Continuous_knapsack_problem + def frac_knapsack(vl: list, wt: list, w: int, n: int) -> float: """ From b36c346336730e0daa8c5ef73e58300c9ed3aab4 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Tue, 24 Oct 2023 17:07:53 +0530 Subject: [PATCH 03/12] Remove added doctests --- greedy_methods/fractional_knapsack.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 99bb46f91aa4..f8661567b730 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -19,10 +19,6 @@ def frac_knapsack(vl: list, wt: list, w: int, n: int) -> float: >>> frac_knapsack([60, 100, 120], [10, 20, 30], 50, 3) 240.0 - >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 10, 4) - 105.0 - >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 4) - 95.0 """ # sort in descending order of value/weight ratio From 4d2458068dc57b1f75ea843a3e7de3dac139c5d0 Mon Sep 17 00:00:00 2001 From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com> Date: Tue, 24 Oct 2023 21:57:43 +0530 Subject: [PATCH 04/12] Add strict=True Co-authored-by: Christian Clauss --- greedy_methods/fractional_knapsack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index f27c1e3f6101..a2c7bd754d20 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -46,7 +46,7 @@ def frac_knapsack(vl: list, wt: list, w: int, n: int) -> float: """ # sort in descending order of value/weight ratio - r = sorted(zip(vl, wt), key=lambda x: x[0] / x[1], reverse=True) + r = sorted(zip(vl, wt), key=lambda x: x[0] / x[1], reverse=True, strict=True) vl, wt = [i[0] for i in r], [i[1] for i in r] # unzip the list acc = list(accumulate(wt)) # cumulative sum of weights From b0a5d6dd6fbcd6ff12e20b8a2da1aa37e3c422d7 Mon Sep 17 00:00:00 2001 From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com> Date: Tue, 24 Oct 2023 21:58:00 +0530 Subject: [PATCH 05/12] Add self-documenting variable names Co-authored-by: Christian Clauss --- greedy_methods/fractional_knapsack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index a2c7bd754d20..5e7b4917d4da 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -4,7 +4,7 @@ # Reference Link: https://en.wikipedia.org/wiki/Continuous_knapsack_problem -def frac_knapsack(vl: list, wt: list, w: int, n: int) -> float: +def frac_knapsack(values: list[int], weights: list[int], capacity: int, max_items: int) -> float: """ This function implements fractional knapsack problem. From 2fb82e2c87a5bdd33daa146bdf05927d2397d61b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 16:29:11 +0000 Subject: [PATCH 06/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- greedy_methods/fractional_knapsack.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 5e7b4917d4da..e3bab105ea8e 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -4,7 +4,9 @@ # Reference Link: https://en.wikipedia.org/wiki/Continuous_knapsack_problem -def frac_knapsack(values: list[int], weights: list[int], capacity: int, max_items: int) -> float: +def frac_knapsack( + values: list[int], weights: list[int], capacity: int, max_items: int +) -> float: """ This function implements fractional knapsack problem. From f647070ce2017c0c34a4ad5a4efc6818ea61d7c6 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Tue, 24 Oct 2023 22:01:26 +0530 Subject: [PATCH 07/12] Renamed the variables --- greedy_methods/fractional_knapsack.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 5e7b4917d4da..3c7115acc525 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -9,10 +9,10 @@ def frac_knapsack(values: list[int], weights: list[int], capacity: int, max_item This function implements fractional knapsack problem. Args: - vl: List of values of items. - wt: List of weights of items. - w: Capacity of the knapsack. - n: Number of items. + values: List of values of items. + weights: List of weights of items. + capacity: Capacity of the knapsack. + max_items: Number of items. Returns: Maximum value of items that can be put into the knapsack. @@ -46,17 +46,19 @@ def frac_knapsack(values: list[int], weights: list[int], capacity: int, max_item """ # sort in descending order of value/weight ratio - r = sorted(zip(vl, wt), key=lambda x: x[0] / x[1], reverse=True, strict=True) + r = sorted(zip(values, weights), + key=lambda x: x[0] / x[1], reverse=True) - vl, wt = [i[0] for i in r], [i[1] for i in r] # unzip the list - acc = list(accumulate(wt)) # cumulative sum of weights - k = bisect(acc, w) # find the index of the weight just greater than w + values, weights = [i[0] for i in r], [i[1] for i in r] # unzip the list + acc = list(accumulate(weights)) # cumulative sum of weights + # find the index of the weight just greater than capacity + k = bisect(acc, capacity) if k == 0: # no item can be put into the knapsack return 0 - elif k != n: # fractional part of the kth item can be put into the knapsack - return sum(vl[:k]) + (w - acc[k - 1]) * (vl[k]) / (wt[k]) - return sum(vl[:k]) # all items can be put into the knapsack + elif k != max_items: # fractional part of the kth item can be put into the knapsack + return sum(values[:k]) + (capacity - acc[k - 1]) * (values[k]) / (weights[k]) + return sum(values[:k]) # all items can be put into the knapsack if __name__ == "__main__": From aa93e554b1acc9eb15fdfa373a24694b129abfe3 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Tue, 24 Oct 2023 22:04:11 +0530 Subject: [PATCH 08/12] Add strcit=True to zip function --- greedy_methods/fractional_knapsack.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index d4e2fa260360..242a361d4cb8 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -26,9 +26,13 @@ def frac_knapsack( >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 4) 95.0 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6], 8, 4) - 60.0 + Traceback (most recent call last): + ... + ValueError: zip() argument 2 is shorter than argument 1 >>> frac_knapsack([10, 40, 30], [5, 4, 6, 3], 8, 4) - 60.0 + Traceback (most recent call last): + ... + ValueError: zip() argument 2 is longer than argument 1 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 0, 4) 0 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 0) @@ -48,7 +52,7 @@ def frac_knapsack( """ # sort in descending order of value/weight ratio - r = sorted(zip(values, weights), + r = sorted(zip(values, weights, strict=True), key=lambda x: x[0] / x[1], reverse=True) values, weights = [i[0] for i in r], [i[1] for i in r] # unzip the list From 168e1cd250a87f0abf2410c6912fed554b276b10 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 16:37:18 +0000 Subject: [PATCH 09/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- greedy_methods/fractional_knapsack.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 242a361d4cb8..b35932e42752 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -52,8 +52,9 @@ def frac_knapsack( """ # sort in descending order of value/weight ratio - r = sorted(zip(values, weights, strict=True), - key=lambda x: x[0] / x[1], reverse=True) + r = sorted( + zip(values, weights, strict=True), key=lambda x: x[0] / x[1], reverse=True + ) values, weights = [i[0] for i in r], [i[1] for i in r] # unzip the list acc = list(accumulate(weights)) # cumulative sum of weights From ecd863428bf2281ef8e2673cefdba0b5dbc807c9 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Wed, 25 Oct 2023 18:53:52 +0530 Subject: [PATCH 10/12] Add input validation for capacity and max_items --- greedy_methods/fractional_knapsack.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index b35932e42752..45c7ff0e803f 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -34,13 +34,21 @@ def frac_knapsack( ... ValueError: zip() argument 2 is longer than argument 1 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 0, 4) - 0 + Traceback (most recent call last): + ... + ValueError: Capacity and max_items must be greater than 0 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 0) - 95.0 + Traceback (most recent call last): + ... + ValueError: Capacity and max_items must be greater than 0 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], -8, 4) - 0 + Traceback (most recent call last): + ... + ValueError: Capacity and max_items must be greater than 0 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, -4) - 95.0 + Traceback (most recent call last): + ... + ValueError: Capacity and max_items must be greater than 0 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 800, 4) 130 >>> frac_knapsack([10, 40, 30, 50], [5, 4, 6, 3], 8, 400) @@ -51,6 +59,10 @@ def frac_knapsack( TypeError: unsupported operand type(s) for /: 'str' and 'int' """ + # Input validation + if capacity <= 0 or max_items <= 0: + raise ValueError("Capacity and max_items must be greater than 0") + # sort in descending order of value/weight ratio r = sorted( zip(values, weights, strict=True), key=lambda x: x[0] / x[1], reverse=True From c37b46f71d1c28951d1d53407eab40be5ba64219 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Wed, 25 Oct 2023 20:12:26 +0530 Subject: [PATCH 11/12] Rectify the Fractional Knapsack logic --- greedy_methods/fractional_knapsack.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 45c7ff0e803f..3c4b26753b13 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -57,6 +57,8 @@ def frac_knapsack( Traceback (most recent call last): ... TypeError: unsupported operand type(s) for /: 'str' and 'int' + >>> frac_knapsack([500], [30], 10, 1) + 166.66666666666666 """ # Input validation @@ -68,15 +70,18 @@ def frac_knapsack( zip(values, weights, strict=True), key=lambda x: x[0] / x[1], reverse=True ) - values, weights = [i[0] for i in r], [i[1] for i in r] # unzip the list + values, weights = zip(*r) # unzip the sorted list acc = list(accumulate(weights)) # cumulative sum of weights + # find the index of the weight just greater than capacity k = bisect(acc, capacity) - if k == 0: # no item can be put into the knapsack - return 0 - elif k != max_items: # fractional part of the kth item can be put into the knapsack - return sum(values[:k]) + (capacity - acc[k - 1]) * (values[k]) / (weights[k]) + if k == 0: # first item is greater than capacity + fraction = capacity / weights[0] + return fraction * values[0] + elif k < max_items: # fractional part of the kth item can be put into the knapsack + fraction = (capacity - acc[k - 1]) / weights[k] + return sum(values[:k]) + fraction * values[k] return sum(values[:k]) # all items can be put into the knapsack From eb1b2d596db27214fa0a9e49dc25b39348a922c7 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Wed, 25 Oct 2023 20:15:39 +0530 Subject: [PATCH 12/12] Fix tuple error --- greedy_methods/fractional_knapsack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/greedy_methods/fractional_knapsack.py b/greedy_methods/fractional_knapsack.py index 3c4b26753b13..e13bc4545d9b 100644 --- a/greedy_methods/fractional_knapsack.py +++ b/greedy_methods/fractional_knapsack.py @@ -70,7 +70,7 @@ def frac_knapsack( zip(values, weights, strict=True), key=lambda x: x[0] / x[1], reverse=True ) - values, weights = zip(*r) # unzip the sorted list + values, weights = [i[0] for i in r], [i[1] for i in r] # unzip acc = list(accumulate(weights)) # cumulative sum of weights # find the index of the weight just greater than capacity