Skip to content

Create-Add files to greedy_method directory #2082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions greedy_method/greedy_knapsack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# To get an insight into Greedy Algorithm through the Knapsack problem


"""
A shopkeeper has bags of wheat that each have different weights and different profits.
eg.
profit 5 8 7 1 12 3 4
weight 2 7 1 6 4 2 5
max_weight 100

Constraints:
max_weight > 0
profit[i] >= 0
weight[i] >= 0
Calculate the maximum profit that the shopkeeper can make given maxmum weight that can
be carried.
"""
from typing import Union


def calc_profit(profit: list, weight: list, max_weight: int) -> Union[str, int]:
"""
Function description is as follows-
:param profit: Take a list of profits
:param weight: Take a list of weight if bags corresponding to the profits
:param max_weight: Maximum weight that could be carried
:return: Maximum expected gain

>>> calc_profit([1, 2, 3], [3, 4, 5], 15)
6
>>> calc_profit([10, 9 , 8], [3 ,4 , 5], 25)
27
"""
if len(profit) != len(weight):
raise ValueError("The length of profit and weight must be same.")
if max_weight <= 0:
raise ValueError("max_weight must greater than zero.")
if any(p < 0 for p in profit):
raise ValueError("Profit can not be negative.")
if any(w < 0 for w in weight):
raise ValueError("Weight can not be negative.")

# List created to store profit gained for the 1kg in case of each weight
# respectively. Calculate and append profit/weight for each element.
profit_by_weight = [p / w for p, w in zip(profit, weight)]

# Creating a copy of the list and sorting profit/weight in ascending order
sorted_profit_by_weight = sorted(profit_by_weight)

# declaring useful variables
length = len(sorted_profit_by_weight)
limit = 0
gain = 0
i = 0

# loop till the total weight do not reach max limit e.g. 15 kg and till i<length
while limit <= max_weight and i < length:
# flag value for encountered greatest element in sorted_profit_by_weight
biggest_profit_by_weight = sorted_profit_by_weight[length - i - 1]
"""
Calculate the index of the biggest_profit_by_weight in profit_by_weight list.
This will give the index of the first encountered element which is same as of
biggest_profit_by_weight. There may be one or more values same as that of
biggest_profit_by_weight but index always encounter the very first element
only. To curb this alter the values in profit_by_weight once they are used
here it is done to -1 because neither profit nor weight can be in negative.
"""
index = profit_by_weight.index(biggest_profit_by_weight)
profit_by_weight[index] = -1

# check if the weight encountered is less than the total weight
# encountered before.
if max_weight - limit >= weight[index]:
limit += weight[index]
# Adding profit gained for the given weight 1 ===
# weight[index]/weight[index]
gain += 1 * profit[index]
else:
# Since the weight encountered is greater than limit, therefore take the
# required number of remaining kgs and calculate profit for it.
# weight remaining / weight[index]
gain += (max_weight - limit) / weight[index] * profit[index]
break
i += 1
return gain


if __name__ == "__main__":
print(
"Input profits, weights, and then max_weight (all positive ints) separated by "
"spaces."
)

profit = [int(x) for x in input("Input profits separated by spaces: ").split()]
weight = [int(x) for x in input("Input weights separated by spaces: ").split()]
max_weight = int(input("Max weight allowed: "))

# Function Call
calc_profit(profit, weight, max_weight)
74 changes: 74 additions & 0 deletions greedy_method/test_knapsack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import unittest
import greedy_knapsack as kp


class TestClass(unittest.TestCase):
"""
Test cases for knapsack
"""

def test_sorted(self):
"""
kp.calc_profit takes the required argument (profit, weight, max_weight)
and returns whether the answer matches to the expected ones
"""
profit = [10, 20, 30, 40, 50, 60]
weight = [2, 4, 6, 8, 10, 12]
max_weight = 100
self.assertEqual(kp.calc_profit(profit, weight, max_weight), 210)

def test_negative_max_weight(self):
"""
Returns ValueError for any negative max_weight value
:return: ValueError
"""
# profit = [10, 20, 30, 40, 50, 60]
# weight = [2, 4, 6, 8, 10, 12]
# max_weight = -15
self.assertRaisesRegex(ValueError, "max_weight must greater than zero.")

def test_negative_profit_value(self):
"""
Returns ValueError for any negative profit value in the list
:return: ValueError
"""
# profit = [10, -20, 30, 40, 50, 60]
# weight = [2, 4, 6, 8, 10, 12]
# max_weight = 15
self.assertRaisesRegex(
ValueError, "Weight can not be negative.",
)

def test_negative_weight_value(self):
"""
Returns ValueError for any negative weight value in the list
:return: ValueError
"""
# profit = [10, 20, 30, 40, 50, 60]
# weight = [2, -4, 6, -8, 10, 12]
# max_weight = 15
self.assertRaisesRegex(ValueError, "Profit can not be negative.")

def test_null_max_weight(self):
"""
Returns ValueError for any zero max_weight value
:return: ValueError
"""
# profit = [10, 20, 30, 40, 50, 60]
# weight = [2, 4, 6, 8, 10, 12]
# max_weight = null
self.assertRaisesRegex(ValueError, "max_weight must greater than zero.")

def test_unequal_list_length(self):
"""
Returns IndexError if length of lists (profit and weight) are unequal.
:return: IndexError
"""
# profit = [10, 20, 30, 40, 50]
# weight = [2, 4, 6, 8, 10, 12]
# max_weight = 100
self.assertRaisesRegex(IndexError, "The length of profit and weight must be same.")


if __name__ == "__main__":
unittest.main()