utils.py 8.35 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 = []
Ben Waters's avatar
Ben Waters committed
8 9
    requirements = program.requirements
    print requirements[0]
Ben Waters's avatar
Ben Waters committed
10
    print requirements
11
    for requirement in requirements:
Ben Waters's avatar
Ben Waters committed
12
        print requirement
13 14
        for coursegroup in requirement.coursegroup:
            for course in coursegroup.courses:
15
                courses.append(course)
16

17
    return courses
18

Chris Reffett's avatar
Chris Reffett committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
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)

44 45 46 47 48 49
### creating a trajectory

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

50
### automatically building a trajectory
Daniel W Bond's avatar
Daniel W Bond committed
51

52 53
def assignedWeights(weightedCourse, programCourses):
    """ assign weights to all courses in a program for automation """
54

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

70
        weights[weightedCourse] = weightedCourseCounter
71

72
    return weights
Daniel W Bond's avatar
Daniel W Bond committed
73

Daniel W Bond's avatar
Daniel W Bond committed
74
def courseWeighting(programCourses):
75
    """ a helper function for properly recursing """
Daniel W Bond's avatar
Daniel W Bond committed
76 77 78 79 80 81 82 83 84

    weights = {}

    weightedCourse = programCourses[0]

    assignedWeights(weightedCourse, programCourses)

    return weights    

85
def customAssignedWeights(weights, selectedCourses):
86 87
    """ remove courses that a student has not selected from the weighted
        courses """
88
    customweights = weights
89 90

    for course in selectedCourses:
91
        del customweights[course]
92

93
    return customweights
94

95
### editing a trajectory
Daniel W Bond's avatar
Daniel W Bond committed
96

97
def requirementsFulfilled(taken, program):
98 99
    """ for *A* program, return a list of all requirements fulfilled """

100 101
    fulfilled = []
    taken = set(taken)
102
    requirements = program.requirements
103

104
    for requirement in requirements:
105 106
        for coursegroup in requirement.coursegroup:
            courseRequirements = set(coursegroup.courses)
107 108
            requirementCoursesTaken = courseRequirements.intersection(alreadyTaken)

109
            if len(requirementCoursesTaken) is requirement.coursegroup.numneeded:
110
                fulfilled.append(requirement)
Daniel W Bond's avatar
Daniel W Bond committed
111 112
    
    # this should return true or false
113
    return fulfilled
Daniel W Bond's avatar
Daniel W Bond committed
114

115

116 117 118 119
#def alreadyTaken():
#    """ return all of the courses that a student has already taken so far
#        in the trajectory """
#    return True
120

121
def remainingReqCourses(taken, programCourses):
122 123
    """ returns the remaining required courses for a program given
    the already taken courses """
Daniel W Bond's avatar
Daniel W Bond committed
124

125
    taken = set(taken)
126
    programCourses = set(programCourses)
Daniel W Bond's avatar
Daniel W Bond committed
127

128
    remainingReqCourses = programCourses.difference(taken)
129 130

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

132
def nextCourses(remainingReqCourses, taken):
Daniel W Bond's avatar
Daniel W Bond committed
133
    """ which courses you can take next based on prereqs and coreqs, given
134
        already taken courses and remaining required courses """
135
    nextcourses = []
136 137
    for course in remainingReqCourses:
        reqs = set()
138 139
        for prereq in course.preq:
            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