utils.py 8.33 KB
Newer Older
1
from mainapp.models import Course, Semester, Trajectory # import more
Daniel W Bond's avatar
Daniel W Bond committed
2

3
### common functionality
4

5 6
def programCourses(program):

7
    courses = []
Chris Reffett's avatar
Chris Reffett committed
8 9 10 11
    requirements = program.requirements
    for requirement in requirements.all():
        for course in requirement.courses.all():
            courses.append(course)
12

13
    return courses
14

Chris Reffett's avatar
Chris Reffett committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
def genDepTree(course):
    toscan = []
    courseset = set(course)
    for prerequisite in course.prerequisites:
        toscan.add(course)
    for corequisite in course.corequisites:
        toscan.add(course)

    for elem in toscan:
        recursiveDepTree(elem, courseset)

def recursiveDepTree(course, courseset):
    toscan = []
    courseset.add(course)
    for prerequisite in course.prerequisites:
        toscan.append(course)
    for corequisite in course.corequisites:
        toscan.append(course)

    if len(toscan) == 0:
        return
    for elem in toscan:
        if elem not in courseset:
            recursiveDepTree(elem, courseset)

40 41 42 43 44 45
### creating a trajectory

#def maxProgramsAllowed():
#    """ the maximum programs allowed, e.g. 2 majors and 3 minors tops """
#   return True

46
### automatically building a trajectory
Daniel W Bond's avatar
Daniel W Bond committed
47

48 49
def assignedWeights(weightedCourse, programCourses):
    """ assign weights to all courses in a program for automation """
50

51 52
    for weightedCourse in programCourses:
        weightedCourseCounter = 0
53
        reqs = set()
54 55 56 57
        for prereq in weightedCourse.preq:
            reqs.add(prereq)
        for coreq in weightedCourse.coreq:
            reqs.add(coreq)
58 59
        for req in reqs:
            for course in programCourses:
60
                childReqList = []
61
                if req is course:
62 63
                    weightedCourseCounter += 1
                    childReqList.append(course)
64
                    assignedWeights(course, childReqList)
65

66
        weights[weightedCourse] = weightedCourseCounter
67

68
    return weights
Daniel W Bond's avatar
Daniel W Bond committed
69

Daniel W Bond's avatar
Daniel W Bond committed
70
def courseWeighting(programCourses):
71
    """ a helper function for properly recursing """
Daniel W Bond's avatar
Daniel W Bond committed
72 73 74 75 76 77 78 79 80

    weights = {}

    weightedCourse = programCourses[0]

    assignedWeights(weightedCourse, programCourses)

    return weights    

81
def customAssignedWeights(weights, selectedCourses):
82 83
    """ remove courses that a student has not selected from the weighted
        courses """
84
    customweights = weights
85 86

    for course in selectedCourses:
87
        del customweights[course]
88

89
    return customweights
90

91
### editing a trajectory
Daniel W Bond's avatar
Daniel W Bond committed
92

93
def requirementsFulfilled(taken, program):
94 95
    """ for *A* program, return a list of all requirements fulfilled """

96 97
    fulfilled = []
    taken = set(taken)
98
    requirements = program.requirements
99

100
    for requirement in requirements:
101 102
        for coursegroup in requirement.coursegroup:
            courseRequirements = set(coursegroup.courses)
103 104
            requirementCoursesTaken = courseRequirements.intersection(alreadyTaken)

105
            if len(requirementCoursesTaken) is requirement.coursegroup.numneeded:
106
                fulfilled.append(requirement)
Daniel W Bond's avatar
Daniel W Bond committed
107 108
    
    # this should return true or false
109
    return fulfilled
Daniel W Bond's avatar
Daniel W Bond committed
110

111

112 113 114 115
#def alreadyTaken():
#    """ return all of the courses that a student has already taken so far
#        in the trajectory """
#    return True
116

117
def remainingReqCourses(taken, programCourses):
118 119
    """ returns the remaining required courses for a program given
    the already taken courses """
Daniel W Bond's avatar
Daniel W Bond committed
120

121
    taken = set(taken)
122
    programCourses = set(programCourses)
Daniel W Bond's avatar
Daniel W Bond committed
123

124
    remainingReqCourses = programCourses.difference(taken)
125 126

    return remainingReqCourses
Daniel W Bond's avatar
Daniel W Bond committed
127

128
def nextCourses(remainingReqCourses, taken):
Daniel W Bond's avatar
Daniel W Bond committed
129
    """ which courses you can take next based on prereqs and coreqs, given
130
        already taken courses and remaining required courses """
131
    nextcourses = []
132 133
    for course in remainingReqCourses:
        reqs = set()
Ben Waters's avatar
Ben Waters committed
134 135 136 137
        try:
            c = Course.objects.get(title=course)
        except:
           pass 
Ben Waters's avatar
Ben Waters committed
138
        for prereq in c.prerequisites.all():
139
            reqs.add(prereq)
140 141
        #for coreq in course.coreq:
        #    reqs.add(coreq)
142
        for req in reqs:
143 144
            if req in taken:
                nextcourses.append(course)
Daniel W Bond's avatar
Daniel W Bond committed
145

Chris Reffett's avatar
Chris Reffett committed
146

147
    return nextCourses
Daniel W Bond's avatar
Daniel W Bond committed
148

149 150 151 152 153
# IMPLEMENT THIS IN JS!
#def maxCreditsAllowed():
#    """ the maximum credits allowed for a semester-- returns different values
#        to warn or disallow if maximum credits are touched or exceeded """

154
def findDependencies(deletedCourse, semester):
Daniel W Bond's avatar
Daniel W Bond committed
155 156
    """ if a student removes a course while editing, find all courses
        that have require the removed courses """
157
    foundDependencies = []
158 159
    for suspectCourse in semester.nextSemester.courses:
        reqs = set()
160
        for prereq in suspectCourse.preq:
161 162
            if prereq is deletedCourse:
                reqs.append(foundDependencies)
163
        for coreq in suspectCourse.coreq:
164 165
            if coreq is deletedCourse:
                reqs.append(foundDependencies)
166

167
    findDependencies(deletedCourse, semester.nextSemester)
168

169
    return foundDependencies
Daniel W Bond's avatar
Daniel W Bond committed
170

Daniel W Bond's avatar
Daniel W Bond committed
171
def enoughCredits(previousCourses, numRequired):
Daniel W Bond's avatar
Daniel W Bond committed
172
    """ checks if enough credits have been taken to graduate """
173
    enoughcredits = False
Daniel W Bond's avatar
Daniel W Bond committed
174 175 176 177 178
    numTaken = 0
    for course in previousCourses:
        numTaken += course.credits
    
    if numTaken >= numRequired:
179
        enoughcredits = True
Daniel W Bond's avatar
Daniel W Bond committed
180

181
    return enoughcredits
Daniel W Bond's avatar
Daniel W Bond committed
182

183 184

def genTrajectories(taken, programs, user):
185 186
    if not taken:
        taken = ['']
187
    taken = set(taken)
Chris Reffett's avatar
changes  
Chris Reffett committed
188 189
    print taken
    sem = Semester(number=0, user=user)
Chris Reffett's avatar
Chris Reffett committed
190
    sem.save()
Chris Reffett's avatar
changes  
Chris Reffett committed
191 192 193 194
    for takencourse in taken:
        takencourse.semester=sem
    sem.courses = taken
    sem.programs = programs
195 196 197 198 199 200 201
    try:
        tj = Trajectory.objects.get(user=user)
    except:
        tj = Trajectory(user=user)
        tj.save()
    tj.semesters=[sem]
    programcourses = []
202
    for program in programs:
203 204
        programcourses = programcourses + programCourses(program)
    remainingCourses=remainingReqCourses(taken, programcourses)
205 206 207 208 209 210 211 212 213
    while True:
        availableCourses=nextCourses(remainingCourses, taken)
        semclasses=[]
        for i in xrange(5):
            doneclass = availableCourses.pop()
            semclasses.append(doneclass)
            taken.add(doneclass)
        newsem = Semester(number=sem.number+1, user=user, courses=semclasses,
            programs=programs)
Chris Reffett's avatar
Chris Reffett committed
214
        tj.semesters.append(newsem)
215 216 217 218 219 220 221 222 223 224 225 226 227
        sem = newsem
        
        failed=False
        for program in programs:
            if requirementsFulfilled(program, taken) != program.requirements:
                failed=True
        if not failed:
             break
    return tj
            
    


Chris Reffett's avatar
Chris Reffett committed
228
'''def generatedTrajectory(taken, programs, user):
Daniel W Bond's avatar
Daniel W Bond committed
229
    
Chris Reffett's avatar
Chris Reffett committed
230 231
    tj = Trajectory(user=user, semesters=[])
    programCourses = []
Daniel W Bond's avatar
Daniel W Bond committed
232
    # get the course's programs
Chris Reffett's avatar
Chris Reffett committed
233 234
    for program in programs:
        programCourses.append(programCourses( program ))
Daniel W Bond's avatar
Daniel W Bond committed
235 236

    # find the weights of all of the programs
237
    courseWeighting( programCourses )
Daniel W Bond's avatar
Daniel W Bond committed
238

Chris Reffett's avatar
Chris Reffett committed
239 240 241 242 243 244 245 246 247 248 249 250
    while len(remainingReqCourses) > 0:
        courseWeighting(programCourses)

        # get the courses you have to take next
        remainingReqCourses( taken, programCourses )
        requirementsFulfilled( taken, program )
        nextCourses( remainingReqCourses, taken )
        # TODO: pick five highest-weighted
        #
        nextsem = Semester(number=len(tj.semesters)+1, user=user,
            courses=semcourses, programs=program, 

Daniel W Bond's avatar
Daniel W Bond committed
251 252 253

    # of those, pick five of the heaviest
    ### IMPLEMENT THIS
254 255

    # associate courseWeights with nextCourses
Chris Reffett's avatar
Chris Reffett committed
256
    courseWeighting(nextCourses()
257 258 259
    # add a list of courses with the five highest weights from nextCourses to
    # generated Trajectory
    # add these new courses to taken
Daniel W Bond's avatar
Daniel W Bond committed
260 261 262 263

    # retrieve the next courses you need to take, and so forth
    remainingReqCourses()
    requirementsFulfilled()
264
    nextCourses()
Daniel W Bond's avatar
Daniel W Bond committed
265 266 267 268 269 270 271 272

    # if there are no remainingReqCourses or requirementsFulfilled is True

    # do you have enough credits?
    enoughCredits()

    # hooray!
    return generatedTrajectory
Chris Reffett's avatar
Chris Reffett committed
273
'''
274
### student page
Daniel W Bond's avatar
Daniel W Bond committed
275

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
def allTrajectories(topSemester):
    """ returns all paths to each end node of a trajectories tree
        for the user page, do this over all trees """
    # traverse the tree

    # find the end leafs

    # find the shortest path to each leaf

    # add the list of that semesters to the allTrajectories list
    
    # return said list of lists

    #endLeafs = []
    #for
    allTrajectories  = []
    #for
    #    singleTrajectory = []
    #    singleTrajectory.append(semester)
    #    allTrajectories.append(singleTrajectory)

    return allTrajectories