utils.py 8.27 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
plural  
Ben Waters committed
134
        c = Course.objects.get(title=course)
Ben Waters's avatar
Ben Waters committed
135
        for prereq in c.prerequisites:
136
            reqs.add(prereq)
137 138
        #for coreq in course.coreq:
        #    reqs.add(coreq)
139
        for req in reqs:
140 141
            if req in taken:
                nextcourses.append(course)
Daniel W Bond's avatar
Daniel W Bond committed
142

Chris Reffett's avatar
Chris Reffett committed
143

144
    return nextCourses
Daniel W Bond's avatar
Daniel W Bond committed
145

146 147 148 149 150
# 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 """

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

164
    findDependencies(deletedCourse, semester.nextSemester)
165

166
    return foundDependencies
Daniel W Bond's avatar
Daniel W Bond committed
167

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

178
    return enoughcredits
Daniel W Bond's avatar
Daniel W Bond committed
179

180 181

def genTrajectories(taken, programs, user):
182 183
    if not taken:
        taken = ['']
184
    taken = set(taken)
Chris Reffett's avatar
changes  
Chris Reffett committed
185 186
    print taken
    sem = Semester(number=0, user=user)
Chris Reffett's avatar
Chris Reffett committed
187
    sem.save()
Chris Reffett's avatar
changes  
Chris Reffett committed
188 189 190 191
    for takencourse in taken:
        takencourse.semester=sem
    sem.courses = taken
    sem.programs = programs
192 193 194 195 196 197 198
    try:
        tj = Trajectory.objects.get(user=user)
    except:
        tj = Trajectory(user=user)
        tj.save()
    tj.semesters=[sem]
    programcourses = []
199
    for program in programs:
200 201
        programcourses = programcourses + programCourses(program)
    remainingCourses=remainingReqCourses(taken, programcourses)
202 203 204 205 206 207 208 209 210
    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
211
        tj.semesters.append(newsem)
212 213 214 215 216 217 218 219 220 221 222 223 224
        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
225
'''def generatedTrajectory(taken, programs, user):
Daniel W Bond's avatar
Daniel W Bond committed
226
    
Chris Reffett's avatar
Chris Reffett committed
227 228
    tj = Trajectory(user=user, semesters=[])
    programCourses = []
Daniel W Bond's avatar
Daniel W Bond committed
229
    # get the course's programs
Chris Reffett's avatar
Chris Reffett committed
230 231
    for program in programs:
        programCourses.append(programCourses( program ))
Daniel W Bond's avatar
Daniel W Bond committed
232 233

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

Chris Reffett's avatar
Chris Reffett committed
236 237 238 239 240 241 242 243 244 245 246 247
    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
248 249 250

    # of those, pick five of the heaviest
    ### IMPLEMENT THIS
251 252

    # associate courseWeights with nextCourses
Chris Reffett's avatar
Chris Reffett committed
253
    courseWeighting(nextCourses()
254 255 256
    # 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
257 258 259 260

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

    # 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
270
'''
271
### student page
Daniel W Bond's avatar
Daniel W Bond committed
272

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
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