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 9 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
118 changes: 118 additions & 0 deletions greedy_method/knapsack_problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# To get an insight into Greedy Algorithm
# Knapsack is a common Greedy Algo problem


"""
You have bags of wheat with different weights and a different profits for each.
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 max profit the shopkeeper can make for the given max_Weight that could 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: Max. weight that could be carried
:return: Max 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 IndexError(
"<< The length of both the arrays must be same! Try again.. >>"
)

if max_Weight <= 0:
raise ValueError(
"<< Gotcha! Max_Weight is a positive quantity greater than zero! >>"
)

for i in range(len(profit)):
if profit[i] < 0:
raise ValueError(
"<< Ono! Profit means positive value. Better luck next time! >>"
)

if weight[i] < 0:
raise ValueError(
"<< Oops! Could not accept a negative value for weight. Try Again.. >>"
)

# List created to store profit gained for the 1kg in case of each weight
# respectively
profit_By_Weight = list()

# Calculate and append profit/weight for each
for i in range(len(weight)):
profit_By_Weight.append(profit[i] / weight[i])

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

# declaring useful variables
length = len(temp_PBW)
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 temp_PBW
flag = temp_PBW[length - i - 1]
"""
Calculating index of the same flag in profit_By_Weight list.
This will give the index of the first encountered element which is same as of flag.
There may be one or more values same as that of flag 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(flag)
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__":

# Input profit, weight and max_Weight (all positive values).

profit = [int(x) for x in input().split()]
weight = [int(x) for x in input().split()]
max_Weight = int(input("Max weight allowed: "))

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


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

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_maxWeight(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,
"<< Gotcha! Max_Weight is a positive quantity 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,
"<< Oops! Could not accept a negative value for weight. Try Again.. >>",
)

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, "<< Ono! Profit means positive value. Better luck next time! >>"
)

def test_zero_maxWeight(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 = 0
self.assertRaisesRegex(
ValueError,
"<< Gotcha! Max_Weight is a positive quantity 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 both the arrays must be same! Try again.. >>"
)


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