Pentru anul școlar care ar sta să înceapă, directorul (sau managerul)
școlii întocmește un plan de încadrare, stabilind între altele
(în conformitate cu anumite normative legale) ce discipline
școlare sunt de parcurs la fiecare clasă și care profesori, la
care clase și pe câte ore de curs, vor face
lecțiile respective.
Folosind datele desprinse din planul de încadrare, urmează să se
formuleze un orar care să indice pe zile și ore ale zilei, la
care clasă are de intrat fiecare profesor; firește, un profesor nu poate
intra, într-o zi și oră date, decât la o singură clasă; iar o clasă nu
poate avea într-o zi și oră date, decât un singur profesor — exceptând
cazul când, pentru unele discipline, s-a decis despărțirea clasei în
două grupe de elevi, repartizate fiecare, pentru ziua și ora
respectivă, la câte un profesor.
Planul de încadrare este bazat pe bugetul de salarii alocat școlii;
după volumul acestuia, se stabilește câte “norme didactice” pot fi
constituite, deci câți profesori pot fi angajați, pentru totalul
claselor și elevilor. În schimb, orarul școlar are de reflectat nu
interese, ci anumite “principii pedagogice” specifice activității de
învățare în care urmează să fie antrenați elevii, cu profesorii
respectivi; se recomandă ca elevii să aibă zilnic 5, 6, excepțional 7
ore; profesorii să nu fie încărcați cu mai mult de 6, excepțional 7
ore/zi; lecțiile pe o aceeași disciplină, la o clasă sau alta, să fie
distribuite echilibrat de-a lungul săptămânii, de regulă câte una pe zi
(și nicidecum, înghesuite în două zile).
Desigur, aceste principii trebuie amintite din start —evitând
contestări ulterioare, bazate și ele pe diverse “principii”— și chiar cu
o anumită fermitate din partea angajatorului (“te pot angaja pe 3 ore de
‘Fizică’, rămase neacoperite la clasa cutare, dar numai dacă accepți să
le faci câte una pe zi”…); dincolo de principii, pot să fie luate în
seamă și unele interese personale (dacă nu țin de “nazuri”), dar
important ar mai fi, pentru un orar acceptabil, ca numărul total de
ferestre apărute în orar să fie pe cât se poate de mic.
Constituirea unui orar echilibrat pleacă de la două sau trei
observații simple… Din planul de încadrare se deduce pentru fiecare
profesor și clasă, numărul de ore pe săptămână, pentru lecțiile
pe disciplina respectivă; numai că în orar trebuie evidențiată (pe câte
o zi și oră) fiecare dintre lecțiile respective. Prin urmare,
firesc este ca în loc de câte o singură linie
Disciplină / Profesor / Clasă / Număr_ore
, să înscriem câte
un număr de Număr_ore
linii identice (păstrând pe
fiecare numai primele trei câmpuri).
Această lungire a tabelului de încadrare asigură imediat o posibilitate
foarte simplă pentru a repartiza echilibrat pe zile, lecțiile unei
clase: pe lista care enumeră pe rând lecțiile fiecărui profesor al
clasei se adaugă o coloană pe care se repetă de sus în jos (pe cât
încape) secvența zilelor; astfel, lecțiile fiecărui profesor, fiind pe
linii consecutive, vor fi alocate în zile diferite (deci în principiu,
câte una pe zi).
Apoi, de ce să ne intereseze pe parcursul construcției orarului,
numele și prenumele? N-are de ce, cu atât mai mult că dacă vom publica
orarul cu “Nume și Prenume”, putem avea de-a face cu “legea drepturilor
personale”… Putem abrevia denumirile disciplinelor pe câte două
litere, desemnând apoi profesorii alipind celor două litere asociate
disciplinei principale pe care este încadrat fiecare, un număr de ordine
în lista celor de pe o aceeași disciplină (… “principală”, mascând
temporar diversele discipline “secundare” care ar fi anexate unora
dintre profesori — precum “Dirigenție”, sau “Cultură civică”, etc.). De
exemplu, “Bi1
”, “Bi2
”, “Bi3
” ar
desemna cei trei profesori de “Biologie”.
Avantajul acestei convenții prealabile de notație constă în faptul că
putem omite mai departe, câmpul pe care am nota disciplina
corespunzătoare fiecărei lecții (ea deducându-se din codul de 3
caractere al profesorului; desigur, la capăt vom putea avea în vedere și
disciplinele secundare, dacă le înregistrăm în prealabil într-un tabel,
pe profesori și clase); pe de altă parte, devine ușor de înregistrat
cuplajele (și ușor de corelat apoi, la repartizarea lecțiilor,
cu membrii respectivi): dacă Gr1
și Gr2
au de
făcut împreună o lecție “pe grupe” ale unei clase, atunci înființăm
“profesorul fictiv” Gr1Gr2
, atribuidu-i în orar
clasa respectivă.
În sfârșit, să observăm că, măcar până a deveni o “problemă” (clasică
sau altfel), constituirea orarului școlar are de-a face doar cu
seturi de date; este dat setul (sau tabelul) tuturor lecțiilor
prof|cls
ale săptămânii și acesta trebuie extins cu un câmp
pe care să figureze ziua și cu unul în care să înscriem ora, pentru
fiecare lecție (poate fi dat și un mic set suplimentar, cu lecții care
din diverse motive, trebuie plasate numai în anumite zile). Și se știe
deja că pentru lucrul eficient cu seturi de date (și nu numai pentru
treburile statisticii), cel mai potrivit este să folosim limbajul
R (cu “dialectul” tidyverse)…
Este normal să nu amestecăm lucrurile: întâi vom repartiza lecțiile
pe zile (dat fiind că vrem ca repartizarea lecțiilor de-a
lungul săptămânii să fie pe cât se poate de omogenă, pe zile,
pe clase și pe profesori) și abia apoi, pentru fiecare zi în parte, vom
repartiza lecțiile acesteia pe orele 1:7
ale zilei (ignorăm
cazul în care școala funcționează cu două schimburi: dacă încadrarea
profesorilor este judicios concepută, orarul unei asemenea școli revine
la două orare pe orele 1:7
, câte unul pentru fiecare
schimb). Iar în final, după ce vom fi completat corect câmpurile de zi
și oră, vom ajusta orarul rezultat astfel încât să reducem numărul total
de ferestre la o valoare acceptabilă.
În pachetele hours2lessons și refitgaps ne-am
ocupat deja de repartizarea pe orele 1:7
a lecțiilor
dintr-o aceeași zi, respectiv de reducerea ferestrelor din orarul unei
zile; în pachetul de față vizăm repartizarea echilibrată a lecțiilor
prof|cls
pe zilele săptămânii.
Sunt de avut în vedere mai multe categorii de profesori (și de lecții). Majoritatea profesorilor au numai ore proprii (fiecare intră singur, la una sau alta dintre clasele pe care a fost încadrat); fie LS1 subsetul lecțiilor acestora. Unii profesori, pe anumite discipline, au ore proprii, dar intră și în cuplaje (în ora respectivă, clasa este împărțită ad-hoc în două grupe, care fac lecția independent una de alta, cu câte unul dintre membrii cuplajului respectiv); fie LS2 subsetul lecțiilor acestora. Pot exista și cuplaje externe, în care niciunul dintre membri nu are ore proprii (deci nu figurează în LS1); convenim să adăugăm cuplajele externe în LS1.
În sfârșit, pe anumite discipline există lecții la unele clase care trebuie să se desfășoare în câte o aceeași zi și oră, împerechind câte un profesor cu câte o clasă; le numim lecții “tuplate” și desemnăm prin “tuplaj” grupul respectiv de profesori și clase. Ne așteptăm ca tuplajele, dacă este cazul, să fie specificate într-un set suplimentar de date, să-l notăm LS3.
LS1, LS2 și LS3 sunt firește, disjuncte între ele. La un moment viitor vom lua în considerație și existența unui set de lecții prealocate pe zile (pentru cazul celor care, fiind încadrați în două școli, nu pot fi prezenți decât în anumite două-trei zile)…
Cel mai simplu de alocat pe zile sunt lecțiile din LS2 și LS3:
ordonăm după profesor lecțiile subsetului respectiv și adăugăm o coloană
pe care repetăm o aceeași permutare de zile; această simplitate ne va
permite să generăm dinamic, repartițiile respective, după ce
vom fi obținut o repartiție pe zile pentru lecțiile din subsetul LS1:
dacă prin cumularea celor trei repartiții, găsim clase pentru care
numărul de ore/zi este în afara intervalului 5:7
, sau
profesori care cumulează mai mult de 7 ore/zi, atunci regenerăm
repartițiile pe zile pentru LS2 și LS3 (schimbând permutarea de zile
anterioară)… Putem spera că la un moment dat nimerim o repartizare pe
zile convenabilă, fiindcă pe de o parte, cuplajele și tuplajele sunt
relativ puține față de totalul lecțiilor și pe de altă parte… repartiția
lecțiilor din LS1 este deja omogenă pe clase și cvasi-omogenă pe
profesorii respectivi.
Repartizarea pe zile, echilibrată, a lecțiilor din LS1 este mai
anevoioasă, necesitând de obicei mai multe reluări. Pentru fiecare
clasă, într-o anumită ordine a acestora, se montează coloana zilelor
alocate lecţiilor ei: se dispun lecțiile clasei după profesori și se
caută o permutare de zile a cărei aplicare consecutivă pe lecțiile
respective asigură că până la momentul curent, distribuțiile pe zile ale
lecțiilor profesorilor clasei (cumulând cu cele rezultate pentru ei până
la clasa curentă) sunt cvasi-omogene (cu diferență de cel mult două ore,
între zile). În caz de succes, se actualizează valorile în vectorul care
păstrează numărul de ore alocate pe zile fiecărui profesor până la
momentul curent și se trece la următoarea clasă, până ce se parcurg
toate clasele. În caz de insucces (când pentru clasa curentă nu găsim
nicio permutare de zile convenabilă)… stopăm parcurgerea listei
claselor, re-inițializăm vectorul alocărilor pe zile și o luăm de la
capăt, dar într-o altă ordine a claselor.
Normativele existente limitează suficient de mult numărul maxim de ore
pe profesor și pe clasă, încât este de așteptat ca după un număr mai mic
sau mai mare de reluări, să nimerim o ordine de parcurgere integrală a
listei claselor, reușind astfel să montăm pe zile, lecțiile
fiecăreia.
Am înglobat setul de lecții LSS
și setul asociat de
tuplaje TPL
:
str(LSS)
#> 'data.frame': 870 obs. of 2 variables:
#> $ prof: chr "Bl2" "Mt1" "Gr4" "In2" ...
#> $ cls : chr "5A" "5A" "5A" "5A" ...
str(TPL)
#> 'data.frame': 27 obs. of 2 variables:
#> $ prof: chr "Gr3 Gr4" "Gr3 Gr1 Gr4" "Gr3 Gr1 Gr4" "Gr3 Gr1 Gr4" ...
#> $ cls : chr "10E 10F" "11A 11B 11D" "11A 11B 11D" "12A 12B 12D" ...
În LSS
sunt înregistrate și câteva cuplaje; de exemplu
In2In3
și In2In1
vor afecta numărul de ore/zi
alocate lecțiilor proprii ale lui In2
, In3
și
In1
.
Din TPL
deducem de exemplu că lecțiile Gr3 10E
și Gr4 10F
vor trebui să figureze în câte o aceeași zi.
Următoarea secvență produce într-un anumit timp, câte o repartizare echilibrată pe zile, a lecțiilor (și afișează distribuția pe zile a numărului total de lecții):
prnTime <- function(S = "") # va afișa timpul curent
cat(strftime(Sys.time(), format="%H:%M:%S"), S)
for(i in 1:2) {
prnTime(" ")
R123 <- mount_days(LSS, TPL) # Dfh = 2 (valoarea implicită)
prnTime("\n")
addmargins(table(R123[c('cls','zl')]))["Sum", 1:5] %>%
as.vector() %>% print()
}
09:27:24 09:27:40 # durată: sub 20 secunde
[1] 186 188 181 188 185
09:27:40 09:28:13 # durată: sub 40 secunde
[1] 184 187 185 185 187
Dintre cele două distribuții rezultate ar fi preferabilă a doua (în
care diferența între ore/zi este cel mult 3, nu 7 ca în prima).
Fiindcă am apelat mount_days()
cu parametrul implicit
Dfh = 2
, în repartițiile pe zile rezultate fiecare clasă
are o distribuție cvasi-omogenă a numărului de ore/zi (diferind de la o
zi la alta cu cel mult 2 ore); desigur, cu Dfh = 3
obțineam
mai rapid o repartiție, dar cu clase la care diferența între zile ajunge
totuși, la 3 ore…
Desigur, repartiția pe zile rezultată poate fi “cizelată” interactiv, pentru a transforma distribuțiile cvasi-omogene în distribuții omogene; dar constituirea unui set de funcții care să afișeze distribuțiile pe zile existente la unele clase sau la unii profesori și să permită schimbarea zilei alocate unei lecții în scopul omogenizării unor distribuții individuale — ar fi probabil sarcina unui alt pachet (viitor).