problema di soddisfazione del vincolo mancante di un vincolo


13

Sono un tutor di laboratorio all'università, sulla base dei commenti degli studenti dell'anno scorso, volevamo che io e il mio capo li affrontassimo. Il mio capo ha scelto di scrivere uno script C e ho scelto python (vincolo python) per provare a risolvere il nostro problema.

informazioni

  • Ci sono 6 sessioni
  • Ci sono 4 ruoli
  • Ci sono 6 pratiche
  • Ci sono 32 studenti
  • Ci sono 4 studenti per squadra

Problema:

Assegna a ogni studente 4 ruoli, in 4 esercitazioni in 4 sessioni diverse.

Vincoli:

  1. Gli studenti dovrebbero svolgere un ruolo una volta
  2. Gli studenti dovrebbero fare 4 pratiche diverse su 6
  3. Gli studenti dovrebbero fare solo una pratica per sessione
  4. Lo studente dovrebbe incontrare lo stesso compagno una sola volta

Modelli:

Ecco il modello che sento con gli studenti, in cui ogni squadra è composta da 4 studenti, le posizioni [0, 1, 2 o 3] sono ruoli assegnati a loro. Ogni posizione disponibile è numerata da 1 a 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]]]

In altre parole :

Questa è una sessione:

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

Quella squadra fa la stessa pratica:

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

Quelle posizioni svolgono lo stesso ruolo:

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

Quello che ho finora:

Utilizzando python-vincolo sono stato in grado di convalidare i primi tre vincoli:

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]

Per quelli che potrebbero essere interessanti, faccio semplicemente così:

Per ogni condizione utilizzo AllDifferentConstraint . Ad esempio, per una sessione faccio:

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

Non riesco a trovare un modo per limitare la squadra, il mio ultimo tentativo nel complesso è semesterstato questo:

    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

Domande :

  1. È possibile fare ciò che voglio per le condizioni del team? Quello che voglio dire è che non ho idea se è possibile assegnare 12 compagni a ogni studente e ognuno di loro incontra lo stesso compagno una sola volta.
  2. Per il vincolo del team, ho perso un algoritmo più performante?
  3. Qualche pistola che posso seguire?

1
Perché le ultime due serie di sessioni hanno una forma (4, 4)anziché (4, 6)come le altre?
Guarda il

Deve corrispondere al fatto che questo corso è solo un credito e richiede molto lavoro, quindi il mio capo merita che gli studenti dovrebbero fare solo 4 pratiche. Quindi abbiamo pensato a questo, abbiamo 32 studenti, che dovrebbero fare 4 pratiche (128 posizioni).
Florian Bernard,

1
Proverei un approccio casuale e bruto. Fai come una permutazione in cui scegli Sessione 1: Ruolo 1 Studente 1 Esercita 1 ... lo stesso con 2 a 4. Quindi incrementa per ogni 6 sessioni, scarta gli studenti già incontrati. Lo stesso con casuale. Perché 128 posizioni e non utilizzare per sessione 32 numero di studenti come massimo in diverse permutazioni? Forse in stackMath possono dirti se questa è una possibile combinazione / permutazione
Cristo,

Attualmente il metodo della forza bruta funziona, il mio capo è tornato da me con la sua sceneggiatura e il suo lavoro davvero bene. Ma voglio ancora usare Python.
Florian Bernard,

Risposte:


2

Alla domanda principale verrebbe data una risposta come ...

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

Aggiunto Modifica

Ieri ho dato un'altra occhiata al tuo problema - (è vero, non molto tempo, dato che al momento ho molto lavoro da fare), e ...

Prima di tutto, vedo che la tua entità "squadra", è praticamente quella che ho chiamato un'entità "azione" e, a posteriori, penso che "squadra" (o "gruppo") sia una parola migliore per questo.

Se stai ancora trovando i vincoli difficili, ti suggerisco di eliminarli e di lavorarci individualmente, in particolare i vincoli squadra / persona / sessione, seguiti dai vincoli ruolo / compito.

/ Aggiunto Modifica

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

Di recente ho avuto un problema simile e alla fine mi sono rivolto agli strumenti OR. https://developers.google.com/optimization/cp/cp_solver

In particolare, dai un'occhiata al problema di pianificazione degli infermieri: https://developers.google.com/optimization/scheduling/employee_scheduling#nurse_scheduling

Ad ogni modo, il problema non è troppo complesso, quindi forse usare un risolutore sarebbe eccessivo per te.

Allo stesso modo, per questo tipo di problema potrebbe essere meglio usare un dict con chiave tupla per contenere le variabili, piuttosto che gli elenchi nidificati:

{Squadra, sessione, persona: BoolVar}

Il motivo principale è che puoi quindi applicare i vincoli tramite i filtri, che è molto più semplice che dover fare manipolazioni di elenchi nidificati, ad esempio, per applicare un vincolo tra persone / team, puoi farlo (dove persona è indice 2 e squadra è indice 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
Grazie, per il ciclo for intendevi p for p in all_people?
Florian Bernard,

1
Si scusa! Ho "tradotto" i miei nomi nel tuo modello, ma ero al lavoro, quindi è stato un po 'veloce.
Konchog,

1
Inoltre, la mailing list è davvero di supporto a OR-tools. Se hai bisogno di aiuto per modellare il tuo problema ti indicheranno un codice di esempio o ti daranno una grande idea su come impostare i vincoli di gruppo / dipendenza
Konchog

Mi dispiace ma la tua soluzione per la testa è difficile da seguire, da dove viene l'io? E quali sono le variabili P, S e G? Cos'è il PV? Grazie per l'aiuto.
Florian Bernard,

0

Solo un'idea di algoritmo di permutazione, per ogni iterazione potrebbe essere focalizzata su uno di ciascuno studente o in una di ciascuna sessione:

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

Qui lo studente 2 ha luogo nello studente 1 nella sessione 1 e continua così

Roles 1234
St 2,5,6,7 

Continua con lo studente 1 S3 R 1234 St 10,9,1,8

S4
R 1234
St 11,12,13,1

Alla fine rimuovi le interazioni per lo studente 1, come sulle permutazioni per la successiva iterazione che rimuovi corrente.

È come un cubo di Rubik.

Se riesci a programmare questo o conosci un codice con questo algo fammelo sapere.

Forse con le permutazioni itertools

Essendo le sessioni> delle pratiche, credo che non sia così rilevante il suo numero. Solo un po 'di pool per prenderne di più quando si esaurisce o più spazio per la rotazione. Forse potrebbe semplificare il problema prima mirando a 4 sessioni = pratiche?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.