Esercitazione greedy - tracce su CD, scheduling shortest-first e (2,1)-boxing
In questa pagina 5
L'esercitazione ha lo scopo di mostrare che un approccio greedy spesso cattura la strategia risolutiva più naturale e umana, che per alcuni problemi è provatamente ottima, e che scrivere l'algoritmo è immediato mentre provare che è ottimo resta delicato anche per un caso semplicissimo. La teoria è in Paradigma greedy - scelta golosa, sottostruttura e selezione delle attivitàIl paradigma greedy compie subito una scelta localmente migliore (scelta greedy), pulisce l'istanza (clean-up) e risolve l'unica sottoistanza residua, con ricorsione di coda eliminabile; il codice è facile, la correttezza no e richiede due proprietà, la scelta greedy (esiste un ottimo che la contiene) e la sottostruttura ottima (cut-and-paste), da cui la correttezza segue per induzione. Caso di studio: la selezione delle attività, con l'algoritmo del primo che finisce, correttezza completa, complessità Theta(n) dopo l'ordinamento e controesempi per le scelte greedy sbagliate.Paradigma greedy - scelta golosa, sottostruttura e selezione delle attività → e, per il caso più importante, in Codifica di Huffman - codici prefissi, algoritmo e ottimalitàCompressione con codifica per carattere: la lunghezza variabile risparmia bit ma deve essere iniettiva, e i codici prefissi lo garantiscono; un codice prefisso è un trie binario con una foglia per carattere, di costo B(T) = somma di f(c) d_T(c), e quello ottimo è un albero pieno con n-1 nodi interni. L'algoritmo di Huffman fonde ripetutamente i due alberi di frequenza minima usando una coda con priorità (2n-1 estrazioni, costo O(n log n)); l'ottimalità si prova con la scelta greedy (i due caratteri più rari sono foglie sorelle di profondità massima, per scambio) e la sottostruttura (B(T) = B(T') + f(x) + f(y)). Esempio completo con 6 caratteri, B = 2,24.Codifica di Huffman - codici prefissi, algoritmo e ottimalità →.
Il metodo, in sei passi
- Scelta greedy: la prima scelta, quella che sembra localmente migliore, fatta senza risolvere sottoistanze.
- Clean-up e sottoistanza residua: cosa si elimina dopo la scelta; ciò che resta è una sottoistanza dello stesso problema.
- Algoritmo: discende direttamente dai passi 1 e 2 (ricorsione di coda, quindi un ciclo). Si dà lo pseudocodice, si argomenta che l'uscita è ammissibile e si calcola la complessità.
- Proprietà di scelta greedy: esiste una soluzione ottima che contiene la scelta greedy. Si parte da una soluzione ottima qualsiasi e, se non la contiene, la si modifica (scambio, cut-and-paste) senza peggiorare il costo, controllando che resti ammissibile.
- Proprietà di sottostruttura ottima: la parte di un ottimo che resta dopo la scelta greedy è ottima per la residua. Si dimostra per assurdo: una residua migliore, composta con la scelta greedy, darebbe una soluzione migliore dell'ottimo.
- Conclusione: per induzione sulla taglia (base: istanza vuota), l'algoritmo ritorna un ottimo.
Se non c'è clean-up (nessuna incompatibilità) la sottostruttura (passo 5) è quasi immediata: ogni soluzione della residua si può completare con la scelta greedy. È il caso di tutti e tre i problemi qui sotto; la sottostruttura più delicata è quella della selezione delle attività, dove il clean-up è limitato.
I tre problemi a confronto
| Tracce su CD | Shortest-first scheduling | (2,1)-boxing | |
|---|---|---|---|
| Istanza | durate in ordine fisso, capienza | tempi di job | pesi in |
| Obiettivo | minimo numero di CD | minimo tempo di attesa cumulativo | minimo numero di scatole (al più 2 oggetti, peso ) |
| Scelta greedy | il più lungo prefisso che sta sul primo CD | il job di durata minima per primo | se o , altrimenti |
| Clean-up | nessuno; residua = suffisso | nessuno; residua = altri job | nessuno; residua = o |
| Scelta greedy (prova) | si spostano da a | si scambia il primo job con uno più breve | si scambiano due scatole, controllando |
| Sottostruttura | |||
| Costo | (ordinamento) | (pesi già ordinati) | |
| Svolgimento | Esercizio - masterizzazione compatta di tracce su CD, scelta greedy e ottimalità (esercitazione greedy, es. 10.1) | Esercizio - shortest-first job scheduling, proprietà SJF e sottostruttura (esercitazione greedy, es. 10.2) | Esercizio - (2,1)-boxing di oggetti, scelta greedy e ottimalità (esercitazione greedy, es. 10.3) |
Che cosa cambia da un problema all'altro
Tracce su CD. Il vincolo che l'ordine delle canzoni sia fisso rende la soluzione una frammentazione della stringa, e riempire il primo CD non può far perdere nulla: ogni altra frammentazione chiude il primo CD prima. La prova sposta le canzoni dal secondo al primo CD e verifica che il secondo non si svuota (altrimenti l'ottimo avrebbe un CD in più del necessario, assurdo). Il caso con canzoni riordinabili è il bin packing, che non è risolubile così.
Shortest-first. Il costo si scrive : i primi job pesano di più, quindi va avanti il più breve. Qui si dimostra qualcosa di più forte della scelta greedy: ogni scheduling ottimo ha come primo job uno di durata minima (non solo "ne esiste uno"). La prova è per assurdo con scambio: se il primo job non è minimo e un job più breve () è in posizione , scambiandoli l'attesa di ciascuno dei job in posizione scende di e le altre non cambiano. Lo stesso criterio, per i processi di un sistema operativo, è in Scheduling della CPU - FCFS, SJF, priorità e round robinLo scheduler della CPU sceglie tra i processi pronti quello a cui dare il core (il dispatcher esegue il cambio, con latenza di dispatch); lo scheduling è non preemptive (il processo tiene la CPU finché termina o si blocca) o preemptive (la CPU gli può essere tolta, con rischio di race condition); i criteri sono utilizzo della CPU e throughput (da massimizzare), tempo di attesa, di turnaround (completamento meno arrivo) e di risposta (da minimizzare); FCFS è semplice ma soffre dell'effetto convoglio (esempio 24, 3, 3: attesa media 17 contro 3); SJF è ottimo per l'attesa media ma richiede la lunghezza del prossimo burst, stimata con la media esponenziale tau(n+1) = alfa t(n) + (1-alfa) tau(n); SRTF è la versione preemptive (esempio con attesa media 6,5 contro 7,75); round robin dà a ciascuno un quanto q e nessuno attende più di (n-1)q; la priorità causa starvation, risolta con l'aging; code multilivello e a feedback (MLFQ) combinano le politiche.Scheduling della CPU - FCFS, SJF, priorità e round robin →.
(2,1)-boxing. Si parte dall'oggetto più difficile da sistemare, il più pesante. La scelta è "azzardata" perché accoppia con il più leggero anche quando ci starebbe un oggetto più pesante; la prova di scelta greedy è un doppio scambio di scatole, dove la disuguaglianza chiave è e , da cui .
Controesempi: provare che una strategia è sbagliata
Per mostrare che una strategia greedy non è ottima basta un'istanza. Per la selezione delle attività sono sbagliate, per esempio, "minima durata" (istanza : sceglie e ottiene 1 attività, l'ottimo ne ha 2) e "minor numero di incompatibilità" (istanza a 11 attività della nota sulla selezione delle attività). Non vale invece il greedy quando le attività hanno pesi da massimizzare: serve la programmazione dinamica (Programmazione dinamica - Fibonacci, memoizzazione e schema del paradigmala programmazione dinamica (DP) evolve il divide and conquer: invece di risolvere di nuovo le stesse sottoistanze, le salva in una tabella. Fibonacci ricorsivo costa F_n - 1 addizioni (esponenziale), quello con tabella n - 1. Tre condizioni: sottostruttura, sottoistanze ripetute, spazio dei sottoproblemi ristretto. Bottom-up o memoizzazione (ricorsione + tabella globale). Per i problemi di ottimizzazione lo schema è: sottostruttura ottima, ricorrenza sui costi, informazione addizionale, calcolo della tabella, ricostruzione.Programmazione dinamica - Fibonacci, memoizzazione e schema del paradigma →).
Domande d'esame
- Quali due proprietà bisogna dimostrare per un algoritmo greedy e che cosa cambia se non c'è clean-up? Traccia: scelta greedy (esiste un ottimo che la contiene, per scambio) e sottostruttura ottima (assurdo con cut-and-paste); senza clean-up la residua è semplicemente ciò che rimane e la sottostruttura segue subito.
- Dimostrare che in ogni scheduling ottimo il primo job è di durata minima. Traccia: formula ; scambio di (primo, non minimo) con più breve in posizione : attese per , invariate per ; il totale scende di .
- Quanti CD servono per con ? Risposta: (greedy: ).
Versione ripasso
- Metodo: (1) scelta greedy, (2) clean-up e residua, (3) algoritmo (ammissibile, complessità), (4) scelta greedy per scambio senza peggiorare il costo, (5) sottostruttura per assurdo con cut-and-paste, (6) induzione sulla taglia. Senza clean-up la sottostruttura è immediata. Teoria: Paradigma greedy - scelta golosa, sottostruttura e selezione delle attivitàIl paradigma greedy compie subito una scelta localmente migliore (scelta greedy), pulisce l'istanza (clean-up) e risolve l'unica sottoistanza residua, con ricorsione di coda eliminabile; il codice è facile, la correttezza no e richiede due proprietà, la scelta greedy (esiste un ottimo che la contiene) e la sottostruttura ottima (cut-and-paste), da cui la correttezza segue per induzione. Caso di studio: la selezione delle attività, con l'algoritmo del primo che finisce, correttezza completa, complessità Theta(n) dopo l'ordinamento e controesempi per le scelte greedy sbagliate.Paradigma greedy - scelta golosa, sottostruttura e selezione delle attività →.
- Tracce su CD: il più lungo prefisso con durata sul primo CD;
sumdche riparte da ; . Prova: si spostano da a ( non si svuota). Esempio , : CD. Svolgimento: Esercizio - masterizzazione compatta di tracce su CD, scelta greedy e ottimalità (esercitazione greedy, es. 10.1). - Shortest-first: ; ordinare per durata non decrescente, . SJF vale per ogni ottimo: scambio con un job più breve riduce il totale di . . Svolgimento: Esercizio - shortest-first job scheduling, proprietà SJF e sottostruttura (esercitazione greedy, es. 10.2); versione sistemi operativi: Scheduling della CPU - FCFS, SJF, priorità e round robinLo scheduler della CPU sceglie tra i processi pronti quello a cui dare il core (il dispatcher esegue il cambio, con latenza di dispatch); lo scheduling è non preemptive (il processo tiene la CPU finché termina o si blocca) o preemptive (la CPU gli può essere tolta, con rischio di race condition); i criteri sono utilizzo della CPU e throughput (da massimizzare), tempo di attesa, di turnaround (completamento meno arrivo) e di risposta (da minimizzare); FCFS è semplice ma soffre dell'effetto convoglio (esempio 24, 3, 3: attesa media 17 contro 3); SJF è ottimo per l'attesa media ma richiede la lunghezza del prossimo burst, stimata con la media esponenziale tau(n+1) = alfa t(n) + (1-alfa) tau(n); SRTF è la versione preemptive (esempio con attesa media 6,5 contro 7,75); round robin dà a ciascuno un quanto q e nessuno attende più di (n-1)q; la priorità causa starvation, risolta con l'aging; code multilivello e a feedback (MLFQ) combinano le politiche.Scheduling della CPU - FCFS, SJF, priorità e round robin →.
- (2,1)-boxing: scatola greedy ( o ) oppure ;
first/last; . Prova: scambio di due scatole con e . Esempio a 8 oggetti: scatole. Svolgimento: Esercizio - (2,1)-boxing di oggetti, scelta greedy e ottimalità (esercitazione greedy, es. 10.3). - Controesempi: per mostrare che un greedy è sbagliato basta un'istanza (attività: minima durata, minimo numero di incompatibilità). Con pesi o riordino libero (bin packing) il greedy non basta.
- Errori tipici: dimostrare solo l'esistenza di un ottimo quando si chiede "ogni ottimo"; non verificare l'ammissibilità dopo lo scambio; dimenticare il caso in cui un CD o una scatola si svuota; non usare l'induzione per chiudere.