[1] Orar pe o școală fără profesori (V)
[2] V.Bazon - De la seturi de date și limbajul R, la orare școlare (Google Books)
[3] V. Bazon - Orare școlare echilibrate și limbajul R (Google Books)
[4] Noul orar (partea a patra) și partea a cincea
Pentru tuplajele cu număr de profesori mai mare ca numărul de clase, inventăm câte un cuplaj — reducându-le astfel la tuplaje standard, cu părți de aceeași dimensiune.
De exemplu, înlocuim tuplajul (Fr1 Fr2 Gr1)
/ (11C 11E)
de trei profesori pe două clase, cu (Fr1Fr2 Gr1)
/ (11C 11E)
în care cuplajul nou Fr1Fr2
este asociat clasei 11C
(ca și cum aceasta ar fi despărțită în două grupe, la care intră respectiv Fr1
și Fr2
, iar Gr1
intră în ora respectivă la 11E
; în realitate, elevii celor trei clase sunt distribuiți cu abstracție de clasă în trei "grupe", câte una fiecărui profesor).
Aceasta impune anumite corecții în setul R12.RDS
(al tuturor lecțiilor prof|cls|zl
, repartizate deja pe zile), în listele Tw12.Rda
asociate cuplajelor existente și desigur, în "orarele parțiale" tj{1,2}.RDS
asociate tuplajelor.
De exemplu, în R12
clasa 11C
apare la Fr2
(v. [1]):
prof Lu Ma Mi Jo Vi Fr2 05C 09A 11C 10C 09A 10C 11C 07A 11A 05C 07A 11A
ori acum ea trebuie pasată profesorului fictiv "Fr1Fr2
":
R12$prof[with(R12, prof=="Fr2" & cls=="11C" & zl %in% c("Lu", "Mi"))] <- "Fr1Fr2"
La fel avem de schimbat și la alte clase dintre cele implicate în tuplaje.
Deasemenea, avem de adăugat unele lecții, materializându-le pe cele care în [1] rămăseseră subînțelese:
R12 <- R12 %>% add_row(cls = c("12A", "10C"), prof = c("Fr1", "Fr3"), zl="Ma")
Avem apoi de adăugat unele chei și valori în dicționarele din "Tw12.Rda
", de exemplu:
Tw1[["Fr1"]] <- c(Tw[["Fr1"]], "Fr1Fr3", "Fr1Fr2") Tw1[["Gr1"]] <- c("Fr1Gr1", "Fr2Gr1", "Gr1Gr2") Tw2[["Gr1Gr2"]] <- c("Gr1", "Gr2", "Fr1Gr2", "Fr2Gr1", "Fr1Gr1")
Și în sfârșit, reformulăm într-o singură listă "tj12.RDS
", orarele parțiale constituite în [1] pentru tuplaje, evidențiind noile cuplaje:
> readRDS("tj12.RDS") # orarul parțial pe tuplaje $Lu # ilustrare prof cls ora Fr2 Fr3 Gr1 09A 09C 09D 0 Fr3 Gr1Gr2 10A 10D 0 Fr1Fr2 Gr1 11C 11E 0 Fr1Fr3 Gr2 12C 12E 0 Ds1 Mz1 09C 09D 0
Acum logica alocării pe ore a tuplajelor (folosind câmpul "ora
" al acestora), în cursul procesului de alocare pe orele 1:7
a lecțiilor dintr-o aceeași zi, corespunde în principiu, celei descrise deja în [2] și deasemenea, în [4].
Doar că, în secvența din mount_h1.R
care tratează cazul când profesorul curent face parte dintr-un tuplaj, trebuie să ținem seama de faptul că acum, se poate să fie vorba nu de un profesor propriu-zis, ci de unul fictiv (cuplaj, pentru care trebuie verificat ca membrii acestuia să fie și ei liberi, în ora propusă pentru alocarea lecției tuplajului).
Procedăm exact ca în [4] (omitem aici, modificarea făcută ad-hoc deocamdată, în mount_h1.R
); dar simplificăm (definitiv) funcția "actual_tpl()
" din bindHours.R
:
P23i <- readRDS("tj12.RDS") actual_tupl <- function() { tupl <- P23i Ora <- list() for(zi in Zile) { Prof <- tupl[[zi]]$prof %>% paste(., collapse=" ") %>% strsplit(., " ") %>% unlist() Cls <- tupl[[zi]]$cls %>% paste(., collapse=" ") %>% strsplit(., " ") %>% unlist() Ora[[zi]] <- ORR[[zi]] %>% filter(prof %in% Prof, cls %in% Cls) } Ora }
Obținem (și repede) lista ORR
, conținând repartizarea pe ore a lecțiilor din fiecare zi:
> source("bindHours.R") 18:22:43 Lu 973 încercări 18:24:52 Ma 525 încercări 18:25:57 Mi 52 încercări 18:26:02 Jo 182 încercări 18:26:26 Vi 9 încercări 18:26:27
Redăm aici orarul rezultat pe Lu
, în formatul asigurat de funcțiile actual_tupl()
(prin care se extrage orarul tuplajelor) și hourly_matrix()
(v. [4]):
[1] "Lu" prof cls ora # orarul tuplajelor 1 Fr2 09A 4 # Fr2, Fr3 și Gr1 în ora 4, la 9A+9C+9D 2 Fr3 09C 4 3 Ds1 09C 6 # Ds1 și Mz1 în ora 5, la 9C și 9D 4 Gr1 09D 4 5 Mz1 09D 6 6 Fr3 10A 2 # Fr3, Gr1 și Gr2 în ora 2, la 10A+10D (trei grupe) 7 Gr1Gr2 10D 2 8 Fr1Fr2 11C 1 # Fr1, Fr2 și Gr1 în ora 1, la 11C+11E (trei grupe) 9 Gr1 11E 1 10 Fr1Fr3 12C 5 # Fr1, Fr3 și Gr2 în ora 5, la 12C+12E (trei grupe) 11 Gr2 12E 5 1 2 3 4 5 6 7 1 2 3 4 5 6 7 Bi1 12D - 10D 06C - - - In2 - - 12A 09E 11E 11B - Bi2 10A 06A 11E 10B - - - In3 11A 05A 09D - - - - Bi3 - 07D - 06B 12A 07A - Is1 - - 07A 07C 10C 10E - Ch1 11D - 11B - 09D 12B - Is2 - 12A 11D 11E - 08D - Ch2 10B - 12C 10C 09C 11C - Is3 06A - - 11A 08B 12E - Ch3 08C 08D - - - - - LL1 09E 07C - - - - - Ds1 - - - 07D 06A 09C 08D Mt1 11B 12B 08D - - - - Ec1 10D 11E - - - - - Mt2 - - 06A 12C 07A 08B - En1 - - 10B 06A 09A 11E 09D Mt3 - 10B 07D - 07C 10D - En2 07C - - 07A 10E 08A 08B Mt4 - 09A - 12D 05C 06B - En3 - 12D - 11D 11A 09E - Mt5 06C 10C - 10A 11D - - En4 08D - 12B 08C 05A - - Mt6 09D - 08A - 08C - - En5 - - 06B 05B 11B 09B - Mt7 - 09B 07B 12A 05B 11A - ES1 - 08C 05A - - 07D - Mz1 - 06B - 08A 06C 09D - Ff1 12E 09C - - - - - Ph1 10E 12C - - - - - Fi1 12C - 10A 11B - - - Rg1 - - 09A 08B 08A 12A - Fi2 - 07A 09E - 07D 12D - Rg2 - 11C 08C 05A - - - Fi3 10C - - 09B 10D 11D - Ro1 07A - - 10D 07B - - Fi4 - - 08B 11C 06B 10B - Ro2 09A 12E 09B - - - - Fi5 09C - - - - - - Ro3 - - 06C - 08D 06A - Fr1 - 05B - - - - - Ro4 - 08A 05B 10E - - - Fr1Fr2 11C - - - - - - Ro5 05C 09D 10C - - - - Fr1Fr3 - - - - 12C - - Ro6 - - - 12B 09E 12C - Fr1Gr1 - - 12D - - - - Ro7 - - - - 12D 10A 08C Fr2 - 05C - 09A - - - Ro8 08B 11B - - - - - Fr3 - 10A - 09C - 07B - Ro9 05A - 07C - - - - Gg1 12A 11D - 12E 12B - - Sp1 - 10E 12E - - - - Gg2 - - 11A 05C 11C 08C - SP1 07D 09E 10E - - 07C - Gg3 06B 07B - - - - - SP2 09B 08B - - 10A 10C - Gr1 11E - - 09D - - - SP3 07B 11A 11C - 10B - - Gr1Gr2 - 10D - - - - - Th1 05B - 05C 07B - - - Gr2 - - - 08D 12E 05A - TI1 08A 06C - - - - - In1 12B - 09C - 09B 09A -
Pentru unele investigații, să listăm toate lecțiile pe "Fr/Gr
" (nu numai pe cele din tuplaje, ca mai sus, ci și lecțiile proprii sau în cuplaj):
> ORR[["Lu"]] %>% filter(grepl("Fr|Gr", prof)) %>% arrange(ora) prof cls ora 1 Fr1Fr2 11C 1 2 Gr1 11E 1 3 Fr1 05B 2 # lecție proprie 4 Fr2 05C 2 5 Fr3 10A 2 6 Gr1Gr2 10D 2 7 Fr1Gr1 12D 3 # cuplaj pe 12D 8 Gr2 08D 4 9 Fr2 09A 4 10 Fr3 09C 4 11 Gr1 09D 4 12 Fr1Fr3 12C 5 13 Gr2 12E 5 14 Gr2 05A 6 15 Fr3 07B 6
Să observăm că Fr1
are orele 1, 2, 3 și 5 — deci are o fereastră, în a 4-a oră; în a 3-a oră avem câte o fereastră la Fr2
și Fr3
, iar Gr2
are două ferestre. Deci în total, la profesorii angajați în tuplaje și cuplaje pe ziua de Lu
, avem 5 ferestre — ceea ce este cam mult, având în vedere că procedura de reducere a numărului de ferestre pe care o vom aplica mai departe nu mută lecțiile tuplate, din locul stabilit lor; însă ar fi de refuzat să ne ocupăm de vreo „îndreptare” a lucrurilor — dacă inventezi tuplaje așa de întortocheate (în loc să ai grijă cum repartizezi elevii pe clase, la începutul anului școlar), atunci trebuie să prevezi și să-ți asumi consecințele…
În orarele rezultate mai sus avem pe fiecare zi cam câte 40 ferestre; procedând exact ca în [4]-V, am reușit (în timpi de ordinul a 4-5 minute/zi) să reducem la câte 12-14 ferestre/zi. De exemplu, pentru Lu
(al cărei orar inițial l-am redat mai sus) ne-a rezultat un orar cu 12 ferestre (dintre care 5 sunt cele moștenite din orarul parțial pe care-l stabilisem pentru tupaje):
1 2 3 4 5 6 7 1 2 3 4 5 6 7 Bi1 12D 06C 10D - - - - In2 - - 09E 11E 12A 11B - Bi2 - - 10A 06A 11E 10B - In3 11A 09D 05A - - - - Bi3 07D 12A - - 06B 07A - Is1 - - 07A 07C 10C 10E - Ch1 - - - 12B 11B 11D 09D Is2 - - 12A 08D 11D 11E - Ch2 12C 10B 10C - 09C 11C - Is3 06A 11A 08B 12E - - - Ch3 - - - - 08C 08D - LL1 09E 07C - - - - - Ds1 - - - 07D 06A 09C 08D Mt1 12B 08D 11B - - - - Ec1 10D 11E - - - - - Mt2 - - 06A 07A 08B 12C - En1 09A 06A 11E 10B 09D - - Mt3 - - 10B 10D 07C 07D - En2 08B 07A 10E - 08A 07C - Mt4 05C 06B 09A 12D - - - En3 11D 09E - - 11A 12D - Mt5 10C 11D 06C 10A - - - En4 08C 12B 08D 05A - - - Mt6 08A 08C 09D - - - - En5 - - 05B 11B 09B 06B - Mt7 - 09B 07B 11A 05B 12A - ES1 05A 07D 08C - - - - Mz1 - - 06B 08A 06C 09D - Ff1 12E 09C - - - - - Ph1 10E 12C - - - - - Fi1 10A 11B 12C - - - - Rg1 - - - 12A 09A 08A 08B Fi2 07A 12D 07D 09E - - - Rg2 - - - 11C 05A 08C - Fi3 - - 11D 10C 10D 09B - Ro1 - - - 07B 07A 10D - Fi4 - - 11C 06B 10B 08B - Ro2 09B 09A 12E - - - - Fi5 09C - - - - - - Ro3 - - - 06C 08D 06A - Fr1 - 05B - - - - - Ro4 05B 10E 08A - - - - Fr1Fr2 11C - - - - - - Ro5 09D 10C 05C - - - - Fr1Fr3 - - - - 12C - - Ro6 - - - 12C 09E 12B - Fr1Gr1 - - 12D - - - - Ro7 - - - 08C 12D 10A - Fr2 - 05C - 09A - - - Ro8 11B 08B - - - - - Fr3 07B 10A - 09C - - - Ro9 07C 05A - - - - - Gg1 12A 12E 12B 11D - - - Sp1 - - - - 10E 12E - Gg2 - - - 05C 11C 11A 08C SP1 - - 07C 10E 07D 09E - Gg3 06B 07B - - - - - SP2 - - 09B 08B 10A 10C - Gr1 11E - - 09D - - - SP3 10B 11C 11A - 07B - - Gr1Gr2 - 10D - - - - - Th1 - - - 05B 05C 07B - Gr2 08D - - - 12E 05A - TI1 06C 08A - - - - - In1 - - 09C 09B 12B 09A -
Prin funcția următoare putem transforma matricele-orar înapoi, în forma normală prof|ora|cls
, din care apoi putem formula ușor orarele claselor sau profesorilor:
mop_to_normal <- function(Mop) { # matrice-orar pentru o zi as.data.frame(Mop) %>% mutate(prof = rownames(Mop), .before = 1) %>% pivot_longer(cols = 2:ncol(.), names_to = "ora", values_to = "cls") %>% filter(cls != "-") } # set de date prof|ora|cls pentru ziua respectivă
De exemplu, să extragem din matricea redată mai sus orarul (pe Lu
) al clasei 08B
, redându-l pe discipline:
ORR <- readRDS("W1.RDS") # matricele orare ale zilelor Obj <- readRDS("../24nov/objabb.RDS") # setul discip|cod, constituit anterior Dsp <- Obj$discip %>% setNames(Obj$cod) # dicționar cod -> discip Lu <- mop_to_normal(ORR[["Lu"]]) # orarul zilei, în forma normală orar_cls <- function(Q, MZ) { # extrage orarul clasei din matricea-orar a zilei orr <- MZ %>% filter(cls==Q) %>% arrange(ora) %>% select(prof) %>% mutate(obj = Dsp[substr(prof, 1,2)]) orr$obj %>% as.vector() } print(orar_cls("08B", Lu), quote=FALSE) #[1] Engleză Română Istorie Sport Matematică Fizică Religie
Aici am dedus disciplina doar pe baza primelor două caractere din prof
; dacă vrem să avem în vedere și disciplinele secundare, precum și tuplajele existente, atunci sunt necesare unele adaptări. Iterând orar_cls()
pe zile și pe clase, putem obține într-un fișier-text orarele claselor, pe discipline (… ca pentru o școală fară profesori).
Studiul în șase părți prezentat aici a plecat acum vreo două luni, de la un "Orar general clase" (cum îl numește aplicația "aSc Orare", larg folosită în școlile noastre) postat pe Internet ca fișier PDF, în care fiecare pagină conține într-un "tabel Excel" orarul câte unei clase, specificând însă numai disciplinele (nu și profesorii, cu excepția cazurilor de lecții "pe grupe"). Ne-am pus problema de a "inventa" profesorii omiși, în număr minim pe fiecare disciplină, încât încadrarea acestora pe clase să corespundă cât mai bine, orarului pe discipline existent.
Pentru a rezolva chestiunea, întâi am constituit un set de date cls|obj|zl|ora
corespunzător paginilor PDF ale claselor; apoi am observat că încadrarea pe clase a profesorilor de pe o aceeași disciplină, corespunde unei colorări pe vârfuri a grafului claselor care nu pot fi atribuite unui aceluiași profesor (fiindcă s-ar suprapune valorile zl|ora
existente).
Odată ce am obținut o încadrare acceptabilă prof|cls
, compatibilă ca repartizare pe zile și ore, cu orarele "fără profesori" originale — firește că am vrut să îi asociem un nou orar; în acest scop am folosit iarăși, procedurile de lucru și funcțiile puse la punct în [2] și [3] — dar acum a apărut și o situație nouă; pe lângă cuplaje și tuplaje, avem de considerat și simultane: situații în care mai mult de doi profesori fac lecții într-un același timp, cu grupe de elevi proveniți din mai multe clase de bază. Deocamdată am tratat simultanul prin reducere la tuplaj (în care părțile au aceeași dimensiune): am înlocuit doi profesori cu un cuplaj nou, pe una dintre clasele simultanului; pare a fi cea mai bună idee, dar probabil… ar fi momentul de a rescrie [2] sau [3].
vezi Cărţile mele (de programare)