kendala kepuasan masalah hilang satu kendala

13

Saya seorang tutor praktikum di universitas, berdasarkan komentar siswa tahun lalu, kami ingin, bos saya dan saya, untuk mengatasinya. Bos saya memilih untuk menulis skrip C dan saya memilih python (python-constraint) untuk mencoba menyelesaikan masalah kita.

Informasi

  • Ada 6 sesi
  • Ada 4 peran
  • Ada 6 praktik
  • Ada 32 siswa
  • Ada 4 siswa per tim

Masalah:

Tugasi setiap siswa ke 4 peran, dalam 4 praktik dalam 4 sesi yang berbeda.

Kendala:

  1. Siswa harus berperan sekali
  2. Siswa harus melakukan 4 praktik berbeda dari 6
  3. Siswa harus melakukan hanya satu latihan per sesi
  4. Siswa harus bertemu pasangan yang sama hanya sekali

Templat:

Inilah templat yang saya rasakan dengan siswa, di mana setiap tim terdiri dari 4 siswa, posisi [0, 1, 2 atau 3] adalah peran yang diberikan kepada mereka. Setiap posisi yang tersedia diberi nomor dari 1 hingga 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]]]

Dengan kata lain :

Ini adalah sesi:

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

Tim-tim itu melakukan latihan yang sama:

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

Posisi itu melakukan peran yang sama:

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

Apa yang saya miliki sejauh ini:

Menggunakan python-constraint, saya dapat memvalidasi tiga kendala pertama:

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]

Bagi mereka yang mungkin menarik, saya cukup melakukan ini:

Untuk setiap kondisi saya menggunakan AllDifferentConstraint . Misalnya, untuk satu sesi saya lakukan:

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])

Saya tidak dapat menemukan cara untuk membatasi tim, upaya terakhir saya secara keseluruhan semesteradalah ini:

    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

Pertanyaan:

  1. Apakah mungkin untuk melakukan apa yang saya inginkan untuk kondisi tim? Maksud saya adalah saya tidak tahu apakah mungkin untuk menetapkan 12 pasangan untuk setiap siswa dan masing-masing dari mereka bertemu pasangan yang sama hanya sekali.
  2. Untuk batasan tim, apakah saya kehilangan algoritma yang lebih berkinerja?
  3. Adakah yang bisa saya ikuti?
Florian Bernard
sumber
1
Mengapa dua set sesi terakhir merupakan bentuk (4, 4)alih-alih (4, 6)seperti yang lain?
mulai
Ini untuk mencocokkan fakta bahwa kursus ini hanya satu kredit dan membutuhkan banyak pekerjaan, jadi bos saya memutuskan bahwa siswa hanya boleh melakukan 4 latihan. Jadi kami datang dengan ini, kami memiliki 32 siswa, yang harus melakukan 4 latihan (128 posisi).
Florian Bernard
1
Saya akan mencoba pendekatan acak dan kasar. Lakukan saja seperti permutasi di mana Anda memilih Sesi 1: Peran 1 Siswa 1 Latihan 1 ... sama dengan 2 hingga 4. Kemudian kenaikan untuk setiap 6 sesi, buang siswa yang sudah bertemu. Sama dengan acak. Mengapa 128 posisi dan tidak menggunakan per Sesi 32 jumlah siswa sebagai maks dalam permutasi yang berbeda? Mungkin di stackMath mereka dapat memberi tahu Anda apakah ini kombinasi / permutasi yang mungkin
Cristo
Saat ini metode brute force bekerja, bos saya kembali kepada saya dengan skripnya dan kerjanya sangat baik. Tapi saya masih ingin menggunakan python.
Florian Bernard

Jawaban:

2

Pertanyaan utama akan dijawab dengan sesuatu seperti ...

   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)) 

Menambahkan Edit

Saya melihat lagi masalah Anda kemarin - (memang tidak lama, karena saya punya banyak pekerjaan saat ini), dan ...

Pertama-tama, saya melihat bahwa entitas 'tim' Anda, adalah apa yang saya sebut entitas 'aksi', dan dalam retrospeksi saya pikir 'tim' (atau 'grup') adalah kata yang lebih baik untuk itu.

Jika Anda masih menemukan kendala sulit, saya sarankan Anda memecahkannya, dan mengatasinya secara individual - terutama kendala tim / orang / sesi, diikuti oleh kendala peran / tugas.

/ Ditambahkan Edit

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

Saya memiliki masalah yang sama baru-baru ini, dan pada akhirnya beralih ke OR-tools. https://developers.google.com/optimization/cp/cp_solver

Khususnya, lihat masalah penjadwalan perawat: https://developers.google.com/optimization/scheduling/employee_scheduling#nurse_scheduling

Bagaimanapun, masalahnya tidak terlalu rumit, jadi mungkin menggunakan pemecah akan terlalu banyak untuk Anda.

Demikian juga, untuk masalah semacam ini, mungkin lebih baik menggunakan dikt kunci tuple untuk menampung variabel Anda, daripada daftar bersarang:

{Tim, Sesi, Orang: BoolVar}

Alasan utamanya adalah Anda kemudian dapat menerapkan kendala melalui filter, yang jauh lebih mudah daripada harus melakukan manipulasi daftar bersarang, misalnya, untuk menerapkan kendala di seluruh orang / tim, Anda dapat melakukannya (di mana orang diindeks 2 dan tim diindeks 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
Konchog
sumber
1
Terima kasih, untuk for loop yang Anda maksud p for p in all_people?
Florian Bernard
1
Ya - maaf! Saya 'menerjemahkan' nama saya ke model Anda, tetapi sedang bekerja jadi agak cepat.
Konchog
1
Juga, milis sangat mendukung di OR-tools. Jika Anda memerlukan bantuan untuk memodelkan masalah Anda, mereka akan mengarahkan Anda ke contoh kode atau memberi Anda ide bagus tentang cara mengatur batasan grup / dependensi
Konchog
Maaf, solusi kepala Anda sulit diikuti, dari mana datangnya diri? Dan apa variabel P, S dan G? Apa itu pv? Terima kasih atas bantuan Anda.
Florian Bernard
0

Hanya ide algoritme permutasi, untuk setiap iterasi dapat difokuskan pada satu dari setiap siswa atau dalam satu dari setiap sesi:

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

Di sini siswa 2 mengambil tempat siswa 1 di sesi 1 dan berlanjut seperti ini

Roles 1234
St 2,5,6,7 

Lanjutkan dengan siswa 1 S3 R 1234 St 10,9,1,8

S4
R 1234
St 11,12,13,1

Pada akhirnya Anda menghapus interaksi untuk siswa 1, seperti pada permutasi untuk iterasi berikutnya yang Anda hapus saat ini.

Ini seperti kubus rubiks.

Jika Anda mendapatkan kode ini atau mengetahui beberapa kode dengan algo ini, beri tahu saya.

Mungkin dengan permutasi itertools

Sesi lebih dari praktik saya percaya tidak relevan dengan jumlahnya. Hanya beberapa kolam untuk mengambil lebih banyak ketika Anda kehabisan atau lebih banyak ruang untuk rotasi. Mungkin bisa menyederhanakan masalah yang pertama bertujuan untuk 4 sesi = praktik?

Cristo
sumber