Learn faster and stay on-track by joining this free class with other self-learners.
Register for MIT OpenCourseWare 6.00 Introduction to Computer Science and Programming now.
|
MIT OpenCourseWare 6.00 Introduction to Computer Science and ProgrammingClass length: 24 weeks. Start anytime. Creator: duallain Status: Established |
Join this class! |
|
Lesson 14: Assignment 1: PS 8Homework Submissions8 total# 6.00 Problem Set 8
#
# Intelligent Course Advisor
#
# Name: Scott Brenner
# Collaborators: http://openstudy.com/studypads/Problem-Set-8-4c6bf092e6153a7f05c12e1e
# Time: problem 1: 20 minutes
#
import time
import string
from operator import itemgetter, attrgetter
SUBJECT_FILENAME = "my_subjects.txt"
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
#
# Problem 1: Building A Subject Dictionary
#
def loadSubjects(filename):
"""
Returns a dictionary mapping subject name to (value, work), where the name
is a string and the value and work are integers. The subject information is
read from the file named by the string filename. Each line of the file
contains a string of the form "name,value,work".
returns: dictionary mapping subject name to (value, work)
"""
result = {}
inputFile = open(filename)
for line in inputFile:
line = line.strip()
line_as_list = line.split(',')
result[line_as_list[0]] = (int(line_as_list[-2]),int(line_as_list[-1]))
return result
# TODO: Instead of printing each line, modify the above to parse the name,
# value, and work of each subject and create a dictionary mapping the name
# to the (value, work).
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
return val1 > val2
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return work1 < work2
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return float(val1) / work1 > float(val2) / work2
#
# Problem 2: Subject Selection By Greedy Optimization
#
def greedyAdvisor(subjects, maxWork, comparator):
"""
Returns a dictionary mapping subject name to (value, work) which includes
subjects selected by the algorithm, such that the total work of subjects in
the dictionary is not greater than maxWork. The subjects are chosen using
a greedy algorithm. The subjects dictionary should not be mutated.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
comparator: function taking two tuples and returning a bool
returns: dictionary mapping subject name to (value, work)
"""
# TODO...
#
# Build function that sorts based on comparator returns list of subject names sorted by comparator criteria.
#
def sort(l, comparator) :
"""
Sorts the list of subjects' names in descendig order
acording to the comparator.
"""
# print "l, comparator type:", type(l), type(comparator)
# print
for i in range(1, len(l)) :
value = l[i]
j = i - 1
done = False
# print 'i, value, j', i, value, j
# print
while not done:
# print "subjects[value], subjects[l[j]] type:", type(subjects[value]), type(subjects[l[j]])
# print
if comparator(subjects[value], subjects[l[j]]):
l[j+1] = l[j]
j -= 1
if j < 0 :
done = True
else :
done = True
l[j+1] = value
#
# Pick classes from top of sorted list until maxWork is reached
#
schedule_list = subjects.keys()
#print 'schedule_list unsorted: ', schedule_list
#print
sort(schedule_list, comparator)
# print 'schedule_list sorted: ', schedule_list
# print
recommended_schedule = {}
courseLoad = 0
done = False
for course in schedule_list:
if subjects[course][1] <= maxWork - courseLoad:
recommended_schedule[course] = subjects[course]
courseLoad += subjects[course][1]
return recommended_schedule
def bruteForceAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work), which
represents the globally optimal selection of subjects using a brute force
algorithm.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
counter = 0
def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue, subset, subsetValue, subsetWork):
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
return subset[:], subsetValue
else:
# Keep the current best.
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK])
subset.pop()
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork)
return bestSubset, bestSubsetValue
#
# Problem 3: Subject Selection By Brute Force
#
def bruteForceTime():
"""
Runs tests on bruteForceAdvisor and measures the time required to compute
an answer.
"""
# TODO...
trial_work = [15]
total_times = {}
for each in trial_work:
start_time = time.time()
print bruteForceAdvisor(subjects,each)
end_time = time.time()
total_times[each] = round(end_time - start_time, 2)
print total_times
# Problem 3 Observations
# ======================
#
# TODO: write here your observations regarding bruteForceTime's performance
# Th brute force function is very slow for even moderately large course loads.
# For a maxLoad of 2: 0.01 seconds
# 4: 0.22
# 6: 1.76
# 7: 3.70
# 8: 11.42
# 9: 27.57
# 10: 122.58
# 11: 354.55
# 12: 778.29
# 13: 1714.95
# 14: 2907.09
# 14: 2850.40
# Unreasonable depends on a multiple factors, including the importance of the results and the quality of the results of a faster, less optimal function. In this case the greedy function probably produces results that nearly as good as the results of the brute force method.
# Considering MIT costs ~$200k in tuition and room and board. Perhaps a few minutes to optimize a semester course load is worth it.
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
These are the results for running this full catalog:
{8: 0.02, 10: 0.01, 45: 0.080000000000000002, 15: 0.02, 120: 0.23000000000000001, 90: 0.23000000000000001, 60: 0.11, 30: 0.050000000000000003}
"""
# TODO...
rec_dict = {}
m = {}
# Build the work and value lists.
work_list = []
value_list = []
key_list = []
for each in subjects:
work_list.append(subjects[each][1])
value_list.append(subjects[each][0])
key_list.append(each)
# Build optimal list of courses to take.
value, rec_list = dp_decision_tree(work_list,value_list,len(work_list)-1,maxWork,m)
# Build dictionary from list.
for each in rec_list:
rec_dict[key_list[each]] = (value_list[each],work_list[each])
return rec_dict
def dp_decision_tree(w,v,i,aW,m):
"""
Creates a course schedule that is optimized the maximum value.
"""
## check if value is already in the dictionary
try: return m[(i,aW)]
except KeyError:
## Leaf/Bottom of the tree case decision
if i == 0:
if w[i] < aW:
m[(i,aW)] = v[i], [i]
return v[i],[i]
else:
m[(i,aW)] = 0, []
return 0,[]
## Calculate with and without i branches
without_i, course_list = dp_decision_tree(w,v,i-1,aW,m)
if w[i] > aW:
m[(i,aW)] = without_i, course_list
return without_i, course_list
else:
with_i, course_list_temp = dp_decision_tree(w, v, i-1, aW - w[i], m)
with_i += v[i]
## Take the branch with the higher value
if with_i > without_i:
i_value = with_i
course_list = [i] + course_list_temp
else:
i_value = without_i
## Add this value calculation to the memo
m[(i,aW)] = i_value, course_list
return i_value, course_list
#
# Problem 5: Performance Comparison
#
def dpTime():
"""
Runs tests on dpAdvisor and measures the time required to compute an
answer.
Prints total schedule, recommended schedule, time to complete each trial.
"""
# TODO...
trial_work = [8,10,15,30,45,60,90,120]
total_times = {}
for each in trial_work:
print "Trial for max workload of %i." % each
start_time = time.time()
recommendation = dpAdvisor(subjects, each)
end_time = time.time()
total_times[each] = round(end_time - start_time, 2)
printSubjects(recommendation)
print total_times
return
# Problem 5 Observations
# ======================
#
# TODO: write here your observations regarding dpAdvisor's performance and
# how its performance compares to that of bruteForceAdvisor.
subjects = loadSubjects(SUBJECT_FILENAME)
dpTime()
#print subjects
#print "Course Catalog"
#printSubjects(loadSubjects(SUBJECT_FILENAME))
# print 'greedy(cmpValue):'
# printSubjects(greedyAdvisor(subjects, 15, cmpValue))
#
# print '\ngreedy(cmpWork):'
# printSubjects(greedyAdvisor(subjects, 15, cmpWork))
#
# print '\ngreedy(cmpRatio)'
# printSubjects(greedyAdvisor(subjects, 15, cmpRatio))
# printSubjects(bruteForceAdvisor(subjects,15))
#
#bruteForceTime()
#print dpAdvisor(subjects, 15)
Problem 4 was really hard. It was easy to get the dynamic programming sample from the lecture to return the proper value but to get it to return the dictionary was challenging. # 6.00 Problem Set 8
#
# Intelligent Course Advisor
#
# Name:
# Collaborators:
# Time:
#
import time
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
#
# Problem 1: Building A Subject Dictionary
#
def loadSubjects(filename):
"""
Returns a dictionary mapping subject name to (value, work), where the name
is a string and the value and work are integers. The subject information is
read from the file named by the string filename. Each line of the file
contains a string of the form "name,value,work".
returns: dictionary mapping subject name to (value, work)
"""
# The following sample code reads lines from the specified file and prints
# each one.
subjects = {}
inputFile = open(filename)
for line in inputFile:
#print line
l = line.strip() # strips line break
l = l.split(',') # strips commas and converts into a list
name = l[0]
value = int(l[1])
work = int(l[2])
subjects[name] = (value, work)
return subjects
# TODO: Instead of printing each line, modify the above to parse the name,
# value, and work of each subject and create a dictionary mapping the name
# to the (value, work).
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
def printValue(subjects):
"""
Prints a string containing total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = ''
subNames = subjects.keys()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
totalVal += val
totalWork += work
res = res + 'Total Value: ' + str(totalVal)
res = res + ' Total Work: ' + str(totalWork)
print res
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
return val1 > val2
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return work1 < work2
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return float(val1) / work1 > float(val2) / work2
#
# Problem 2: Subject Selection By Greedy Optimization
#
def greedyAdvisor(subjects, maxWork, comparator):
"""
Returns a dictionary mapping subject name to (value, work) which includes
subjects selected by the algorithm, such that the total work of subjects in
the dictionary is not greater than maxWork. The subjects are chosen using
a greedy algorithm. The subjects dictionary should not be mutated.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
comparator: function taking two tuples and returning a bool
returns: dictionary mapping subject name to (value, work)
"""
# performs a selection sort on the list of the subjects.keys()
assert type(maxWork) == int and maxWork >= 0
outputSubjects = {}
nameList = subjects.keys()
sortedList = nameList[:]
sumWork = 0
for i in range(len(sortedList) - 1):
minIndx = i
subInfo1 = subjects[sortedList[i]]
j = i + 1
while j < len(sortedList):
subInfo2 = subjects[sortedList[j]]
if not comparator(subInfo1, subInfo2):
minIndx = j
subInfo1 = subjects[sortedList[j]]
j += 1
temp = sortedList[i]
sortedList[i] = sortedList[minIndx]
sortedList[minIndx] = temp
#selects the best answers by the amount of maxWork remaining
for best in sortedList:
work = subjects[best][WORK]
if work + sumWork <= maxWork:
outputSubjects[best] = subjects[best]
sumWork += work
if sumWork == maxWork: break
return outputSubjects
def bruteForceAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work), which
represents the globally optimal selection of subjects using a brute force
algorithm.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
subset, subsetValue, subsetWork):
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
return subset[:], subsetValue
else:
# Keep the current best.
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK])
subset.pop()
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork)
return bestSubset, bestSubsetValue
#
# Problem 3: Subject Selection By Brute Force
#
def bruteForceTime():
"""
Runs tests on bruteForceAdvisor and measures the time required to compute
an answer.
"""
maxWork = [1,2,3,4,5,6,7,8,9,10]
for work in maxWork:
start_time = time.time()
bruteForceAdvisor(SUBJECTS, work)
end_time = time.time()
total_time = end_time - start_time
print 'It took %0.3f seconds to complete bruteForceAdvisor for maxWork = %s' % (total_time, work)
# Problem 3 Observations
# ======================
#
# It took 0.002 seconds to complete bruteForceAdvisor for maxWork = 1
# It took 0.007 seconds to complete bruteForceAdvisor for maxWork = 2
# It took 0.026 seconds to complete bruteForceAdvisor for maxWork = 3
# It took 0.095 seconds to complete bruteForceAdvisor for maxWork = 4
# It took 0.306 seconds to complete bruteForceAdvisor for maxWork = 5
# It took 0.995 seconds to complete bruteForceAdvisor for maxWork = 6
# It took 2.875 seconds to complete bruteForceAdvisor for maxWork = 7
# It took 8.130 seconds to complete bruteForceAdvisor for maxWork = 8
# It took 21.928 seconds to complete bruteForceAdvisor for maxWork = 9
# It took 56.926 seconds to complete bruteForceAdvisor for maxWork = 10
# It took 143.230 seconds to complete bruteForceAdvisor for maxWork = 11
# It took 351.753 seconds to complete bruteForceAdvisor for maxWork = 12
# It took 832.148 seconds to complete bruteForceAdvisor for maxWork = 13
# A reasonable amount of time would be less than a minute so 10 hours or less
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
i = len(nameList) - 1
outputSubjects = {}
memo = {}
bestSubjectsValue, bestSubjectsIndex = dpHelper(tupleList, i, maxWork, memo, ())
for index in bestSubjectsIndex:
outputSubjects[nameList[index]] = tupleList[index]
return outputSubjects
def dpHelper(tupleList, i, maxWork, memo, subjectsIndex):
try: return memo[(i, maxWork)][0], memo[(i, maxWork)][1]
except KeyError:
if i == 0:
if tupleList[i][WORK] <= maxWork:
# if there is room for the last course to be added
# then it adds the index number of the course to tuple.
subjectsIndex += (i,)
memo[(i, maxWork)] = tupleList[i][VALUE], subjectsIndex
return tupleList[i][VALUE], subjectsIndex
else:
memo[(i, maxWork)] = 0, subjectsIndex
return 0, subjectsIndex
without_value, without_i = dpHelper(tupleList, i-1, maxWork, memo, subjectsIndex)
if tupleList[i][WORK] > maxWork:
memo[(i, maxWork)] = without_value, without_i
return without_value, without_i
else:
with_value, with_i = dpHelper(tupleList, i-1, maxWork - tupleList[i][WORK], memo, subjectsIndex)
with_value += tupleList[i][VALUE]
bestSubjectsValue = max(with_value, without_value)
# conditional decides whether the course was added or not.
# if the course was added then it adds the index number of the course
# to the tuple.
if with_value == bestSubjectsValue:
subjectsIndex = with_i + (i,)
memo[(i, maxWork)] = bestSubjectsValue, subjectsIndex
else:
subjectsIndex = without_i
memo[(i, maxWork)] = bestSubjectsValue, subjectsIndex
return bestSubjectsValue, subjectsIndex
#
# Problem 5: Performance Comparison
#
def dpTime():
"""
Runs tests on dpAdvisor and measures the time required to compute an
answer.
"""
maxWork = [1,2,3,4,5,6,7,8,9,10,20,25,50,100,200,300,400,500]
for work in maxWork:
start_time = time.time()
dpAdvisor(SUBJECTS, work)
end_time = time.time()
total_time = end_time - start_time
print 'It took %0.3f seconds to complete dpAdvisor for maxWork = %s' % (total_time, work)
def greedyTime():
maxWork = [1,2,3,4,5,6,7,8,9,10,20,25,50,100,200,300,400,500]
for work in maxWork:
start_time = time.time()
greedyAdvisor(SUBJECTS, work, cmpRatio)
end_time = time.time()
total_time = end_time - start_time
print 'It took %0.3f seconds to complete dpAdvisor for maxWork = %s' % (total_time, work)
# Problem 5 Observations
# ======================
#
# TODO: write here your observations regarding dpAdvisor's performance and
# how its performance compares to that of bruteForceAdvisor.
#
# Greedy
# It took 0.058 seconds to complete dpAdvisor for maxWork = 1
# It took 0.058 seconds to complete dpAdvisor for maxWork = 2
# It took 0.059 seconds to complete dpAdvisor for maxWork = 3
# It took 0.057 seconds to complete dpAdvisor for maxWork = 4
# It took 0.055 seconds to complete dpAdvisor for maxWork = 5
# It took 0.057 seconds to complete dpAdvisor for maxWork = 6
# It took 0.057 seconds to complete dpAdvisor for maxWork = 7
# It took 0.057 seconds to complete dpAdvisor for maxWork = 8
# It took 0.056 seconds to complete dpAdvisor for maxWork = 9
# It took 0.057 seconds to complete dpAdvisor for maxWork = 10
# It took 0.057 seconds to complete dpAdvisor for maxWork = 20
# It took 0.057 seconds to complete dpAdvisor for maxWork = 25
# It took 0.058 seconds to complete dpAdvisor for maxWork = 50
# It took 0.058 seconds to complete dpAdvisor for maxWork = 100
# It took 0.057 seconds to complete dpAdvisor for maxWork = 200
# It took 0.057 seconds to complete dpAdvisor for maxWork = 300
# It took 0.056 seconds to complete dpAdvisor for maxWork = 400
# It took 0.056 seconds to complete dpAdvisor for maxWork = 500
#
# Dynamic Programming
# It took 0.002 seconds to complete dpAdvisor for maxWork = 1
# It took 0.003 seconds to complete dpAdvisor for maxWork = 2
# It took 0.003 seconds to complete dpAdvisor for maxWork = 3
# It took 0.005 seconds to complete dpAdvisor for maxWork = 4
# It took 0.006 seconds to complete dpAdvisor for maxWork = 5
# It took 0.006 seconds to complete dpAdvisor for maxWork = 6
# It took 0.008 seconds to complete dpAdvisor for maxWork = 7
# It took 0.009 seconds to complete dpAdvisor for maxWork = 8
# It took 0.010 seconds to complete dpAdvisor for maxWork = 9
# It took 0.010 seconds to complete dpAdvisor for maxWork = 10
# It took 0.023 seconds to complete dpAdvisor for maxWork = 20
# It took 0.024 seconds to complete dpAdvisor for maxWork = 21
# It took 0.029 seconds to complete dpAdvisor for maxWork = 25
# It took 0.067 seconds to complete dpAdvisor for maxWork = 50
# It took 0.144 seconds to complete dpAdvisor for maxWork = 100
# It took 0.316 seconds to complete dpAdvisor for maxWork = 200
# It took 0.491 seconds to complete dpAdvisor for maxWork = 300
# It took 0.700 seconds to complete dpAdvisor for maxWork = 400
# It took 0.921 seconds to complete dpAdvisor for maxWork = 500
#
# The performance of dpAdvisor increases slowly as maxWork increases because
# as maxWork increases the total number of solutions increases and since the
# complexity is O(ns) where n is number of subjects and s is the number of
# solutions.
#
# bruteForceAdvisor grows exponentially and isn't workable past maxWork > 10
# I'm guessing the complexity is O(2**ns) as the size of the solution grows
# when maxWork increases
#
# greedyAdvisor complexity is O(n) where n is the number of entries in subjects.
# The time it takes to solve doesn't change when maxWork changes. the comparator
# cmpRatio gives the correct answer most of the time, but not always.
#
# dpAdvisor is faster than greedyAdvisor when maxWork < 50
# dpAdvisor is faster than bruteForceAdvisor when maxWork > 1
#
if __name__ == '__main__':
SUBJECTS = loadSubjects('subjects.txt')
maxWork = 30
#
# Testing Problem 2
#
##print 'Greedy By Value'
##printSubjects(greedyAdvisor(SUBJECTS, maxWork, cmpValue))
##print 'Greedy By Work'
##printSubjects(greedyAdvisor(SUBJECTS, maxWork, cmpWork))
##print 'Greedy By Ratio'
##printSubjects(greedyAdvisor(SUBJECTS, maxWork, cmpRatio))
##if maxWork <= 10:
## print 'Brute Force'
## printSubjects(bruteForceAdvisor(SUBJECTS, maxWork))
#
# Testing Problem 4
#
##print 'Dynamic Programming'
printSubjects(dpAdvisor(SUBJECTS, maxWork))
##for work in range(1,60):
## print 'Greedy By Ratio'
## printValue(greedyAdvisor(SUBJECTS, work, cmpRatio))
## print 'Dynamic Programming'
## printValue(dpAdvisor(SUBJECTS, work))
## print
#
# Testing Problem 5
#
##print 'Greedy'
##greedyTime()
##print
##print 'Brute Force'
##bruteForceTime()
##print
##print 'Dynamic Programming'
##dpTime()
No comments. Sign up or log in to comment # 6.00 Problem Set 8
#
# Intelligent Course Advisor
#
# Name: Hugo Arruda de Moura Torres
# Collaborators:
# Time: Sun Dec5 2010 03:01 AM to...
#
import time
import csv # this module should allow me to treat each value in the lines of the
# input data file independently
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
#
# Problem 1: Building A Subject Dictionary
#
def loadSubjects(filename):
"""
Returns a dictionary mapping subject name to (value, work), where the name
is a string and the value and work are integers. The subject information is
read from the file named by the string filename. Each line of the file
contains a string of the form "name,value,work".
returns: dictionary mapping subject name to (value, work)
"""
# The following sample code reads lines from the specified file and prints
# each one.
work_value = {}
with open(filename) as arquivo:
for linha in csv.reader(arquivo):
work_value[linha[0]] = int(linha[1]), int(linha[2])
return work_value
# TODO: Instead of printing each line, modify the above to parse the name,
# value, and work of each subject and create a dictionary mapping the name
# to the (value, work).
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
return val1 > val2
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return work1 < work2
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return float(val1) / work1 > float(val2) / work2
#
# Problem 2: Subject Selection By Greedy Optimization
#
def sel_sort(subject_dictionary, comparator):
"""Returns a new comparator-sorted list with the same elements as subject_dictionary keys.
A selection sort algorithm is used."""
lista = subject_dictionary.keys()
for i in range(len(lista)-1):
#print lista
maxIndx = i
maxVal = lista[i]
j = i + 1 #this will walk the lenght of the list
while j < len(lista):
if comparator(subject_dictionary[lista[j]],subject_dictionary[maxVal]):
maxIndx = j
maxVal = lista[j]
j += 1
temp = lista[i]
lista[i] = lista[maxIndx]
lista[maxIndx] = temp
return lista
def quick_sort(subjects, comparator) :
"""
Sorts the list of subjects' names in descendig order
acording to the comparator. It uses a "merge sort" algorithm
"""
lista = subjects.keys()
def merge(left,right, comparator,subjects):
"""Assumes left and right are lists sorted according to 'comparator'.
Returns a new sorted list containing the same elements
as (left + right) would contain."""
#print 'left:', left
#print 'right', right
result = []
i,j = 0, 0
while i < len(left) and j < len(right):
if comparator(subjects[left[i]], subjects[right[j]]):
result.append(left[i])
i = i + 1
else:
result.append(right[j])
j = j + 1
while (i < len(left)):
result.append(left[i])
i = i + 1
while (j < len(right)):
result.append(right[j])
j = j + 1
return result
def mergesort(lista):
"""Returns a new sorted list with the same elements as lista"""
#print lista
if len(lista) < 2:
return lista[:]
else:
middle = len(lista) / 2
left = mergesort(lista[:middle])
right = mergesort(lista[middle:])
together = merge(left,right,comparator,subjects)
#print 'merged', together
return together
return mergesort(lista)
def greedyAdvisor(subjects, maxWork, comparator):
"""
Returns a dictionary mapping subject name to (value, work) which includes
subjects selected by the algorithm, such that the total work of subjects in
the dictionary is not greater than maxWork. The subjects are chosen using
a greedy algorithm. The subjects dictionary should not be mutated.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
comparator: function taking two tuples and returning a bool
returns: dictionary mapping subject name to (value, work)
"""
#A greedy algorythm always gets the most valuable item up until the
#limit is reached.
# - First, sort a list of subjects acording to the comparator function in
# question.
# - Add the values from the sorted list of subjetcs to the results dictionary until
# - the work limit is reached.
#materias = sel_sort(subjects, comparator)
materias = quick_sort(subjects, comparator)
#print 'sorted:', materias
GreedyCombo = {}
sumWork = 0
count = 0 #trick: this will count the times we take the next 'else' branch
while sumWork < maxWork:
for item in materias:
if sumWork + subjects[item][WORK] <= maxWork and subjects[item] not in GreedyCombo: # if work of item does not reach or surpass threshold then I can add subject
sumWork += subjects[item][WORK]
GreedyCombo[item] = subjects[item]
else: #if adding next subject surpasses maxWork do not add the subject
count +=1
if count >= len(materias):
sumWork = maxWork + 1 # this is a trick to break out of the while loop
###because all subjects were already tried in this condition
return GreedyCombo
def bruteForceAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work), which
represents the globally optimal selection of subjects using a brute force
algorithm.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
subset, subsetValue, subsetWork):
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
return subset[:], subsetValue
else:
# Keep the current best.
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK])
subset.pop()
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork)
return bestSubset, bestSubsetValue
#
# Problem 3: Subject Selection By Brute Force
#
def bruteForceTime(subjects, maxwork, k):
"""
Runs tests on bruteForceAdvisor and measures the time required to compute
an answer.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
result = bruteForceAdvisor(subjects,maxwork)
end_time = time.time()
totalTime = end_time - start_time
print 'It took the brute force algorythm %s seconds to compute' %totalTime
#printSubjects(result)
return int(end_time - start_time) * k
# TODO...
# Problem 3 Observations
# ======================
#
# TODO: write here your observations regarding bruteForceTime's performance
# For maxwork > 10 bruteForceAdvisor seems to take an unreasonable amount of time
# to halt on my PC.
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
Essentially, like the example used in class we are implementing a decision-
tree comprising two vectors containing work and value entries and a
maximum work restraint(e.g. available knapsack capacity).
"""
#this dictionary will hold the best combination of classes to take
result = {}
#a list of subject names
#subjectlist = subjects.keys()
#a list of tuples containing subjects's (value, workload)
tuple_list= subjects.values()
#print 'tuplas:', tuple_list
#the number of items to be analysed by dynamic programming
item = len(tuple_list)-1
magisteria = subjects.keys()
#-memo = memoization dictionary containing precomputed values of the
#form item, maxWork: (value).
memo= {}
selectedSubjects=dpAdvisorHelper(subjects, magisteria, maxWork, item, memo)[1]
for magisteria in selectedSubjects:
#print magisteria
result[magisteria]=subjects[magisteria]
return result
# this function is ok do not mess with it
def dpAdvisorHelper(subjects, magisteria, maxWork, item, memo):
"""
-memo = memoization dictionary containing precomputed values of the
form item, maxWork: [value, (selected_subjects,)].
- index = index of the first undecided object to include in the knapsack
- reuturns a dictionary mapping (item, maxwork to optimal value and included subjects)
24:26http://www.youtube.com/watch?v=6h6Fi6AQiRM&feature=related
"""
memoIndex = (item, maxWork)
#try and use pre-computed values:
try: return memo[memoIndex]
except KeyError: #if not there, compute it and store for future use.
# item 0 means we are at the last subject
if item == 0:
# We are considering the first item to include: if we have room, include it, if not, do not
if subjects[magisteria[item]][WORK] <= maxWork:
memo[memoIndex] = subjects[magisteria[item]][VALUE], (magisteria[item],)
else:
#withoutItem = dpAdvisorHelper(subjects, tuple_list, item - 1, maxWork, selected_subjects, memo)
memo[memoIndex] = 0, () # The empty lists represents no item included.
return memo[memoIndex]
#If we are NOT in the last item we have to consider 3 options
#first, if the class exceeds maxWork, we can't take the class. Over.
withoutItem = dpAdvisorHelper(subjects, magisteria, maxWork, item-1, memo)
if subjects[magisteria[item]][WORK] > maxWork:
memo[memoIndex] = withoutItem
return memo[memoIndex]
#Now if it doesn't we can either take it or not depending on the Knapsak value:
#Case 1: Including the item:
#Get the value for the previous knapsack..
PreviousValue, PreviousSelection = dpAdvisorHelper(subjects, magisteria,\
maxWork - subjects[magisteria[item]][WORK], item - 1, memo)
#And add the Item and its value to
ValueWithItem = PreviousValue + subjects[magisteria[item]][VALUE]
SelectionWithItem = PreviousSelection + (magisteria[item],)
#=========================================================
#Case 2 Excluding it:
ValueWithoutItem, SelectionWithoutItem = dpAdvisorHelper(subjects, \
magisteria, maxWork, item - 1, memo)
#=========================================================
# Compare case 1 and 2: choose whichever is more valuable:
if ValueWithItem > ValueWithoutItem:
memo[memoIndex] = ValueWithItem, SelectionWithItem
else:
memo[memoIndex] = ValueWithoutItem, SelectionWithoutItem
return memo[memoIndex]
def dpTime(subjects,MaxWork):
"""
Runs tests on dpAdvisor and measures the time required to compute an
answer.
"""
start=time.time()
selection = dpAdvisor(subjects,MaxWork)
end=time.time()
totalTime = end - start
print 'It took %s seconds for the dynamic programming algorythm to \
complete its job' %totalTime
#printSubjects(selection)
# TODO...
smallCatalog = {'teste2':(5,3),'6.00':(16,8),'1.00':(7,7),'6.01':(5,45),'15.01':(9,6), 'teste':(7,7)} #smaller dictionary for debugging purposes
subjects = loadSubjects(SUBJECT_FILENAME) #dictionary containing subjects
# mapped to work and value
##print subjects
##print 'Triar:'
##printSubjects(smallCatalog)
##selection = dpAdvisor(smallCatalog,15)
##print '==========='
##print 'Dynamic Programming selection: (MaxWork = 15)'
##printSubjects(selection)
##
##
##print 'Triar:'
##printSubjects(smallCatalog)
##selection = greedyAdvisor(smallCatalog, 15, cmpValue)
##print '==========='
##print 'Greedy selection: (MaxWork = 15)'
##printSubjects(selection)
#print subjects
#print 'Triar:'
##printSubjects(subjects)
##selection = dpAdvisor(subjects,30)
##print '==========='
##print 'Dynamic Programming selection: (MaxWork = 30)'
##printSubjects(selection)
#dpTime(smallCatalog,15)
#bruteForceTime(subjects,30,1)
#bruteForceTime(smallCatalog,15,1)
dpTime(subjects,30)
bruteForceTime(subjects,30,1)
# Problem 5 Observations
# ======================
#
# TODO: write here your observations regarding dpAdvisor's performance and
# how its performance compares to that of bruteForceAdvisor.
#
#Well... it seems that for small datasets the bruteforce algorythm can be pretty quick
#and finishes at comparable timespan as the dp algorythm
#But it is much slower and even fails to complete when using larger datasets as input,
#it fails to comply and the dp algorythm still is able to finish at relatively short time.
#For instance, calling:
#dpTime(smallCatalog,15)
#bruteForceTime(smallCatalog,15,1) :
#
#It took 7.48634338379e-05 seconds for the dynamic programming algorythm to complete its job
#It took the brute force algorythm 4.29153442383e-05 seconds to compute
#
#When calling:
#dpTime(subjects,30)
#bruteForceTime(subjects,30,1)
#It took 0.0338768959045 seconds for the dynamic programming algorythm to complete its job
#Bruteforce never halts.
#
No comments. Sign up or log in to comment # 6.00 Problem Set 9
#
# Name: geoB
# Collaborators:
# Time: far too long!!
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
import random
import time
def makeSmall(subjects, n):
"""
create a random subset of subjects dictionary with n elements
"""
if n > len(subjects):
print 'n is too big!'
return
i = 0
small = {}
subNames = subjects.keys()
for i in random.sample(xrange(len(subjects)), n):
small[subNames[i]] = subjects[subNames[i]]
return small
def loadSubjects(filename):
inputFile = open(filename)
svw = {}
for line in inputFile:
str = line.split(',')
svw[str[0]] = (int(str[1]), int(str[2].strip()))
return svw
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
subjects = loadSubjects(SUBJECT_FILENAME)
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
return val1 > val2
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return work1 < work2
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return float(val1) / work1 > float(val2) / work2
small = makeSmall(subjects, 6)
def greedy(s, aW):
"""s: subjects; aW: available work"""
advice = {}
L = len(s)
work = 0
for i in range(L):
key = s[i].keys()[0]
s_work = s[i][key][WORK] + work
if s_work >= aW:
return advice
advice[key] = s[i][key]
work = s_work
return advice
def greedyAdvisor(subjects, aW, comparator):
start = time.time()
keys = subjects.keys()
s = selSort(subjects, comparator)
greed = greedy(s, aW)
end = time.time()
deltaT = end - start
printSubjects(greed)
print 'Time to calculate: %0.2f seconds' % deltaT
def selSort(D, compare):
"""D: dictionary of subjects; compare: comparator function name"""
keys = D.keys()
sortedD = []
for k in range(len(D) - 1):
for i in range(len(D)):
minI = i
minD = D[keys[i]]
dI = {keys[minI]:minD}
if dI not in sortedD:
for j in range(len(D)):
jI = {keys[j]:D[keys[j]]}
if jI not in sortedD:
if compare(D[keys[j]], minD):
minI = j
minD = D[keys[j]]
sortedD.append({keys[minI]: minD})
return sortedD
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
# TODO...
memo = {}
i = len(subjects) - 1
aW = maxWork
keys = subjects.keys()
result = {}
start = time.time()
advice = fastDP(subjects, keys, aW, i, memo)
end = time.time()
for i in advice[1]:
result[keys[i]] = subjects[keys[i]]
printSubjects(result)
deltaT = end - start
print 'Time to calculate: %0.2f seconds' % deltaT
def fastDP(subjects, keys, aW, i, memo):
try: return memo[(i, aW)]
except KeyError:
if i == 0:
if subjects[keys[i]][WORK] <= aW:
memo[(i, aW)] = [subjects[keys[i]][VALUE], [i]]
return [subjects[keys[i]][VALUE], [i]]
else:
memo[(i, aW)] = [0, []]
return [0, []]
without_i = fastDP(subjects, keys, aW, i-1, memo)
if subjects[keys[i]][WORK] > aW:
memo[(i, aW)] = without_i
return without_i
else:
with_v = fastDP(subjects, keys, aW-subjects[keys[i]][WORK], i-1, memo)
with_i = [subjects[keys[i]][VALUE] + with_v[0], with_v[1] + [i]]
res = max(with_i, without_i)
if with_i[0] > without_i[0]: res = with_i
else: res = without_i
memo[(i, aW)] = res
return res
Comments:I don't get why with_i is a list and whithou_i is not. There are no comments on the fastDP functions. I can see it works but I can't understand why some steps where taken in such and such way. import time
from pprint import pprint
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
#
# Problem 1: Building A Subject Dictionary
#
def loadSubjects(filename):
"""
Returns a dictionary mapping subject name to (value, work), where the name
is a string and the value and work are integers. The subject information is
read from the file named by the string filename. Each line of the file
contains a string of the form "name,value,work".
returns: dictionary mapping subject name to (value, work)
"""
subjectMapping = {}
inputFile = open(filename)
for line in inputFile:
words = line.strip().split(',')
subjectMapping[words[0]] = (int(words[1]), int(words[2]))
return subjectMapping
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
return val1 > val2
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return work1 < work2
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return float(val1) / work1 > float(val2) / work2
#
# Problem 2: Subject Selection By Greedy Optimization
#
def greedyAdvisor(subjects, maxWork, comparator):
"""
Returns a dictionary mapping subject name to (value, work) which includes
subjects selected by the algorithm, such that the total work of subjects in
the dictionary is not greater than maxWork. The subjects are chosen using
a greedy algorithm. The subjects dictionary should not be mutated.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
comparator: function taking two tuples and returning a bool
returns: dictionary mapping subject name to (value, work)
"""
subjectsToTake = {}
currentBest = None
done = False
while not done:
currentBest = None
for subject in subjects:
# If we have not selected the subject already and we either
# do not have a "best" subject yet or the current subject is
# better than our current best and we can fit it in with regards
# to our maximum workload
if not(subject in subjectsToTake) and (not currentBest or comparator(subjects[subject], subjects[currentBest])) and not(maxWork - subjects[subject][1] < 0):
currentBest = subject
# Cannot fit another subject in
if not currentBest:
done = True
else:
subjectsToTake[currentBest] = subjects[currentBest]
maxWork -= subjects[currentBest][1]
return subjectsToTake
def bruteForceAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work), which
represents the globally optimal selection of subjects using a brute force
algorithm.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
subset, subsetValue, subsetWork):
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
return subset[:], subsetValue
else:
# Keep the current best.
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK])
subset.pop()
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork)
return bestSubset, bestSubsetValue
#
# Problem 3: Subject Selection By Brute Force
#
def bruteForceTime():
"""
Runs tests on bruteForceAdvisor and measures the time required to compute
an answer.
"""
start = time.time()
print "Starting brute force"
print bruteForceAdvisor(loadSubjects('subjects.txt'), 9)
print "Ending brute force, took %0.2f seconds" % (time.time() - start)
# Problem 3 Observations
# ======================
#
# Anything over 8 for maxWork is unreasonable (10+ seconds is too much)
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjectsInfoDict, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjectsInfoDict that provides the maximum value without exceeding maxWork.
subjectsInfoDict: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
selectedSubjectsDict = {}
# Just the subject names
subjects = subjectsInfoDict.keys()
# Just the subject workload/value pairs
workloadValueTuples = subjectsInfoDict.values()
# Start searching for the optimal selection, starting at the top of
# the subjects stack
maxValue, selectedSubjects = dpAdvisorHelper(subjects, workloadValueTuples, len(subjects) - 1, maxWork, (), {})
for subject in selectedSubjects:
selectedSubjectsDict[subject] = subjectsInfoDict[subject]
return selectedSubjectsDict
def dpAdvisorHelper(subjects, workloadValueTuples, index, maxWork, selectedSubjects, memo):
memoIndex = (index, maxWork)
# Check if the current index/maxWork combination is memoized
try: return memo[memoIndex]
except KeyError: pass
# Index 0 means we are at the last subject
if index == 0:
# If we have room, include it, if not, do not
if workloadValueTuples[index][1] <= maxWork:
memo[memoIndex] = (workloadValueTuples[index][0], (subjects[index],))
else:
memo[memoIndex] = (0, ())
return memo[memoIndex]
# Selections if we do not choose the current subject
withoutCurrentSubject = dpAdvisorHelper(subjects, workloadValueTuples, index - 1, maxWork, selectedSubjects, memo)
# If we cannot include the current subject, then skip it
if workloadValueTuples[index][1] > maxWork:
memo[memoIndex] = withoutCurrentSubject
return memo[memoIndex]
# Get the selected subjects and maximum value with the current
# subject selected
withValue, withSelected = dpAdvisorHelper(subjects, workloadValueTuples, index - 1, maxWork - workloadValueTuples[index][1], selectedSubjects, memo)
withValue += workloadValueTuples[index][0]
without_value, without_selected = withoutCurrentSubject
# Compare the two and determine which one is better
if withValue > without_value:
memo[memoIndex] = (withValue, (subjects[index],) + withSelected)
else:
memo[memoIndex] = withoutCurrentSubject
return memo[memoIndex]
#
# Problem 5: Performance Comparison
#
def dpTime():
"""
Runs tests on dpAdvisor and measure the time required to compute
an answer.
"""
start = time.time()
print "Starting dp"
print dpAdvisor(loadSubjects('subjects.txt'), 30)
print "Ending dp, took %0.2f seconds" % (time.time() - start)
dpTime()
printSubjects(dpAdvisor(loadSubjects('subjects.txt'), 30))
# Problem 5 Observations
# ======================
#
# As the input and maximum workload grows, the dpAdvisor function gets much
# faster than the bruteForceAdvisor function. With the subjects loaded from
# the subjects.txt file and a maximum workload of 9, dpAdvisor is 2226 times
# faster.
No comments. Sign up or log in to comment problem 4 is really tough. I peeked someone else's code. I suggest read more about dynamic programming. # 6.00 Problem Set 8
#
# Intelligent Course Advisor
#
# Name: Joe Li
# Time: 10:00
#
import time
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
#
# Problem 1: Building A Subject Dictionary
#
def loadSubjects(filename):
"""
Returns a dictionary mapping subject name to (value, work), where the name
is a string and the value and work are integers. The subject information is
read from the file named by the string filename. Each line of the file
contains a string of the form "name,value,work".
returns: dictionary mapping subject name to (value, work)
"""
# The following sample code reads lines from the specified file and prints
# each one.
inputFile = open(filename)
d={}
for line in inputFile:
line = line.split(',')
subject = line[0]
value = int(line[1])
work = int(line[2].strip())
d[subject]=(value, work)
return d
# TODO: Instead of printing each line, modify the above to parse the name,
# value, and work of each subject and create a dictionary mapping the name
# to the (value, work).
subjects=loadSubjects(SUBJECT_FILENAME)
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
return val1 > val2
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return work1 < work2
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return float(val1) / work1 > float(val2) / work2
#
# Problem 2: Subject Selection By Greedy Optimization
#
def greedyAdvisor(subjects, maxWork, comparator):
"""
Returns a dictionary mapping subject name to (value, work) which includes
subjects selected by the algorithm, such that the total work of subjects in
the dictionary is not greater than maxWork. The subjects are chosen using
a greedy algorithm. The subjects dictionary should not be mutated.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
comparator: function taking two tuples and returning a bool
returns: dictionary mapping subject name to (value, work)
"""
assert type(subjects) == dict, 'subjects should be dictionary'
assert type(maxWork) == int and maxWork >= 0, 'maxWork should be non-negative int'
work = 0
choice = {}
sub=subjects.copy()
while work < maxWork:
b = []
# b is a list which contains all the best sub in one travserse
for s in sub:
best = True
# assume such subject is the best one
if work + sub[s][WORK] <= maxWork:
# if work load exceeds limit after addition,
# then we don't even consider such subject
for others in sub:
if work + sub[others][WORK] <= maxWork:
# the other subjected must also under the work limit
# otherwise the best may not be found
# because the best may beyond the work limit
if best == True and comparator(sub[others], sub[s]):
# as soon as such subject turns out not the best
# then the comparason is saved
best = False
# if there is another subject better than such one
# such one cannot be the best, skip the following
if best == True:
# if such subject is the best one
choice[s] = sub[s]
# choose this subject
b.append(s)
# delete the subject from dictionary later
# otherwise it will be found again
work += choice[s][WORK]
if b != []:
# if there are best ones found
for d in b:
del sub[d]
# delete them all
else:
# if no best one found, which may be caused by work load limit,
# or there's nothing left in the sub
return choice
# jump out of the loop if work == maxWork
return choice
def bruteForceAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work), which
represents the globally optimal selection of subjects using a brute force
algorithm.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
subset, subsetValue, subsetWork):
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
return subset[:], subsetValue
else:
# Keep the current best.
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK])
subset.pop()
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork)
return bestSubset, bestSubsetValue
#
# Problem 3: Subject Selection By Brute Force
#
def bruteForceTime():
"""
Runs tests on bruteForceAdvisor and measures the time required to compute
an answer.
"""
for maxWork in range(9):
start_time = time.time()
bruteForceAdvisor(subjects, maxWork)
end_time = time.time()
time_used = round(end_time - start_time,3)
print 'maxWork:', maxWork, 'time:', time_used
# Problem 3 Observations
# ======================
#
# maxWork time_used(s)
# maxWork: 0 time: 0.001
# maxWork: 1 time: 0.004
# maxWork: 2 time: 0.015
# maxWork: 3 time: 0.058
# maxWork: 4 time: 0.193
# maxWork: 5 time: 0.689
# maxWork: 6 time: 2.008
# maxWork: 7 time: 6.106
# maxWork: 8 time: 16.679
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
name, v, w = extract(subjects)
subIndex = range(len(subjects))
workCap = range(maxWork+1)
A = {}
# A[(subIndex, workCap)]: int - given subjects in name[0:subIndex]
# and work load limit workCap, the best value we can get
B = {}
# B[(subIndex, workCap)]: list - all the subjects chosen to get the above value
for i in subIndex:
# set base case
A[(i, 0)] = 0
B[(i, 0)] = []
for j in workCap:
A[(0, j)] = 0
B[(0, j)] = []
for i in subIndex[1:]:
# base case excluded
for j in workCap[1:]:
if w[i] > j:
# if work load limit exeeds, don't take it
A[(i, j)] = A[(i - 1,j)]
B[(i, j)] = B[(i - 1,j)]
else:
if v[i] + A[(i - 1, j - w[i])] > A[(i - 1 ,j)]:
# if worth taking it, take it and store the choice to B
A[(i, j)] = v[i] + A[(i - 1, j - w[i])]
B[(i, j)] = B[(i - 1, j - w[i])]+[name[i]]
else:
# if not worth taking it, don't take it
A[(i, j)] = A[(i - 1, j)]
B[(i, j)] = B[(i - 1,j)]
output={}
for name in B[(len(subjects)-1,maxWork)]:
# to get the form as same as subjects
output[name] = (subjects[name][VALUE], subjects[name][WORK])
return output
def extract(subjects):
"""
input: type(subjects) == dict subjects[name] = (VALUE, WORK)
output: name[i] = name, value[i] = VALUE, work[i] = WORK
"""
name=[]
value=[]
work=[]
for j in subjects:
name.append(j)
value.append(subjects[j][VALUE])
work.append(subjects[j][WORK])
return name, value, work
#
# Problem 5: Performance Comparison
#
def dpTime():
"""
Runs tests on dpAdvisor and measures the time required to compute an
answer.
"""
for maxWork in range(8):
start_time = time.time()
dpAdvisor(subjects, maxWork)
end_time = time.time()
time_used = round(end_time - start_time,3)
print 'maxWork:', maxWork, 'time:', time_used
# Problem 5 Observations
# ======================
#
# maxWork: 0 time: 0.001
# maxWork: 1 time: 0.002
# maxWork: 2 time: 0.003
# maxWork: 3 time: 0.003
# maxWork: 4 time: 0.007
# maxWork: 5 time: 0.006
# maxWork: 6 time: 0.006
# maxWork: 7 time: 0.007
No comments. Sign up or log in to comment # 6.00 Problem Set 8
#
# Intelligent Course Advisor
#
# Name: Alex
#
import time
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
#
# Problem 1: Building A Subject Dictionary
#
def loadSubjects(filename):
"""
Returns a dictionary mapping subject name to (value, work), where the name
is a string and the value and work are integers. The subject information is
read from the file named by the string filename. Each line of the file
contains a string of the form "name,value,work".
returns: dictionary mapping subject name to (value, work)
"""
# The following sample code reads lines from the specified file and prints
# each one.
inputFile = open(filename)
subject_dict = {}
for line in inputFile:
name, value, work = line.split(',')
value = int(value)
work = int(work.strip())
subject_dict[name] = (value, work)
return subject_dict
# TODO: Instead of printing each line, modify the above to parse the name,
# value, and work of each subject and create a dictionary mapping the name
# to the (value, work).
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
if val1 > val2:
return 1
else:
return -1
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
if work1 < work2:
return 1
else:
return -1
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
if float(val1) / work1 > float(val2) / work2:
return 1
else:
return -1
#
# Problem 2: Subject Selection By Greedy Optimization
#
def greedyAdvisor(subjects, maxWork, comparator):
"""
Returns a dictionary mapping subject name to (value, work) which includes
subjects selected by the algorithm, such that the total work of subjects in
the dictionary is not greater than maxWork. The subjects are chosen using
a greedy algorithm. The subjects dictionary should not be mutated.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
comparator: function taking two tuples and returning a bool
returns: dictionary mapping subject name to (value, work)
"""
adv_subjects = {}
work_cnt = 0
tmp_subj = [(v, w, n) for n, (v, w) in subjects.iteritems()]
for v, w, n in sorted(tmp_subj, cmp=comparator, reverse=True):
if (work_cnt + w < maxWork):
adv_subjects[n] = (v, w)
work_cnt += w
else:
break
return adv_subjects
def bruteForceAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work), which
represents the globally optimal selection of subjects using a brute force
algorithm.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
subset, subsetValue, subsetWork):
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
return subset[:], subsetValue
else:
# Keep the current best.
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK])
subset.pop()
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork)
return bestSubset, bestSubsetValue
#
# Problem 3: Subject Selection By Brute Force
#
def bruteForceTime():
"""
Runs tests on bruteForceAdvisor and measures the time required to compute
an answer.
"""
filename = 'subjects.txt'
max_work = 5
subject_dict = loadSubjects(filename)
start_time = time.time()
adv_subjects = bruteForceAdvisor(subject_dict, max_work)
end_time = time.time()
total_time = end_time - start_time
printSubjects(adv_subjects)
print "Total time with max_work = %d is %0.4f seconds" %(max_work, total_time)
# Problem 3 Observations
# ======================
#
# TODO: write here your observations regarding bruteForceTime's performance
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
dpAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0, {})
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
def dpAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
subset, subsetValue, subsetWork, memo):
global numCalls
numCalls += 1
try: return memo[0]
except KeyError:
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
memo[0] = subset[:], subsetValue
return subset[:], subsetValue
else:
# Keep the current best.
memo[0] = bestSubset, bestSubsetValue
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = dpAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK], memo)
subset.pop()
bestSubset, bestSubsetValue = dpAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork, memo)
memo[0] = bestSubset, bestSubsetValue
return bestSubset, bestSubsetValue
#
# Problem 5: Performance Comparison
#
def dpTime():
"""
Runs tests on dpAdvisor and measures the time required to compute an
answer.
"""
filename = 'subjects.txt'
max_work = 15
# subject_dict = loadSubjects(filename)
subject_dict = {'6.00': (16, 8), '1.00': (7, 7), '6.01': (5, 3), '15.01': (9, 6)}
# start_time = time.time()
adv_subjects = dpAdvisor(subject_dict, max_work)
print numCalls
# end_time = time.time()
printSubjects(adv_subjects)
adv_subjects = bruteForceAdvisor(subject_dict, max_work)
# print numCalls
# total_time = end_time - start_time
printSubjects(adv_subjects)
# print "Total time with max_work = %d is %0.4f seconds" %(max_work, total_time)
numCalls = 0
dpTime()
No comments. Sign up or log in to comment # 6.00 Problem Set 8
#
# Intelligent Course Advisor
#
# Name:
# Collaborators:
# Time:
#
import time
SUBJECT_FILENAME = "subjects.txt"
VALUE, WORK = 0, 1
#
# Problem 1: Building A Subject Dictionary
#
def loadSubjects(filename):
"""
Returns a dictionary mapping subject name to (value, work), where the name
is a string and the value and work are integers. The subject information is
read from the file named by the string filename. Each line of the file
contains a string of the form "name,value,work".
returns: dictionary mapping subject name to (value, work)
"""
# The following sample code reads lines from the specified file and prints
# each one.
inputFile = open(filename)
subjectDict = {}
for line in inputFile:
templist = []
templist += line.strip().split(',')
subjectDict[templist[0]] = (int(templist[1]),int(templist[2]))
return subjectDict
def printSubjects(subjects):
"""
Prints a string containing name, value, and work of each subject in
the dictionary of subjects and total value and work of all subjects
"""
totalVal, totalWork = 0,0
if len(subjects) == 0:
return 'Empty SubjectList'
res = 'Course\tValue\tWork\n======\t====\t=====\n'
subNames = subjects.keys()
subNames.sort()
for s in subNames:
val = subjects[s][VALUE]
work = subjects[s][WORK]
res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
totalVal += val
totalWork += work
res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
res = res + 'Total Work:\t' + str(totalWork) + '\n'
print res
def cmpValue(subInfo1, subInfo2):
"""
Returns True if value in (value, work) tuple subInfo1 is GREATER than
value in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
return val1 > val2
def cmpWork(subInfo1, subInfo2):
"""
Returns True if work in (value, work) tuple subInfo1 is LESS than than work
in (value, work) tuple in subInfo2
"""
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return work1 < work2
def cmpRatio(subInfo1, subInfo2):
"""
Returns True if value/work in (value, work) tuple subInfo1 is
GREATER than value/work in (value, work) tuple in subInfo2
"""
val1 = subInfo1[VALUE]
val2 = subInfo2[VALUE]
work1 = subInfo1[WORK]
work2 = subInfo2[WORK]
return float(val1) / work1 > float(val2) / work2
#
# Problem 2: Subject Selection By Greedy Optimization
#
def greedyAdvisor(subjects, maxWork, comparator):
"""
Returns a dictionary mapping subject name to (value, work) which includes
subjects selected by the algorithm, such that the total work of subjects in
the dictionary is not greater than maxWork. The subjects are chosen using
a greedy algorithm. The subjects dictionary should not be mutated.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
comparator: function taking two tuples and returning a boolean
returns: dictionary mapping subject name to (value, work)
"""
temp_dict = subjects.copy()
select_dict = {}
totalWork = 0
while totalWork < maxWork:
best = temp_dict.keys()[-1]
for i in temp_dict:
if comparator(temp_dict[i], temp_dict[best]):
best = i
if totalWork + temp_dict[best][WORK] <= maxWork:
select_dict[best] = temp_dict.pop(best)
totalWork += select_dict[best][WORK]
else:
break
return select_dict
def bruteForceAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work), which
represents the globally optimal selection of subjects using a brute force
algorithm.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
bestSubset, bestSubsetValue = \
bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
outputSubjects = {}
for i in bestSubset:
outputSubjects[nameList[i]] = tupleList[i]
return outputSubjects
def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
subset, subsetValue, subsetWork):
# Hit the end of the list.
if i >= len(subjects):
if bestSubset == None or subsetValue > bestSubsetValue:
# Found a new best.
return subset[:], subsetValue
else:
# Keep the current best.
return bestSubset, bestSubsetValue
else:
s = subjects[i]
# Try including subjects[i] in the current working subset.
if subsetWork + s[WORK] <= maxWork:
subset.append(i)
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue + s[VALUE], subsetWork + s[WORK])
subset.pop()
bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
maxWork, i+1, bestSubset, bestSubsetValue, subset,
subsetValue, subsetWork)
return bestSubset, bestSubsetValue
#
# Problem 3: Subject Selection By Brute Force
#
def bruteForceTime(maxWork):
"""
Runs tests on bruteForceAdvisor and measures the time required to compute
an answer.
"""
start_time = time.time()
bruteForceAdvisor(subjects, maxWork)
end_time = time.time()
total_time = end_time - start_time
return total_time
# Problem 3 Observations
# ======================
#
# The order of bruteForceAdvisor is clearly exponential in maxWork.
#
# Problem 4: Subject Selection By Dynamic Programming
#
def dpAdvisor(subjects, maxWork):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)
"""
nameList = subjects.keys()
tupleList = subjects.values()
optimal_value, optimal_tuple = dpAdvisorHelper(maxWork, len(subjects)-1, nameList, tupleList, (), {})
optimal_dict = {}
for i in optimal_tuple:
optimal_dict[i] = subjects[i]
return optimal_dict
def dpAdvisorHelper(maxWork, index, nameList, tupleList, best_tuple, memo):
"""
Returns a dictionary mapping subject name to (value, work) that contains a
set of subjects that provides the maximum value without exceeding maxWork.
subjects: dictionary mapping subject name to (value, work)
maxWork: int >= 0
returns: dictionary mapping subject name to (value, work)"""
#try and return the stored solution
try:
return memo[(index, maxWork)][0], memo[(index, maxWork)][1]
except KeyError:
# base case returns nothing if won't fit or the items if it does.
if index == 0:
if tupleList[index][WORK] <= maxWork:
best_tuple += (nameList[index],)
memo[(index, maxWork)] = (tupleList[index][VALUE], best_tuple)
return tupleList[index][VALUE], best_tuple
else:
memo[(index, maxWork)] = (0, best_tuple)
return 0, best_tuple
# if the course won't fit then skip it.
without_value, without_tuple = dpAdvisorHelper(maxWork, index-1, nameList, tupleList, best_tuple, memo)
if tupleList[index][WORK] > maxWork:
memo[(index, maxWork)] = (without_value, without_tuple)
return without_value, without_tuple
# if the course will fit then choose the better value of adding the item or skipping it.
else:
with_value, with_tuple = dpAdvisorHelper(maxWork - tupleList[index][WORK], index-1, nameList, tupleList, best_tuple, memo)
total_with_value = with_value + tupleList[index][VALUE]
if total_with_value > without_value:
best_tuple = with_tuple + (nameList[index],)
memo[(index, maxWork)] = (total_with_value, best_tuple)
return total_with_value, best_tuple
else:
return without_value, without_tuple
#
# Problem 5: Performance Comparison
#
def dpTime(maxWork):
"""
Runs tests on dpAdvisor and measures the time required to compute an
answer.
"""
start_time = time.time()
dpAdvisor(subjects, maxWork)
end_time = time.time()
total_time = end_time - start_time
return total_time
# Problem 5 Observations
# ======================
#
# TODO: write here your observations regarding dpAdvisor's performance and
# how its performance compares to that of bruteForceAdvisor.
subjects = loadSubjects(SUBJECT_FILENAME)
smallset = {'6.00':(16, 8),'1.00':(7,7), '6.01':(5,3), '15.01':(9,6)}
No comments. Sign up or log in to comment |
No comments. Sign up or log in to comment