From c7118a8b797fe8240b0dd301ef8122f16c01dc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Sun, 4 Oct 2020 09:44:56 +0200 Subject: [PATCH 1/9] Add naive recursive implementation of 0-1 Knapsack problem --- knappsack/__init__.py | 0 knappsack/knappsack.py | 43 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 knappsack/__init__.py create mode 100644 knappsack/knappsack.py diff --git a/knappsack/__init__.py b/knappsack/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/knappsack/knappsack.py b/knappsack/knappsack.py new file mode 100644 index 000000000000..f0ce88eb7abc --- /dev/null +++ b/knappsack/knappsack.py @@ -0,0 +1,43 @@ +from typing import List + + +# A naive recursive implementation of 0-1 Knapsack Problem + +def knapsack(capacity: int, weights: List[int], value: List[int], counter) -> int: + """ + Returns the maximum value that can be put in a knapsack of a capacity, + whereby each weight has a specific value. + + >>> capactiy = 50 + >>> values = [60, 100, 120] + >>> weights = [10, 20, 30] + >>> counter = len(values) + >>> print(knapsack(capactiy, weights, values, counter)) + 50 + + The result is 50 cause the values of 100 and 120 got the weight of 50 + which is the limit of the capacity. + """ + + # Base Case + if counter == 0 or capacity == 0: + return 0 + + # If weight of the nth item is more than Knapsack of capacity, + # then this item cannot be included in the optimal solution, + # else return the maximum of two cases: + # (1) nth item included + # (2) not included + if weights[counter - 1] > capacity: + return knapsack(capacity, weights, value, counter - 1) + else: + left_capacity = capacity - weights[counter - 1] + new_value_included = value[counter - 1] + knapsack(left_capacity, weights, value, counter - 1) + without_new_value = knapsack(capacity, weights, value, counter - 1) + return max(new_value_included, without_new_value) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From c6071aa5e28e088929cbf03b1361a5ebd8defe94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Sun, 4 Oct 2020 09:46:28 +0200 Subject: [PATCH 2/9] Fix shadowing --- knappsack/knappsack.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/knappsack/knappsack.py b/knappsack/knappsack.py index f0ce88eb7abc..d36a39932126 100644 --- a/knappsack/knappsack.py +++ b/knappsack/knappsack.py @@ -3,16 +3,16 @@ # A naive recursive implementation of 0-1 Knapsack Problem -def knapsack(capacity: int, weights: List[int], value: List[int], counter) -> int: +def knapsack(capacity: int, weights: List[int], values: List[int], counter) -> int: """ - Returns the maximum value that can be put in a knapsack of a capacity, - whereby each weight has a specific value. - - >>> capactiy = 50 - >>> values = [60, 100, 120] - >>> weights = [10, 20, 30] - >>> counter = len(values) - >>> print(knapsack(capactiy, weights, values, counter)) + Returns the maximum value that can be put in a knapsack of a capacity cap, + whereby each weight w has a specific value val. + + >>> cap = 50 + >>> val = [60, 100, 120] + >>> w = [10, 20, 30] + >>> c = len(values) + >>> print(knapsack(cap, w, val, c)) 50 The result is 50 cause the values of 100 and 120 got the weight of 50 @@ -29,11 +29,11 @@ def knapsack(capacity: int, weights: List[int], value: List[int], counter) -> in # (1) nth item included # (2) not included if weights[counter - 1] > capacity: - return knapsack(capacity, weights, value, counter - 1) + return knapsack(capacity, weights, values, counter - 1) else: left_capacity = capacity - weights[counter - 1] - new_value_included = value[counter - 1] + knapsack(left_capacity, weights, value, counter - 1) - without_new_value = knapsack(capacity, weights, value, counter - 1) + new_value_included = values[counter - 1] + knapsack(left_capacity, weights, values, counter - 1) + without_new_value = knapsack(capacity, weights, values, counter - 1) return max(new_value_included, without_new_value) From 04056108e0b6afcdf88deb24c7ce851e85d6abeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Sun, 4 Oct 2020 12:41:40 +0200 Subject: [PATCH 3/9] Add doctest --- knappsack/knappsack.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/knappsack/knappsack.py b/knappsack/knappsack.py index d36a39932126..d94149ce351e 100644 --- a/knappsack/knappsack.py +++ b/knappsack/knappsack.py @@ -11,11 +11,11 @@ def knapsack(capacity: int, weights: List[int], values: List[int], counter) -> i >>> cap = 50 >>> val = [60, 100, 120] >>> w = [10, 20, 30] - >>> c = len(values) - >>> print(knapsack(cap, w, val, c)) - 50 + >>> c = len(val) + >>> knapsack(cap, w, val, c) + 220 - The result is 50 cause the values of 100 and 120 got the weight of 50 + The result is 220 cause the values of 100 and 120 got the weight of 50 which is the limit of the capacity. """ From 0871a7d4af089a86bfd19a6866e1532255e1c70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Sun, 4 Oct 2020 12:42:33 +0200 Subject: [PATCH 4/9] Fix type hints --- knappsack/knappsack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knappsack/knappsack.py b/knappsack/knappsack.py index d94149ce351e..e9b02f9770ed 100644 --- a/knappsack/knappsack.py +++ b/knappsack/knappsack.py @@ -3,7 +3,7 @@ # A naive recursive implementation of 0-1 Knapsack Problem -def knapsack(capacity: int, weights: List[int], values: List[int], counter) -> int: +def knapsack(capacity: int, weights: List[int], values: List[int], counter: int) -> int: """ Returns the maximum value that can be put in a knapsack of a capacity cap, whereby each weight w has a specific value val. From a9a5ce18808fcd328f1e8da59335572d567a5cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Sun, 4 Oct 2020 12:44:47 +0200 Subject: [PATCH 5/9] Add link to wiki --- knappsack/knappsack.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/knappsack/knappsack.py b/knappsack/knappsack.py index e9b02f9770ed..a297a1457315 100644 --- a/knappsack/knappsack.py +++ b/knappsack/knappsack.py @@ -2,6 +2,7 @@ # A naive recursive implementation of 0-1 Knapsack Problem +# https://en.wikipedia.org/wiki/Knapsack_problem def knapsack(capacity: int, weights: List[int], values: List[int], counter: int) -> int: """ @@ -32,7 +33,8 @@ def knapsack(capacity: int, weights: List[int], values: List[int], counter: int) return knapsack(capacity, weights, values, counter - 1) else: left_capacity = capacity - weights[counter - 1] - new_value_included = values[counter - 1] + knapsack(left_capacity, weights, values, counter - 1) + new_value_included = values[counter - 1] + \ + knapsack(left_capacity, weights, values, counter - 1) without_new_value = knapsack(capacity, weights, values, counter - 1) return max(new_value_included, without_new_value) From 88472c2e8e4c5c878306ec6d0521b98efc6204b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Sun, 4 Oct 2020 13:02:53 +0200 Subject: [PATCH 6/9] Blacked the file --- knappsack/knappsack.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/knappsack/knappsack.py b/knappsack/knappsack.py index a297a1457315..0aae9a5b3a78 100644 --- a/knappsack/knappsack.py +++ b/knappsack/knappsack.py @@ -4,6 +4,7 @@ # A naive recursive implementation of 0-1 Knapsack Problem # https://en.wikipedia.org/wiki/Knapsack_problem + def knapsack(capacity: int, weights: List[int], values: List[int], counter: int) -> int: """ Returns the maximum value that can be put in a knapsack of a capacity cap, @@ -33,8 +34,9 @@ def knapsack(capacity: int, weights: List[int], values: List[int], counter: int) return knapsack(capacity, weights, values, counter - 1) else: left_capacity = capacity - weights[counter - 1] - new_value_included = values[counter - 1] + \ - knapsack(left_capacity, weights, values, counter - 1) + new_value_included = values[counter - 1] + knapsack( + left_capacity, weights, values, counter - 1 + ) without_new_value = knapsack(capacity, weights, values, counter - 1) return max(new_value_included, without_new_value) From 731d9c3f6e57ff0cbccc552f1118cf3d6ef576b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Sun, 4 Oct 2020 13:39:47 +0200 Subject: [PATCH 7/9] Fix isort --- knappsack/knappsack.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/knappsack/knappsack.py b/knappsack/knappsack.py index 0aae9a5b3a78..756443ea6163 100644 --- a/knappsack/knappsack.py +++ b/knappsack/knappsack.py @@ -1,8 +1,8 @@ from typing import List - -# A naive recursive implementation of 0-1 Knapsack Problem -# https://en.wikipedia.org/wiki/Knapsack_problem +""" A naive recursive implementation of 0-1 Knapsack Problem + https://en.wikipedia.org/wiki/Knapsack_problem +""" def knapsack(capacity: int, weights: List[int], values: List[int], counter: int) -> int: From 1edd96a56d37fcaf93d778eebd13b2362d3c65cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Fri, 16 Oct 2020 09:36:47 +0200 Subject: [PATCH 8/9] Move knapsack / add readme and more tests --- knapsack/README.md | 32 +++++++++++++ {knappsack => knapsack}/__init__.py | 0 .../knappsack.py => knapsack/knapsack.py | 0 knapsack/test_knapsack.py | 48 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 knapsack/README.md rename {knappsack => knapsack}/__init__.py (100%) rename knappsack/knappsack.py => knapsack/knapsack.py (100%) create mode 100644 knapsack/test_knapsack.py diff --git a/knapsack/README.md b/knapsack/README.md new file mode 100644 index 000000000000..6041c1e48eb8 --- /dev/null +++ b/knapsack/README.md @@ -0,0 +1,32 @@ +# A naive recursive implementation of 0-1 Knapsack Problem + +This overview is taken from: + + https://en.wikipedia.org/wiki/Knapsack_problem + +--- + +## Overview + +The knapsack problem is a problem in combinatorial optimization: Given a set of items, each with a weight and a value, determine the number of each item to include in a collection so that the total weight is less than or equal to a given limit and the total value is as large as possible. It derives its name from the problem faced by someone who is constrained by a fixed-size knapsack and must fill it with the most valuable items. The problem often arises in resource allocation where the decision makers have to choose from a set of non-divisible projects or tasks under a fixed budget or time constraint, respectively. + +The knapsack problem has been studied for more than a century, with early works dating as far back as 1897 The name "knapsack problem" dates back to the early works of mathematician Tobias Dantzig (1884–1956), and refers to the commonplace problem of packing the most valuable or useful items without overloading the luggage. + +--- + +## Documentation + +This module uses docstrings to enable the use of Python's in-built `help(...)` function. +For instance, try `help(Vector)`, `help(unitBasisVector)`, and `help(CLASSNAME.METHODNAME)`. + +--- + +## Usage + +Import the module `knapsack.py` from the **.** directory into your project. + +--- + +## Tests + +`.` contains Python unit tests which can be run with `python3 -m unittest -v`. diff --git a/knappsack/__init__.py b/knapsack/__init__.py similarity index 100% rename from knappsack/__init__.py rename to knapsack/__init__.py diff --git a/knappsack/knappsack.py b/knapsack/knapsack.py similarity index 100% rename from knappsack/knappsack.py rename to knapsack/knapsack.py diff --git a/knapsack/test_knapsack.py b/knapsack/test_knapsack.py new file mode 100644 index 000000000000..fc9342b6fcc9 --- /dev/null +++ b/knapsack/test_knapsack.py @@ -0,0 +1,48 @@ +""" +Created on Fri Oct 16 09:31:07 2020 + +@author: Dr. Tobias Schröder +@license: MIT-license + +This file contains the test-suite for the knapsack problem. +""" +import unittest + +from knapsack import knapsack + + +class Test(unittest.TestCase): + def test_base_case(self): + """ + test for the base case + """ + cap = 0 + val = [0] + w = [0] + c = len(val) + self.assertEqual(knapsack(cap, w, val, c), 0) + + val = [60] + w = [10] + c = len(val) + self.assertEqual(knapsack(cap, w, val, c), 0) + + def test_easy_case(self): + """ + test for the base case + """ + cap = 3 + val = [1, 2, 3] + w = [3, 2, 1] + c = len(val) + self.assertEqual(knapsack(cap, w, val, c), 5) + + def test_knapsack(self): + """ + test for the knapsack + """ + cap = 50 + val = [60, 100, 120] + w = [10, 20, 30] + c = len(val) + self.assertEqual(knapsack(cap, w, val, c), 220) From 57f7b29c36b6c7a4ce401211fbd21a83aa6a8b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Tobias=20Schr=C3=B6der?= Date: Fri, 16 Oct 2020 09:45:58 +0200 Subject: [PATCH 9/9] Add missed main in tests --- knapsack/test_knapsack.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/knapsack/test_knapsack.py b/knapsack/test_knapsack.py index fc9342b6fcc9..248855fbce53 100644 --- a/knapsack/test_knapsack.py +++ b/knapsack/test_knapsack.py @@ -8,7 +8,7 @@ """ import unittest -from knapsack import knapsack +from knapsack import knapsack as k class Test(unittest.TestCase): @@ -20,12 +20,12 @@ def test_base_case(self): val = [0] w = [0] c = len(val) - self.assertEqual(knapsack(cap, w, val, c), 0) + self.assertEqual(k.knapsack(cap, w, val, c), 0) val = [60] w = [10] c = len(val) - self.assertEqual(knapsack(cap, w, val, c), 0) + self.assertEqual(k.knapsack(cap, w, val, c), 0) def test_easy_case(self): """ @@ -35,7 +35,7 @@ def test_easy_case(self): val = [1, 2, 3] w = [3, 2, 1] c = len(val) - self.assertEqual(knapsack(cap, w, val, c), 5) + self.assertEqual(k.knapsack(cap, w, val, c), 5) def test_knapsack(self): """ @@ -45,4 +45,8 @@ def test_knapsack(self): val = [60, 100, 120] w = [10, 20, 30] c = len(val) - self.assertEqual(knapsack(cap, w, val, c), 220) + self.assertEqual(k.knapsack(cap, w, val, c), 220) + + +if __name__ == "__main__": + unittest.main()