Запуск симуляции распределения неоднократно прерывается после первого запуска

Предыстория
У меня есть группа студентов, их желаемые проекты и руководители соответствующих проектов. Я запускаю серию симуляций, чтобы посмотреть, какие проекты получат студенты, что позволит мне получить полезную статистику, необходимую для обратной связи. Итак, это, по сути, Monte-Carlo симуляция, в которой я рандомизирую список студентов, а затем перебираю его, распределяя проекты, пока не дойду до конца списка. Затем процесс повторяется снова.

Обратите внимание, что в течение одного сеанса после каждого успешного распределения проекта происходит следующее:
+ проект устанавливается на allocated и не может быть передан другому студенту
+ у руководителя есть фиксированное quota студентов, которых он может контролировать. Это значение уменьшается на 1
+ Как только quota достигает 0, все проекты от этого руководителя становятся blocked, и это имеет тот же эффект, что и проект, который становится allocated.

Код

def resetData():
    for student in students.itervalues():
        student.allocated_project = None

    for supervisor in supervisors.itervalues():
        supervisor.quota = 0

    for project in projects.itervalues():
        project.allocated = False
        project.blocked = False

Роль resetData() заключается в «сбросе» определенных битов данных. Например, когда проект успешно выделен, project.allocated для этого проекта меняется на True. Хотя это полезно для одного запуска, для следующего запуска мне нужно освободить место.

Выше я просматриваю три словаря — по одному для студентов, проектов и руководителей — где хранится информация.

Следующий бит — это симуляция «Монте-Карло» для алгоритма распределения.

sesh_id = 1

for trial in range(50):

    for id in randomiseStudents(1):
        stud_id = id
        student = students[id]
        if not student.preferences:
        # Ignoring the students who've not entered any preferences

            for rank in ranks:
                temp_proj = random.choice(list(student.preferences[rank]))

                if not (temp_proj.allocated or temp_proj.blocked):
                    alloc_proj = student.allocated_proj_ref = temp_proj.proj_id
                    alloc_proj_rank = student.allocated_rank = rank
                    successActions(temp_proj)
                    temp_alloc = Allocated(sesh_id, stud_id, alloc_proj, alloc_proj_rank)
                    print temp_alloc # Explained
                    break                  
    sesh_id += 1
    resetData()  # Refer to def resetData() above

Все, что делает randomiseStudents(1), — рандомизирует порядок учеников.

Allocated — это класс, определенный как таковой:

class Allocated(object):
    def __init__(self, sesh_id, stud_id, alloc_proj, alloc_proj_rank):
        self.sesh_id = sesh_id
        self.stud_id = stud_id
        self.alloc_proj = alloc_proj
        self.alloc_proj_rank = alloc_proj_rank

   def __repr__(self):
        return str(self)

   def __str__(self):
        return "%s - Student: %s (Project: %s - Rank: %s)" %(self.sesh_id, self.stud_id, self.alloc_proj, self.alloc_proj_rank)

Output and problem

Теперь, если я запускаю это, я получаю такой вывод (усеченный):

1 - Student: 7720 (Project: 1100241 - Rank: 1)
1 - Student: 7832 (Project: 1100339 - Rank: 1)
1 - Student: 7743 (Project: 1100359 - Rank: 1)
1 - Student: 7820 (Project: 1100261 - Rank: 2)
1 - Student: 7829 (Project: 1100270 - Rank: 1)
.
.
.
1 - Student: 7822 (Project: 1100280 - Rank: 1)
1 - Student: 7792 (Project: 1100141 - Rank: 7)
2 - Student: 7739 (Project: 1100267 - Rank: 1)
3 - Student: 7806 (Project: 1100272 - Rank: 1)
.
.
.
45 - Student: 7806 (Project: 1100272 - Rank: 1)
46 - Student: 7714 (Project: 1100317 - Rank: 1)
47 - Student: 7930 (Project: 1100343 - Rank: 1)
48 - Student: 7757 (Project: 1100358 - Rank: 1)
49 - Student: 7759 (Project: 1100269 - Rank: 1)
50 - Student: 7778 (Project: 1100301 - Rank: 1)

По сути, он отлично работает для первого запуска, но при последующих запусках, ведущих к n-му запуску, в данном случае 50, возвращается только одна пара распределения учащийся-проект.

Таким образом, основная проблема, с которой у меня возникли проблемы, заключается в том, чтобы выяснить, что вызывает это аномальное поведение, тем более что первый запуск работает гладко.

Заранее спасибо,

Az


person PizzAzzra    schedule 26.05.2010    source источник
comment
Попробуйте записывать идентификатор студента каждый раз, когда он выбирается (в самом начале цикла). Если вы не распечатываете это 50 раз при более поздних запусках, проблема связана с randomiseStudents(), что, я подозреваю, как и paxdiablo.   -  person Justin Peel    schedule 26.05.2010
comment
Оказалось, проблема с resetData(), на которую указал paxdiablo. Спасибо за вклад в любом случае. :)   -  person PizzAzzra    schedule 26.05.2010


Ответы (1)


Вы действительно намерены установить квоту супервизора на 0 в resetData()? Не означает ли это, что все их проекты теперь заблокированы?

Сказал ворон:

У супервайзера есть фиксированная квота студентов, которых он может курировать. Это значение уменьшается на 1. Как только квота достигает 0, все проекты от этого руководителя блокируются, и это имеет тот же эффект, что и выделение проекта.

Если это не так, вам следует проверить вывод randomiseStudents(), чтобы убедиться, что он возвращает полный список. В конце концов, это контролирующий элемент для этого внутреннего цикла.


Обновление на основе комментариев:

Похоже, проблема была в том, что вы установили квоту руководителя на 0, что привело к блокировке всех его проектов.

Это чистое предположение с моей стороны, но вы, вероятно, выводили одного ученика на каждой итерации, потому что проверка всех супервайзеров происходила после распределения. В этом случае только что выделенная квота будет иметь квоту -1, а все остальные квоты будут равны 0, эффективно останавливая все выделения после этой.

В идеале вы хотели бы вернуть квоту супервизора к исходному значению в resetData(). Если бы это была фиксированная квота (одинаковая для каждого руководителя), вы могли бы просто использовать:

for supervisor in supervisors.itervalues():
    supervisor.quota = 7 # for example

Если бы у каждого супервизора была своя квота, вам нужно было бы сохранить ее вместе с другой информацией (во время инициализации, но не при сбросе), как, например, supervisor.start_quota. Затем вы можете использовать:

for supervisor in supervisors.itervalues():
    supervisor.quota = supervisor.start_quota
person paxdiablo    schedule 26.05.2010
comment
Хахахахахахаха! Хороший! Я не могу поверить, что напечатал все это из-за такой простой ошибки. Спасибо приятель! - person PizzAzzra; 26.05.2010
comment
Взгляд в прошлое — это видение 20/20 :-) Знаете, мне всегда было интересно, откуда взялся этот термин, и однажды я его просмотрел. На самом деле это означает, что вы можете видеть на расстоянии 20 футов то, что обычный человек видит на расстоянии 20 футов. Следовательно, у орлов зрение 80/20, они могут видеть на 80 футов с таким же уровнем детализации, как мы можем видеть на 20, и поэтому они так хорошо обнаруживают полевых мышей и тому подобное. Просто немного образования для тех, кто заинтересован. - person paxdiablo; 26.05.2010
comment
О боже, это более серьезная проблема, чем я думал. У каждого руководителя есть отдельная квота, поэтому я не могу просто сбросить ее до фиксированного значения... - person PizzAzzra; 26.05.2010
comment
@Az, вы также должны хранить стартовую квоту каждого супервайзера в их структуре. Затем в resetData() просто выполните: supervisor.quota = supervisor.start_quota - person paxdiablo; 26.05.2010
comment
Ах, конечно. Я делал это с компонентом для проектов - не могу поверить, что не мог вспомнить. Ты дважды спас меня, приятель. Я очень благодарен. PS - Зрение 20/20 было интересным. Мне всегда казалось это забавным с точки зрения индекса объектива. 20± означает, что вы практически слепы :) - person PizzAzzra; 26.05.2010