PageRenderTime 1044ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/ps8.py

https://bitbucket.org/c4nn1b4l/mit-introduction-to-computer-science-and-programming-python-3
Python | 297 lines | 278 code | 8 blank | 11 comment | 0 complexity | 2753f0c1b1fa69abba9fab448d787a91 MD5 | raw file
  1. # 6.00 Problem Set 8
  2. #
  3. # Intelligent Course Advisor
  4. #
  5. # Name: c4nn1b4l
  6. import time
  7. import copy
  8. SUBJECT_FILENAME = "subjects.txt"
  9. VALUE, WORK = 0, 1
  10. measuredDataBrute = open('ps8measuredbrute.txt', 'w')
  11. measuredDataDp = open('ps8measureddp.txt', 'w')
  12. # Problem 1: Building A Subject Dictionary
  13. #
  14. def loadSubjects(filename):
  15. """
  16. Returns a dictionary mapping subject name to (value, work), where the name
  17. is a string and the value and work are integers. The subject information is
  18. read from the file named by the string filename. Each line of the file
  19. contains a string of the form "name,value,work".
  20. returns: dictionary mapping subject name to (value, work)
  21. """
  22. subValWork = {}
  23. inputFile = open(filename)
  24. for line in inputFile:
  25. namValWor = (line.strip('/n')).split(',')
  26. subValWork[str(namValWor[0])] = ( int(namValWor[1]), int(namValWor[2]) )
  27. return subValWork
  28. def printSubjects(subjects):
  29. """
  30. Prints a string containing name, value, and work of each subject in
  31. the dictionary of subjects and total value and work of all subjects
  32. """
  33. totalVal, totalWork = 0,0
  34. if len(subjects) == 0:
  35. return 'Empty SubjectList'
  36. res = 'Course\tValue\tWork\n======\t====\t=====\n'
  37. subNames = list(subjects.keys())
  38. subNames.sort()
  39. for s in subNames:
  40. val = subjects[s][0]
  41. work = subjects[s][1]
  42. res = res + s + '\t' + str(val) + '\t' + str(work) + '\n'
  43. totalVal += val
  44. totalWork += work
  45. res = res + '\nTotal Value:\t' + str(totalVal) +'\n'
  46. res = res + 'Total Work:\t' + str(totalWork) + '\n'
  47. print(res)
  48. def cmpValue(subInfo1, subInfo2):
  49. """
  50. Returns True if value in (value, work) tuple subInfo1 is GREATER than
  51. value in (value, work) tuple in subInfo2
  52. """
  53. val1 = subInfo1[0]
  54. val2 = subInfo2[0]
  55. return val1 > val2
  56. def cmpWork(subInfo1, subInfo2):
  57. """
  58. Returns True if work in (value, work) tuple subInfo1 is LESS than than work
  59. in (value, work) tuple in subInfo2
  60. """
  61. work1 = subInfo1[1]
  62. work2 = subInfo2[1]
  63. return work1 < work2
  64. def cmpRatio(subInfo1, subInfo2):
  65. """
  66. Returns True if value/work in (value, work) tuple subInfo1 is
  67. GREATER than value/work in (value, work) tuple in subInfo2
  68. """
  69. val1 = subInfo1[0]
  70. val2 = subInfo2[0]
  71. work1 = subInfo1[1]
  72. work2 = subInfo2[1]
  73. return float(val1) / work1 > float(val2) / work2
  74. # Problem 2: Subject Selection By Greedy Optimization
  75. #
  76. def greedyAdvisor(subjects, maxWork, comparator):
  77. """
  78. Returns a dictionary mapping subject name to (value, work) which includes
  79. subjects selected by the algorithm, such that the total work of subjects in
  80. the dictionary is not greater than maxWork. The subjects are chosen using
  81. a greedy algorithm. The subjects dictionary should not be mutated.
  82. subjects: dictionary mapping subject name to (value, work)
  83. maxWork: int >= 0
  84. comparator: function taking two tuples and returning a bool
  85. returns: dictionary mapping subject name to (value, work)
  86. """
  87. currentWork = 0
  88. answer = {}
  89. subjectsMutable = list( subjects.keys() )
  90. while True:
  91. maxVal = ""
  92. #seraching for the maximum value
  93. for subji in subjectsMutable:
  94. if len(maxVal) == 0:
  95. maxVal = subji
  96. elif comparator(subjects[subji], subjects[maxVal]):
  97. maxVal = subji
  98. #ensuring not to exceed maxWork, i know it's ugly but i got frustrated over a sitcom so i just wanted to make it work, asap
  99. #shitty excuse is shitty
  100. if currentWork <= maxWork:
  101. if maxVal == "":
  102. break
  103. elif subjects[maxVal][1] + currentWork <= maxWork:
  104. answer[maxVal] = subjects[maxVal]
  105. subjectsMutable.remove(maxVal)
  106. currentWork += subjects[maxVal][1]
  107. #print(currentWork, answer) #debug stuff
  108. else:
  109. try:
  110. subjectsMutable.remove(maxVal)
  111. except KeyError:
  112. break
  113. else:
  114. break
  115. return answer
  116. def bruteForceAdvisor(subjects, maxWork):
  117. """
  118. Returns a dictionary mapping subject name to (value, work), which
  119. represents the globally optimal selection of subjects using a brute force
  120. algorithm.
  121. subjects: dictionary mapping subject name to (value, work)
  122. maxWork: int >= 0
  123. returns: dictionary mapping subject name to (value, work)
  124. """
  125. nameList = list(subjects.keys())
  126. tupleList = list(subjects.values())
  127. bestSubset, bestSubsetValue = \
  128. bruteForceAdvisorHelper(tupleList, maxWork, 0, None, None, [], 0, 0)
  129. outputSubjects = {}
  130. for i in bestSubset:
  131. outputSubjects[nameList[i]] = tupleList[i]
  132. return outputSubjects
  133. def bruteForceAdvisorHelper(subjects, maxWork, i, bestSubset, bestSubsetValue,
  134. subset, subsetValue, subsetWork):
  135. # Hit the end of the list.
  136. if i >= len(subjects):
  137. if bestSubset == None or subsetValue > bestSubsetValue:
  138. # Found a new best.
  139. return subset[:], subsetValue
  140. else:
  141. # Keep the current best.
  142. return bestSubset, bestSubsetValue
  143. else:
  144. s = subjects[i]
  145. # Try including subjects[i] in the current working subset.
  146. if subsetWork + s[WORK] <= maxWork:
  147. subset.append(i)
  148. bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
  149. maxWork, i+1, bestSubset, bestSubsetValue, subset,
  150. subsetValue + s[VALUE], subsetWork + s[WORK])
  151. subset.pop()
  152. bestSubset, bestSubsetValue = bruteForceAdvisorHelper(subjects,
  153. maxWork, i+1, bestSubset, bestSubsetValue, subset,
  154. subsetValue, subsetWork)
  155. return bestSubset, bestSubsetValue
  156. # Problem 3: Subject Selection By Brute Force
  157. #
  158. def timeOutHandler(signum, frame):
  159. raise Exception("TimedOut")
  160. def bruteForceTime(subjects, timeOut):
  161. """
  162. Runs tests on bruteForceAdvisor and measures the time required to compute
  163. an answer.
  164. timeOut: the maximum time the function waits for bruteForceAdvisor before terminating
  165. """
  166. maxWork = 0
  167. while True:
  168. maxWork += 1
  169. startTime = time.time()
  170. # print(maxWork, bruteForceAdvisor(subjects, maxWork))
  171. bruteForceAdvisor(subjects, maxWork)
  172. endTime = time.time()
  173. # print('Maximum work:',maxWork,'time:',(endTime - startTime))
  174. otime = endTime - startTime
  175. result = str(maxWork) + ',' + str(otime) + '\n'
  176. measuredDataBrute.write(result)
  177. if (endTime - startTime) >= timeOut:
  178. break
  179. #bruteForceTime(loadSubjects(SUBJECT_FILENAME), 20)
  180. # Problem 3 Observations
  181. # ======================
  182. #
  183. # Nothing particular. Tried to implement a version, where the function would have terminated the
  184. # bruteForceAdvisor when it reached the time limit, but i would have produced a *nix only code,
  185. # and did not wanted to get an unportable code.
  186. # Also bruteForceAdvisor runtime grows exponentially.
  187. #
  188. # Problem 4: Subject Selection By Dynamic Programming
  189. #
  190. def dpAdvisor(subjects, maxWork):
  191. """
  192. Returns a dictionary mapping subject name to (value, work) that contains a
  193. set of subjects that provides the maximum value without exceeding maxWork.
  194. subjects: dictionary mapping subject name to (value, work)
  195. maxWork: int >= 0
  196. returns: dictionary mapping subject name to (value, work)
  197. """
  198. memi = {}
  199. nameList = list(subjects.keys())
  200. valueList = []
  201. workList = []
  202. for each in subjects:
  203. valueList.append(subjects[each][VALUE])
  204. workList.append(subjects[each][WORK])
  205. answer = {}
  206. value, answerList = dpAdvisorHelper(workList, valueList, len(workList) - 1, maxWork, memi)
  207. for item in answerList:
  208. answer[nameList[item]] = (valueList[item],workList[item])
  209. return answer
  210. def dpAdvisorHelper(w,v,i,aW,m):
  211. try:
  212. return m[(i,aW)]
  213. except KeyError:
  214. if i == 0:
  215. if w[i] < aW:
  216. m[(i,aW)] = v[i], [i]
  217. return v[i],[i]
  218. else:
  219. m[(i,aW)] = 0, []
  220. return 0,[]
  221. without_i, course_list = dpAdvisorHelper(w,v,i-1,aW,m)
  222. if w[i] > aW:
  223. m[(i,aW)] = without_i, course_list
  224. return without_i, course_list
  225. else:
  226. with_i, course_list_temp = dpAdvisorHelper(w, v, i-1, aW - w[i], m)
  227. with_i += v[i]
  228. if with_i > without_i:
  229. i_value = with_i
  230. course_list = [i] + course_list_temp
  231. else:
  232. i_value = without_i
  233. m[(i,aW)] = i_value, course_list
  234. return i_value, course_list
  235. #
  236. # Problem 5: Performance Comparison
  237. #
  238. def dpTime(subjects, timeOut):
  239. """
  240. Runs tests on dpAdvisor and measures the time required to compute an
  241. answer.
  242. """
  243. maxWork = 0
  244. while True:
  245. maxWork += 1
  246. startTime = time.time()
  247. # print(maxWork, dpAdvisor(subjects, maxWork))
  248. dpAdvisor(subjects, maxWork)
  249. endTime = time.time()
  250. # print('Maximum work:',maxWork,'time:',(endTime - startTime))
  251. otime = endTime - startTime
  252. result = str(maxWork) + ',' + str(otime) + '\n'
  253. measuredDataDp.write(result)
  254. if (endTime - startTime) >= timeOut:
  255. break
  256. # # Problem 5 Observations
  257. # # ======================
  258. # #
  259. # # WOW, that's fast! :)