Проблема задоволення обмеження відсутня одна обмеження


13

Я викладач лабораторних практик в університеті, грунтуючись на коментарях минулого року студентів, ми хотіли, мій шеф та я, звернутися до них. Мій бос вирішив піти з написання сценарію С, і я вибираю python (python-constraint), щоб спробувати вирішити нашу проблему.

Інформація

  • Є 6 сеансів
  • Є 4 ролі
  • Є 6 практик
  • Є 32 студенти
  • У команді - 4 учні

Проблема:

Призначте кожному студенту 4 ролі, в 4 практиках у 4 різних сесіях.

Обмеження:

  1. Студенти повинні виконувати роль один раз
  2. Студенти повинні робити 4 різні практики з 6
  3. Студенти повинні робити лише одну практику за сеанс
  4. Студент повинен зустрітися з тим самим товаришем лише один раз

Шаблони:

Ось шаблон, який я відчуваю зі студентами, де кожна команда складається з 4 учнів, посади [0, 1, 2 або 3] - призначені їм ролі. Кожна наявна позиція налічує від 1 до 128

[# Semester
   [ # Session
     [ # Practice/Team
1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12],
  [13, 14, 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, 40],
  [41, 42, 43, 44],
  [45, 46, 47, 48]],
 [[49, 50, 51, 52],
  [53, 54, 55, 56],
  [57, 58, 59, 60],
  [61, 62, 63, 64],
  [65, 66, 67, 68],
  [69, 70, 71, 72]],
 [[73, 74, 75, 76],
  [77, 78, 79, 80],
  [81, 82, 83, 84],
  [85, 86, 87, 88],
  [89, 90, 91, 92],
  [93, 94, 95, 96]],
 [[97, 98, 99, 100],
  [101, 102, 103, 104],
  [105, 106, 107, 108],
  [109, 110, 111, 112]],
 [[113, 114, 115, 116],
  [117, 118, 119, 120],
  [121, 122, 123, 124],
  [125, 126, 127, 128]]]

Іншими словами :

Це сеанс:

 [[1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12],
  [13, 14, 15, 16],
  [17, 18, 19, 20],
  [21, 22, 23, 24]],

Ці команди виконують ту саму практику:

[
    [1, 2, 3, 4],
    [25, 26, 27, 28],
    [49, 50, 51, 52],
    [73, 74, 75, 76],
    [97, 98, 99, 100],
    [113, 114, 115, 116]
]

Ці позиції виконують ту саму роль:

[
   1,
   5,
   9,
   13,
   17,
   21,
   25,
   ...
]

Що я маю досі:

Використовуючи обмеження python, я зміг перевірити перші три обмеження:

Valid solution : False
            - sessions  : [True, True, True, True, True, True]
            - practices : [True, True, True, True, True, True]
            - roles     : [True, True, True, True]
            - teams     : [False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False]

Для тих, що можуть цікаво, я просто так:

Для кожної умови я використовую AllDifferentConstraint . Наприклад, за один сеанс я роблю:

problem.addConstraint(AllDifferentConstraint(), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24])

Я не в змозі знайти шлях до обмеження команди, остання моя спроба в цілому semesterбула така:

    def team_constraint(self, *semester):
        students = defaultdict(list)

        # get back each teams based on the format [# Semester [ #Session [# Practice/Team ... 
        teams = [list(semester[i:i+4]) for i in range(0, len(semester), 4)]

        # Update Students dict with all mate they work with
        for team in teams:
            for student in team:
                students[student] += [s for s in team if s != student]

        # Compute for each student if they meet someone more than once 
        dupli = []
        for student, mate in students.items():
            dupli.append(len(mate) - len(set(mate)))

        # Loosly constraint, if a student meet somone 0 or one time it's find
        if max(dupli) >= 2:
            print("Mate encounter more than one time", dupli, min(dupli) ,max(dupli))
            return False
        pprint(students)
        return True

Запитання:

  1. Чи можна робити те, що я хочу, для командних умов? Що я маю на увазі, що я не маю уявлення, чи можна призначити 12 товаришів для кожного учня, і кожен з них зустрінеться з тим самим товаришем лише один раз.
  2. Зважаючи на обмеження команди, я пропустив більш ефективний алгоритм?
  3. Якийсь піст, який я можу дотримуватися?

1
Чому останні два сеанси сеансів мають форму, (4, 4)а не (4, 6)як інші?
r.ook

Це відповідати тому, що цей курс є лише одним кредитом і вимагає багато роботи, тому мій начальник вважає, що студенти повинні робити лише 4 практики. Тож ми придумали це, у нас 32 студенти, які повинні робити 4 практики (128 позицій).
Флоріан Бернард

1
Я б спробував випадковий і жорстокий підхід. Так само робимо, як перестановка, коли ви вибираєте Сесія 1: Роль 1 Студент 1 Практикуйте 1 ... те ж саме з 2 до 4. Потім збільшуйте кожні 6 сеансів, відмовтеся від вже зустрічаються учнів. Те саме із випадковими. Чому 128 позицій і не використовувати на сесії 32 кількість студентів як макс у різних перестановках? Можливо, в stackMath вони можуть сказати вам, чи можлива ця комбінація / перестановка
Cristo

В даний час працює метод грубої сили, мій начальник повернувся до мене зі своїм сценарієм і його роботою дуже добре. Але я все ще хочу використовувати пітон.
Флоріан Бернард

Відповіді:


2

На головне питання відповіли б щось на зразок ...

   def person_works_with_different():
        # over all the sessions, each person works with each other person no more than once.
        # 'works with' means in 'same session team'
        for p in all_people:
            buddy_constraint = []
            for s in all_sessions:
                for g in all_teams:
                    p_list = [pv[k] for k in filter(lambda i: i[P] == p and i[S] == s and i[G] == g, pv)]
                    for o in all_people:
                        if o != p:  # other is not person
                            o_list = [self.pv[k] for k in filter(lambda i: i[self.P] == o and i[self.S] == s and i[self.G] == g, self.pv)]
                            tmp = model.NewBoolVar('')
                            buddy_constraint.append(tmp)
                            model.Add(sum(o_list) == sum(p_list)).OnlyEnforceIf(tmp)
                            # tmp is set only if o and p are in the same session/team
            # The number of times a student gets to take part is the number of roles.
            # The size of the group controlled by the number of roles
            model.Add(sum(buddy_constraint) = all_roles * (all_roles - 1)) 

Додано Правка

Учора я по-іншому подивився на вашу проблему - (правда, недовго, оскільки я зараз багато працюю), і ...

По-перше, я бачу, що ваша організація «команда» - це майже те, що я назвав сутністю «дії», і, зрештою, я вважаю, що «команда» (або «група») була кращим словом для цього.

Якщо ви все ще знаєте обмеження, я пропоную вам їх усунути та попрацювати над ними індивідуально - особливо обмеження команди / особи / сесії, а потім обмеження ролі / завдання.

/ Додано Правка

team: a gathering of 4 persons during a session
person (32): a participant of a team
session (6): time: eg, 8am -10am
role (4): what responsibility a person has in an action
task (6): type of action

A person does:
 0..1 action per session-group
 1 role per action
 1 task per action
 0..1 of each task
 1 of each role in an action
 4 persons in an action

A person meets each other person 0..1 times
An action requires exactly 4 people

У мене була подібна проблема нещодавно, і врешті-решт звернулася до OR-інструментів. https://developers.google.com/optimization/cp/cp_solver

Зокрема, ознайомтеся з проблемою планування медичної сестри: https://developers.google.com/optimization/scheduling/employee_scheduling#nurse_scheduling

У всякому разі, проблема не надто складна, тому, можливо, використання розв’язувача буде для вас надмірним.

Крім того, для подібного роду проблем може бути краще використовувати dict-ключ, щоб зберігати свої змінні, а не вкладені списки:

{Команда, сесія, особа: BoolVar}

Основна причина полягає в тому, що ви можете застосовувати обмеження за допомогою фільтрів, що набагато простіше, ніж робити вкладені маніпуляції зі списком, наприклад, застосовувати обмеження для осіб / команд, що ви можете зробити (де людина - індекс 2, а команда - індекс 0):

for p in all_persons:
    for t in all_teams:
        stuff = [b_vars[k] for k in filter(lambda i: i[2] == p and i[0] == t, b_vars)]
        model.Add(sum(stuff) == 4)  # persons per team == 4

1
Спасибі, що за цикл ви мали на увазі p for p in all_people?
Флоріан Бернар

1
Так - вибачте! Я «переклав» свої імена до вашої моделі, але був на роботі, тому було трохи швидко.
Кончог

1
Також список розсилки дуже підтримує OR-інструменти. Якщо вам потрібна допомога в моделюванні вашої проблеми, вони вкажуть на приклад коду або дадуть вам прекрасне уявлення про те, як встановити обмеження для групи / залежності
Konchog

Вибачте, але за рішенням вашої голови важко слідувати, звідки беруться я? А що таке змінні P, S та G? Що таке pv? Спасибі за вашу допомогу.
Флоріан Бернард

0

Просто ідея алгоритму перестановки, для кожної ітерації можна було зосередитись на одному з кожного учня або на одному з кожного сеансу:

Session 1:
Roles
1,2,3,4
Students
1,2,3,4

(Note is 1st permutation 1234)

Sess 2 for student 1
Roles 1234
Students 5,1,7,6

Тут студент 2 займає участь студента 1 в сесії 1 і продовжується так

Roles 1234
St 2,5,6,7 

Продовжуйте зі студентом 1 S3 R 1234 St 10,9,1,8

S4
R 1234
St 11,12,13,1

Наприкінці ви видаляєте взаємодії для учня 1, як на перестановках для наступної ітерації, ви видаляєте поточну.

Це як кубик рубіків.

Якщо ви отримаєте код цього чи знаєте якийсь код із цього альго, дайте мені знати.

Можливо, з перестановками itertools

Я вважаю, що сесії, ніж практики, не є такими релевантними. Просто трохи басейну, щоб зайняти більше, коли ви закінчите або більше місця для обертання. Може, можна спростити проблему, спочатку націлюючись на 4 сеанси = практики?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.