示例#1
0
def init(cur):
    """
    Create a temporaty table for scheduling AWS
    """

    global db_
    cur.execute('DROP TABLE IF EXISTS aws_temp_schedule')
    cur.execute('''
            CREATE TABLE IF NOT EXISTS aws_temp_schedule
            ( speaker VARCHAR(40) PRIMARY KEY, date DATE NOT NULL )
            ''')
    db_.commit()
    cur.execute(
        "SELECT * FROM logins WHERE eligible_for_aws='YES' AND status='ACTIVE'"
    )
    for a in cur.fetchall():
        login = a['login'].lower()
        speakers_[login] = a

    cur.execute("""SELECT * FROM holidays ORDER BY date""")
    for a in cur.fetchall():
        if a['schedule_talk_or_aws'] == 'NO':
            holidays_[a['date']] = a

    cur.execute("""SELECT DISTINCT(specialization) FROM faculty""")
    for a in cur.fetchall():
        specialization_list_.append(a['specialization'])

    _logger.info('Total speakers %d' % len(speakers_))
示例#2
0
def init(cur):
    """
    Create a temporaty table for scheduling AWS
    """

    global db_

    cur.execute('DROP TABLE IF EXISTS aws_temp_schedule')
    cur.execute('''
            CREATE TABLE IF NOT EXISTS aws_temp_schedule 
            ( speaker VARCHAR(40) PRIMARY KEY, date DATE NOT NULL ) 
            ''')
    db_.commit()
    cur.execute("""
        SELECT * FROM logins WHERE eligible_for_aws='YES' AND status='ACTIVE'
        ORDER BY login 
        """)
    for a in cur.fetchall():
        speakers_[a['login'].lower()] = a
        spec = a['specialization']
        if spec is None:
            pi = a['pi_or_host']
            if pi is None:
                continue
            spec = getSpecialization(cur, pi)

        spec = spec or 'UNSPECIFIED'
        specialization_[a['login']] = spec

    cur.execute("""SELECT * FROM holidays ORDER BY date""")
    for a in cur.fetchall():
        if a['schedule_talk_or_aws'] == 'NO':
            holidays_[a['date']] = a

    _logger.info('Total speakers %d' % len(speakers_))
示例#3
0
def main(outfile):
    global db_
    _logger.info('Scheduling AWS')
    getAllAWSPlusUpcoming()
    ans = None
    try:
        construct_flow_graph()
        ans = computeSchedule()
    except Exception as e:
        _logger.warn("Failed to schedule. Error was %s" % e)
    try:
        print_schedule(ans, outfile)
    except Exception as e:
        _logger.error("Could not print schedule. %s" % e)

    if ans:
        commit_schedule(ans)
    else:
        print('Failed to compute schedule')
        return -1
    try:
        write_graph()
    except Exception as e:
        _logger.error("Could not write graph to file")
        _logger.error("\tError was %s" % e)
    db_.close()
示例#4
0
def commit_schedule(schedule):
    global db_
    cur = db_.cursor()
    _logger.info('Committing computed schedules ')
    for date in sorted(schedule):
        for speaker in schedule[date]:
            query = """
                INSERT INTO aws_temp_schedule (speaker, date) VALUES ('{0}', '{1}') 
                ON DUPLICATE KEY UPDATE date='{1}'
                """.format(speaker, date)
            cur.execute(query)
    db_.commit()
    _logger.info("Committed to database")
示例#5
0
def swapSpeakers(speakersA, speakersB, schedule, low=-21, high=21):
    """Swap speakersA with speakersB 
    """
    alreadySwapped = []
    for speaker, date in speakersA.iteritems():
        swapWith = potentialSpeakerToSwap(speaker, date, speakersB,
                                          alreadySwapped, low, high)
        if swapWith:
            _logger.info('Swapping %s with %s' % (speaker, swapWith))
            alreadySwapped.append(swapWith)
            swapInSchedule(speaker, swapWith, schedule)

    _logger.info("After swapping %f" % fresherIndex(schedule))
    return schedule
示例#6
0
    def execute(self, **_meta):
        """
            Run the job using the specified meta values to control the
            execution.
        """
        try:
            try:
                _logger.info("%s %s", self.id, unicode(self))
            except NameError:
                _logger.info("%s %s", self.id, str(self))
            args = loads(self.args)
            kwargs = non_unicode_kwarg_keys(loads(self.kwargs))
            function = object_at_end_of_path(self.name)
            _logger.debug(u"%s resolved to %s" % (self.name, function))

            def execute():
                """Execute the database updates in one transaction.
                """
                self.started = timezone.now()
                result = function(*args, **kwargs)
                self.executed = timezone.now()
                self.cancelled = None
                self.result = dumps(result)
                self.save()
                return result

            return atomic(execute)()
        except Exception as exception:
            self.started = None
            errors = 1 + self.errors.count()
            self.scheduled = (timezone.now() +
                              timedelta(seconds=60 * pow(errors, 1.6)))
            self.priority = self.priority - 1
            _logger.error(
                "Job failed. Rescheduled for %s after %s error(s). "
                "New priority is %s", self.scheduled, errors, self.priority)

            def record():
                """Local function allows us to wrap these updates into a
                transaction.
                """
                Error.objects.create(job=self,
                                     exception=repr(exception),
                                     traceback=format_exc())
                self.save()

            atomic(record)()
            raise
示例#7
0
def no_common_labs(schedule, nweeks=2, ncalls=0):
    # Make sure that first 2 week entries have different PIs.
    if ncalls > 100:
        _logger.warn("Terminated after 100 calls")
        return schedule
    failedDates = []
    sortedDates = sorted(schedule)
    for ix, date in enumerate(sortedDates[:nweeks]):
        labs = []
        for i, speaker in enumerate(schedule[date]):
            spec = g_.node['%s,%d' % (date, i)]['specialization']
            piH = speakers_[speaker]['pi_or_host']
            if piH in labs:
                spec = specialization_.get(speaker, 'UNSPECIFIED')
                replaceWith = findReplacement(speaker, date, spec, piH,
                                              schedule)
                if replaceWith is not None:
                    speakerB, dateB = replaceWith
                    speakerA, dateA = speaker, date
                    schedule[dateA].append(speakerB)
                    schedule[dateA].remove(speakerA)
                    schedule[dateB].append(speakerA)
                    schedule[dateB].remove(speakerB)
                    _logger.info('Swapping %s and %s' % (speakerA, speakerB))
                else:
                    # swap this row by next and try again.
                    failedDates.append(date)
                    _logger.info("Failed to find alternative for %s" % date)
                    # swap this date with someone else.
                    for iy, datey in enumerate(sortedDates[nweeks:]):
                        if len(schedule[datey]) == len(schedule[date]):
                            # we can swap with entry.
                            temp = schedule[datey]
                            schedule[datey] = schedule[date]
                            schedule[date] = temp
                            return no_common_labs(schedule, nweeks, ncalls + 1)
            else:
                labs.append(piH)

    for fd in failedDates:
        _logger.warn('Entry for date %s has multiple speakers from same lab' %
                     fd)
        _logger.warn('Moving whole row down to more than %d positions' %
                     nweeks)

    return schedule
示例#8
0
 def execute(self, **_meta):
     """
         Run the job using the specified meta values to control the
         execution.
     """
     try:
         _logger.info("%s %s", self.id, unicode(self))
         args = loads(self.args)
         kwargs = non_unicode_kwarg_keys(loads(self.kwargs))
         #Add priority and fairness to kwargs.
         kwargs['priority'] = self.priority
         kwargs['fairness'] = self.fairness
         function = object_at_end_of_path(self.name)
         _logger.debug(u"%s resolved to %s" % (self.name, function))
         def execute():
             """Execute the database updates in one transaction.
             """
             self.started = timezone.now()
             result = function(*args, **kwargs)
             self.executed = timezone.now()
             self.result = dumps(result)
             self.save()
             return result
         return transaction.commit_on_success(execute)()
     except Exception, exception:
         self.started = None
         errors = 1 + self.errors.count()
         self.scheduled = (timezone.now() +
             timedelta(seconds=60 * pow(errors, 1.6)))
         self.priority = self.priority - 1
         _logger.error(
             "Job %s failed. Rescheduled for %s after %s error(s). "
                 "New priority is %s."
                 "Exception is %s."
                 "Trace is %s",
             self.id, self.scheduled, errors, self.priority, repr(exception), format_exc())
         def record():
             """Local function allows us to wrap these updates into a
             transaction.
             """
             Error.objects.create(job=self, exception=repr(exception),
                 traceback=format_exc())
             self.save()
         transaction.commit_on_success(record)()
         raise
示例#9
0
def main(outfile):
    global db_
    _logger.info('Scheduling AWS')
    getAllAWSPlusUpcoming()
    ans = None
    try:
        construct_flow_graph()
        ans = computeSchedule()
    except Exception as e:
        _logger.warn("Failed to schedule. Error was %s" % e)

    # update specialization on g_ nodes.
    for date in ans:
        specs = [specialization_.get(x, 'UNSPECIFIED') for x in ans[date]]
        mostCommonSpec, freq = Counter(specs).most_common(1)[0]
        for slot in range(3):
            slot = '%s,%d' % (date, slot)
            if slot in g_:
                g_.node[slot]['specialization'] = mostCommonSpec

    ans = group_schedule(ans)
    ans = aws_helper.no_common_labs(ans)

    if ans:
        commit_schedule(ans)
    else:
        print('Failed to compute/commit schedule')
        return -1

    try:
        print_schedule(ans, outfile)
    except Exception as e:
        _logger.error("Could not print schedule. %s" % e)

    try:
        write_graph()
    except Exception as e:
        _logger.error("Could not write graph to file")
        _logger.error("\tError was %s" % e)
    db_.close()
示例#10
0
def computeSchedule():
    _logger.info('Scheduling AWS now')
    test_graph(g_)
    _logger.info('Computing max-flow, min-cost')
    res = nx.max_flow_min_cost(g_, 'source', 'sink')
    _logger.info('\t Computed. Getting schedules now ...')
    sch = getMatches(res)
    return sch
示例#11
0
def test_graph(graph):
    """Test that this graph is valid """
    # Each edge must have a capcity and weight
    for u, v in graph.edges():
        if 'capacity' not in graph[u][v]:
            _logger.info('Error: %s -> %s no capacity assigned' % (u, v))
        if 'weight' not in graph[u][v]:
            _logger.info('Error: %s -> %s no weight assigned' % (u, v))
    _logger.info('\tDone testing graph')
示例#12
0
def get_prev_aws_date(speaker):

    lastDate = None

    if speakersSpecialization_.get(speaker, 'UNSPECIFIED') == 'UNSPECIFIED':
        _logger.warning("Could not find specialization for %s" % speaker)

    # Last entry is most recent
    if speaker not in aws_.keys():
        # We are here because this speaker has not given any AWS yet.
        freshers_.add(speaker)

        # If this user has PHD/POSTDOC, or INTPHD title. We create  a dummy
        # last date to bring her into potential speakers.
        # First make sure, I have their date of joining. Otherwise I
        # can't continue. For MSc By Research/INTPHD assign their first AWS
        # after 18 months. For PHD and POSTDOC, it should be after 12 months.
        if speakers_[speaker]['title'] == 'INTPHD':
            # InPhd should get their first AWS after 15 months of
            # joining.
            _logger.info('%s = INTPHD with 0 AWS so far' % speaker)
            joinDate = speakers_[speaker]['joined_on']
            if not joinDate:
                _logger.warn("Could not find joining date")
            else:
                lastDate = monthdelta(joinDate, +6)

        if speakers_[speaker]['title'] == 'MSC':
            # MSc should get their first AWS after 18 months of
            # joining. Same as INTPHD
            _logger.info('%s = MSC BY RESEARCH with 0 AWS so far' % speaker)
            joinDate = speakers_[speaker]['joined_on']
            if not joinDate:
                _logger.warn("Could not find joining date")
            else:
                lastDate = monthdelta(joinDate, +6)

        elif speakers_[speaker]['title'] in ['PHD', 'POSTDOC']:
            joinDate = speakers_[speaker]['joined_on']
            _logger.info('%s PHD/POSTDOC with 0 AWS so far' % speaker)
            if not joinDate:
                _logger.warn("Could not find joining date")
            else:
                try:
                    # if datetime.
                    lastDate = joinDate.date()
                except Exception as e:
                    # Else its date
                    lastDate = joinDate
    else:
        # We are here because this speaker has given AWS before
        # If this speaker is already on upcoming AWS list, ignore it.
        if speaker in upcoming_aws_:
            _logger.info('Speaker %s is already scheduled on %s' %
                         (speaker, upcoming_aws_[speaker]))
            return None
        # If this speakers is MSC by research and has given AWS before, she/he
        # need not give another.
        elif speakers_[speaker]['title'] == 'MSC':
            _logger.info('%s is MSC and has given AWS in the past' % speaker)
            return None
        else:
            lastDate = aws_[speaker][-1]['date']
    return lastDate
示例#13
0
def construct_graph(validSlots):

    lastDate = None
    for i, speaker in enumerate(speakers_):
        lastDate = get_prev_aws_date(speaker)
        # If a speaker has a lastDate either because he has given AWS in the
        # past or becuase she is fresher. Create an edge.
        if lastDate is not None:
            g_.add_node(speaker, last_date=lastDate, pos=(1, 3 * i))
            g_.add_edge('source', speaker, capacity=1, weight=0)

    for sid, monday, specForWeek in validSlots:
        # For each Monday, we have 3 AWS - (assigned on upcoming_aws_slots_)
        # For each week select a specialization.
        _logger.info("++ Specialization for this week is %s" % specForWeek)
        g_.add_node(sid, date=monday, specialization=specForWeek)
        g_.add_edge(sid, 'sink', capacity=1, weight=0)

    # Now for each student, add potential edges.
    idealGap = 357

    freshersDate = defaultdict(list)
    for speaker in speakers_:
        speakerSpecialization = speakersSpecialization_.get(speaker, '')
        preferences = aws_scheduling_requests_.get(speaker, {})

        if preferences:
            _logger.info("%s has preferences %s " % (speaker, preferences))

        if speaker not in g_.nodes():
            _logger.info('Nothing for user %s' % speaker)
            continue

        prevAWSDate = g_.node[speaker]['last_date']
        for slot, monday, speci in validSlots:
            # If this slot does not belong to some specialization then ignore
            # it.
            if g_.node[slot]['specialization'] != speakerSpecialization:
                continue

            date = g_.node[slot]['date']
            weight = computeCost(speaker, date, prevAWSDate)
            if weight is None:
                continue

            # If the speaker is fresher, do not draw edges to all three
            # slots. Draw just one but make sure that they get this slot. We
            # reduce the cost to almost zero.
            if speaker in freshers_:
                # Let two freshers take maximum of two slots on same day.
                # The weight should be low but not lower than user
                # preference.
                if freshersDate.get(speaker, []).count(date) < 2:
                    addEdge(speaker, slot, 1, 5)
                    # This date is taken by this fresher.
                    freshersDate[speaker].append(date)
            else:
                addEdge(speaker, slot, 1, weight)

            # Honour user preferences..
            if preferences:
                first = preferences.get('first_preference', None)
                second = preferences.get('second_preference', None)
                if first:
                    ndays = diffInDays(date, first, True)
                    if ndays <= 14:
                        _logger.debug('Using first preference for %s' %
                                      speaker)
                        addEdge(speaker, slot, 1, 0 + ndays / 7)
                if second:
                    ndays = diffInDays(date, second, True)
                    if ndays <= 14:
                        _logger.info('Using second preference for %s' %
                                     speaker)
                        addEdge(speaker, slot, 1, 2 + ndays / 7)

    # Each slot node must have at least 3 nodes.
    missedSlots = []
    for slot, monday, speci in validSlots:
        inDegree = g_.in_degree(slot)
        inedges = g_.predecessors(slot)
        if inDegree < 1:
            _logger.warn("slot %s [%s] have no options" % (slot, speci))
            missedSlots.append(slot)

    _logger.info('Constructed flow graph')
    return missedSlots
示例#14
0
def avoidClusteringOfFreshers(schedule):
    """
    Make sure not all student are freshers. Also try to put at least 1
    fresher.

    THIS FUNCTION IS DEPRECATED.:
    We almost achieved same assignment by drawing at most 2 edges from fresheres
    to same date.

    """
    global aws_, speakers_

    _logger.info("Before swapping %f" % fresherIndex(schedule))

    # 1: SWAP one in rows with all experienced with a fresher.
    # Store speaker to move in this dict. Freshers should not move too much
    # therefore we do not change the default low and high parameters.
    speakersToSwap = OrderedDict()
    candidates = OrderedDict()
    for date in sorted(schedule):
        nAws = {}
        speakers = schedule[date]
        nFreshers = 0
        for i, speaker in enumerate(speakers):
            naws = len(aws_.get(speaker, []))
            if naws == 0:
                nFreshers += 1
            if nFreshers > 1:
                # Take this speaker from here and put it into to swap with list.
                candidates[speaker] = date

        # If all of them are experienced, then I can take one of them ( to be
        # replace by fresher) and put him/her into to be moved list.
        if nFreshers == 0:
            speakersToSwap[speakers[0]] = date
    # Since we really do not want mutliple freshers on same day, we search wide
    # for swapping. We can delay AWS of senior students.
    schedule = swapSpeakers(speakersToSwap,
                            candidates,
                            schedule,
                            low=-91,
                            high=28)

    # 2 : SWAP two in rows which have all freshers with experienced
    # Store speaker to move in this dict.
    speakersToSwap = {}
    candidates = {}
    for date in sorted(schedule):
        nAws = {}
        speakers = schedule[date]
        nFreshers = 0
        for i, speaker in enumerate(speakers):
            naws = len(aws_.get(speaker, []))
            if naws == 0:
                nFreshers += 1
            if nFreshers > 1:
                speakersToSwap[speaker] = date

        # If no of freshers are zero, I can put 1 speaker into swap list.
        if nFreshers == 0:
            candidates[speakers[0]] = date

    schedule = swapSpeakers(speakersToSwap, candidates, schedule)

    return schedule
示例#15
0
def construct_flow_graph(seed=0):
    """This is the most critical section of this task. It is usually good if
    flow graph is constructed to honor policy as much as possible rather than
    fixing the solution later.

    One important scheduling aim is to minimize number of freshers on the same
    day. Ideally no more than 1 freshers should be allowed on same day. This can
    be achieved by modifying the solution later : swapping freshers with
    experienced speaker from other days. We avoid that by drawing two edges
    from freshers to a 'date' i.e. maximum of 2 slots can be filled by freshers.
    For others we let them fill all three slots.

    4 slots every monday and all belong to one specialization.
    """

    g_.clear()

    g_.add_node('source', pos=(0, 0))
    g_.add_node('sink', pos=(10, 10))

    # Compute totalWeeks of schedule starting today.
    totalWeeks = 32
    d = datetime.date.today()
    while d.weekday() != 0:  # 0 is monday
        d += datetime.timedelta(days=1)
    nextMonday = d
    slots = []

    weeks = [afterNDays(nextMonday, 7 * i) for i in range(totalWeeks)]

    specializations = chooseSpecialization(totalWeeks, seed)

    # Ignore the already filled upcoming AWS slots.
    freq = Counter(speakersSpecialization_.values())
    for monday in sorted(upcoming_aws_slots_):
        speakers = upcoming_aws_slots_[monday]
        for speaker in speakers:
            specialization = speakersSpecialization_.get(
                speaker, 'UNSPECIFIED')
            freq[specialization] = max(0, freq[specialization] - 1)

    # Update the frequencies.
    for k in freq:
        specializationFreqs_[k] = 1.0 * freq[k] / sum(freq.values())

    # Collect all the valid slots with specialization in a list.
    validSlots = []
    for specForWeek, monday in zip(specializations, weeks):
        # AWS don't care about holidays.
        if monday in holidays_:
            _logger.warn("This date %s is holiday" % monday)
            continue

        nSlots = 3
        if monday in upcoming_aws_slots_:
            # Check how many of these dates have been taken.
            _logger.info('Date %s is taken ' % monday)
            nSlots -= len(upcoming_aws_slots_[monday])
            for i in range(nSlots):
                validSlots.append(('%s,%s' % (monday, i), monday, specForWeek))
        else:
            validSlots += [('%s,%s' % (monday, i), monday, specForWeek)
                           for i in range(nSlots)]

    # Keep edges from freshers to dates here. We allow maximum of 2 out of 3
    # slots to be taken by freshers (maximum ).
    missed = construct_graph(validSlots)
    return missed
示例#16
0
def construct_flow_graph():
    """This is the most critical section of this task. It is usually good if
    flow graph is constructed to honor policy as much as possible rather than
    fixing the solution later.

    One important scheduling aim is to minimize number of freshers on the same
    day. Ideally no more than 1 freshers should be allowed on same day. This can
    be achieved by modifying the solution later : swapping freshers with
    experienced speaker from other days. We avoid that by drawing two edges 
    from freshers to a 'date' i.e. maximum of 2 slots can be filled by freshers.
    For others we let them fill all three slots.
    """

    g_.add_node('source', pos=(0, 0))
    g_.add_node('sink', pos=(10, 10))

    lastDate = None
    freshers = set()
    for i, speaker in enumerate(speakers_):
        # Last entry is most recent
        if speaker not in aws_.keys():
            # We are here because this speaker has not given any AWS yet.
            freshers.add(speaker)

            # If this user has PHD/POSTDOC, or INTPHD title. We create  a dummy
            # last date to bring her into potential speakers.
            # First make sure, I have their date of joining. Otherwise I
            # can't continue. For MSc By Research/INTPHD assign their first AWS
            # after 18 months. For PHD and POSTDOC, it should be after 12 months.
            if speakers_[speaker]['title'] == 'INTPHD':
                # InPhd should get their first AWS after 15 months of
                # joining.
                _logger.info('%s = INTPHD with 0 AWS so far' % speaker)
                joinDate = speakers_[speaker]['joined_on']
                if not joinDate:
                    _logger.warn("Could not find joining date")
                else:
                    lastDate = monthdelta(joinDate, +6)

            if speakers_[speaker]['title'] == 'MSC':
                # MSc should get their first AWS after 18 months of
                # joining. Same as INTPHD
                _logger.info('%s = MSC BY RESEARCH with 0 AWS so far' %
                             speaker)
                joinDate = speakers_[speaker]['joined_on']
                if not joinDate:
                    _logger.warn("Could not find joining date")
                else:
                    lastDate = monthdelta(joinDate, +6)

            elif speakers_[speaker]['title'] in ['PHD', 'POSTDOC']:
                joinDate = speakers_[speaker]['joined_on']
                _logger.info('%s PHD/POSTDOC with 0 AWS so far' % speaker)
                if not joinDate:
                    _logger.warn("Could not find joining date")
                else:
                    try:
                        # if datetime.
                        lastDate = joinDate.date()
                    except Exception as e:
                        # Else its date
                        lastDate = joinDate
        else:
            # We are here because this speaker has given AWS before
            # If this speaker is already on upcoming AWS list, ignore it.
            if speaker in upcoming_aws_:
                _logger.info('Speaker %s is already scheduled on %s' %
                             (speaker, upcoming_aws_[speaker]))
                continue
            # If this speakers is MSC by research and has given AWS before, she/he
            # need not give another.
            elif speakers_[speaker]['title'] == 'MSC':
                _logger.info('%s is MSC and has given AWS in the past' %
                             speaker)
                continue
            else:
                lastDate = aws_[speaker][-1]['date']

        # If a speaker has a lastDate either because he has given AWS in the
        # past or becuase she is fresher. Create an edge.
        if lastDate:
            g_.add_node(speaker, last_date=lastDate, pos=(1, 3 * i))
            g_.add_edge('source', speaker, capacity=1, weight=0)

    # Compute totalWeeks of schedule starting today.
    totalWeeks = int(365 / 7.0)
    today = datetime.date.today()
    nextMonday = today + datetime.timedelta(days=-today.weekday(), weeks=1)
    slots = []
    _logger.info("Computing for total %d weeks" % totalWeeks)
    for i in range(totalWeeks):
        nDays = i * 7
        monday = nextMonday + datetime.timedelta(nDays)

        # AWS don't care about holidays.
        if monday in holidays_:
            _logger.warn("This date %s is holiday" % monday)
            continue

        nSlots = 3
        if monday in upcoming_aws_slots_:
            # Check how many of these dates have been taken.
            _logger.info('Date %s is taken ' % monday)
            nSlots -= len(upcoming_aws_slots_[monday])

        # For each Monday, we have 3 AWS - (assigned on upcoming_aws_slots_)
        for j in range(nSlots):
            dateSlot = '%s,%d' % (monday, j)
            g_.add_node(dateSlot, date=monday, pos=(5, 10 * (3 * i + j)))
            g_.add_edge(dateSlot, 'sink', capacity=1, weight=0)
            slots.append(dateSlot)

    # Now for each student, add potential edges.
    idealGap = 7 * 60

    # Keep edges from freshers to dates here. We allow maximum of 2 out of 3
    # slots to be taken by freshers (maximum ).
    freshersDate = defaultdict(list)
    for speaker in speakers_:
        preferences = aws_scheduling_requests_.get(speaker, {})
        if preferences:
            _logger.info("%s has preferences %s " % (speaker, preferences))

        if speaker not in g_.nodes():
            _logger.info('Nothing for user %s' % speaker)
            continue

        prevAWSDate = g_.node[speaker]['last_date']
        for slot in slots:
            date = g_.node[slot]['date']
            weight = computeCost(speaker, date, prevAWSDate)
            if weight:
                # If the speaker is fresher, do not draw edges to all three
                # slots. Draw just one but make sure that they get this slot. We
                # reduce the cost to almost zero.
                if speaker in freshers:
                    # Let two freshers take maximum of two slots on same day.
                    # The weight should be low but not lower than user
                    # preference.
                    if freshersDate.get(speaker, []).count(date) < 2:
                        addEdge(speaker, slot, 1, 5)
                        # This date is taken by this fresher.
                        freshersDate[speaker].append(date)
                else:
                    addEdge(speaker, slot, 1, weight)

                # Honour user preferences..
                if preferences:
                    first = preferences.get('first_preference', None)
                    second = preferences.get('second_preference', None)
                    if first:
                        ndays = diffInDays(date, first, True)
                        if ndays <= 14:
                            _logger.info('Using first preference for %s' %
                                         speaker)
                            addEdge(speaker, slot, 1, 0 + ndays / 7)
                    if second:
                        ndays = diffInDays(date, second, True)
                        if ndays <= 14:
                            _logger.info('Using second preference for %s' %
                                         speaker)
                            addEdge(speaker, slot, 1, 2 + ndays / 7)

    _logger.info('Constructed flow graph')
示例#17
0
import datetime
import copy
import tempfile
from logger import _logger
from db_connect import db_
import compute_cost
import cluster_aws
import aws_helper
from collections import defaultdict, OrderedDict, Counter
from global_data import *

cwd = os.path.dirname(os.path.realpath(__file__))
networkxPath = os.path.join('%s/networkx' % cwd)
sys.path.insert(0, networkxPath)

_logger.info('Using networkx from %s' % nx.__file__)
_logger.info('Using networkx from %s' % nx.__file__)
_logger.info('Started on %s' % datetime.date.today())

random.seed(1)
np.random.seed(1)


def spec_short(spec):
    return ''.join([x.strip()[0] for x in spec.split()])


def getSpecialization(cur, piOrHost):
    cur.execute("SELECT specialization FROM faculty WHERE email='%s'" %
                piOrHost)
    a = cur.fetchone()
示例#18
0
def getAllAWSPlusUpcoming():
    global db_
    # cur = db_.cursor( cursor_class = MySQLCursorDict )
    try:
        cur = db_.cursor(dictionary=True)
    except Exception as e:
        print(e)
        print('''If complain is about dictionary keyword. Install
        https://pypi.python.org/pypi/mysql-connector-python-rf/2.2.2
        using easy_install''')
        quit()

    init(cur)

    # Entries in this table are usually in future.
    cur.execute('SELECT * FROM upcoming_aws')
    for a in cur.fetchall():
        aws_[a['speaker']].append(a)
        upcoming_aws_[a['speaker'].lower()] = a['date']
        # Keep the number of slots occupied at this day.
        upcoming_aws_slots_[a['date']].append(a['speaker'])

    # Now get all the previous AWSs happened so far. Also fetch the
    # specialization of student depending on what student has specified or by
    # reading PI.
    cur.execute('SELECT * FROM annual_work_seminars')
    for a in cur.fetchall():
        # If this speaker is not eligible anymore ignore.
        if a['speaker'] not in speakers_:
            continue

        aws_[a['speaker'].lower()].append(a)
        # Also get the specialization by reading the supervisor_1 .
        pi = a['supervisor_1']
        if not pi:
            continue
        cur.execute("SELECT specialization FROM faculty WHERE email='%s'" % pi)
        spec = cur.fetchone()
        if spec:
            specialization = spec.get('specialization', 'UNSPECIFIED')
            if specialization and specialization != 'UNSPECIFIED':
                speakersSpecialization_[a['speaker']] = spec['specialization']

    for a in aws_:
        # Sort a list in place.
        aws_[a].sort(key=lambda x: x['date'])
        # print( a, [ x['date'] for x in aws_[a] ] )

    # Select all aws scheduling requests which have been approved.
    cur.execute("SELECT * FROM aws_scheduling_request WHERE status='APPROVED'")
    for a in cur.fetchall():
        aws_scheduling_requests_[a['speaker'].lower()] = a

    # Get specialization of each student. If no specified, fetch the
    # specialization of current PI.
    # IMP: This will overwrite the specialization fetched from previous AWS. It
    # is required.
    for st in speakers_:
        # If  this speaker has given AWS in less than 6 months, do not count her
        # when computing frequencies.
        prevAWSDate = getPrevisousAWS(cur, st)
        #if prevAWSDate is not None:
        #    if diffInDays( prevAWSDate, datetime.date.today( ) ) < 200:
        #        _logger.warn( 'Not counting %s. Recently given AWS' % st )
        #        continue

        cur.execute("SELECT specialization FROM logins WHERE login='******'" % st)
        a = cur.fetchone()
        if not a['specialization']:
            # Ok. Not specified; use faculty specialization.
            piOrHost = speakers_[st]['pi_or_host']

            if piOrHost:
                cur.execute(
                    "SELECT specialization FROM faculty WHERE email='%s'" %
                    piOrHost)
                a = cur.fetchone()

        if a is not None and a['specialization']:
            speakersSpecialization_[st] = a['specialization']

    ## Compute the frequencies of specialization.
    ## Print specialization
    _logger.debug('Total speakers %d' % len(speakersSpecialization_))
    freq = Counter(speakersSpecialization_.values())
    for k in freq:
        specializationFreqs_[k] = 1.0 * freq[k] / sum(freq.values())

    _logger.info(specializationFreqs_)
    print(specializationFreqs_)