Vai al contenuto

31.10 KP: ammissibilità e penalità

  • La rappresentazione del KP con un vettore binario \(x\) descrive anche oggetti non ammissibili, il cui peso supera la capacità. Ci sono due modi di trattarli:

    1. restare ammissibili: l'intorno contiene solo i vicini ammissibili, come fatto finora;

    2. penalizzare: i vettori non ammissibili sono ammessi, e la ricerca massimizza una funzione che sottrae dal profitto una penalità proporzionale al peso in eccesso.

  • Restare ammissibili può rendere la ricerca miope. Nel capitolo «Algoritmi euristici: definizioni», \(x=(1,0,1,0)\) è un ottimo locale per flip: per raggiungere la soluzione ottima \((1,1,0,0)\) con i flip occorre aggiungere l'oggetto \(2\) e togliere l'oggetto \(3\), e il vettore intermedio è o \((1,1,1,0)\), non ammissibile, o \((1,0,0,0)\), di profitto \(10<16\). L'intorno swap risolve questo caso eseguendo i due flip insieme; le penalità lo risolvono lasciando che la ricerca passi attraverso il vettore non ammissibile.

  • Con le penalità, lo spazio di ricerca è l'intero insieme \(\{0,1\}^n\), e la funzione da massimizzare è

\[ g_\alpha(x) \;=\; \sum_{j\in\mathscr{I}} p_j x_j \;-\; \alpha\cdot\max\Big\{0,\ \sum_{j\in\mathscr{I}} w_jx_j-c\Big\}, \]

dove \(\alpha>0\) è la penalità per ogni unità di peso in eccesso. Per un \(x\) ammissibile, \(g_\alpha(x)\) è il profitto di \(x\).

31.10.1 Restare ammissibili

La ricerca locale flip+swap per il KP esamina i flip e poi gli swap della soluzione corrente, scarta quelli che superano la capacità, ne applica uno migliorante scelto con la regola first improvement o best improvement, e si ferma quando nessun vicino ammissibile ha un profitto maggiore.

Algoritmo: Passo flip+swap per il KP

Input: \(n\) oggetti, profitti \(p[1..n]\), pesi \(w[1..n]\), capacità \(c\), soluzione ammissibile \(x[1..n]\), regola
Output: true se a \(x\) è stata applicata una mossa migliorante, false altrimenti
1Function KPFlipSwapStep(\(n, p, w, c, x, \textit{rule}\))
2\(W := \sum_{j=1}^n w[j]\,x[j]\) \(\bar\Delta := 0\); \((\bar\jmath,\bar k) := (0,0)\) ▹ peso della soluzione corrente miglior mossa trovata finora (\(\bar k=0\): flip)
3for \(j := 1\) to \(n\) do ▹ flip dell'oggetto \(j\)
4\(\Delta p := (1-2x[j])\,p[j]\); \(\Delta w := (1-2x[j])\,w[j]\) ▹ togliere, o aggiungere, l'oggetto \(j\)
5if \(W+\Delta w \le c\) and \(\Delta p > \bar\Delta\) then
6\(\bar\Delta \leftarrow \Delta p\); \((\bar\jmath,\bar k) \leftarrow (j,0)\)
7if \(\textit{rule}=\textit{first}\) then
8uscire da tutti i cicli
9end
10end
11end
12for \(j := 1\) to \(n\) con \(x[j]=1\) do ▹ swap: \(j\) fuori, \(k\) dentro
13for \(k := 1\) to \(n\) con \(x[k]=0\) do
14\(\Delta p := p[k]-p[j]\); \(\Delta w := w[k]-w[j]\)
15if \(W+\Delta w \le c\) and \(\Delta p > \bar\Delta\) then
16\(\bar\Delta \leftarrow \Delta p\); \((\bar\jmath,\bar k) \leftarrow (j,k)\)
17if \(\textit{rule}=\textit{first}\) then
18uscire da tutti i cicli
19end
20end
21end
22end
23if \(\bar\jmath = 0\) then return false ▹ nessuna mossa migliorante: ottimo locale
24\(x[\bar\jmath] \leftarrow 1-x[\bar\jmath]\) ▹ flip, oppure togliere l'oggetto che esce
25if \(\bar k \ne 0\) then
26\(x[\bar k] \leftarrow 1\) ▹ aggiungere l'oggetto che entra
27end
28return true

Esegui in Colab:PythonC++
  • Con la regola first improvement, se si trova un flip migliorante gli swap non vengono esaminati. Solo i flip che aggiungono un oggetto possono migliorare il profitto; i flip che tolgono un oggetto restano nell'intorno per uniformità. Un'iterazione costa tempo \(O(n^2)\), a causa degli swap.

31.10.2 Penalizzare il peso in eccesso

La ricerca locale penalty flip per il KP esamina i flip del vettore corrente, ammissibile o no, li valuta con \(g_\alpha\), ne applica uno migliorante scelto con la regola first improvement o best improvement, e si ferma quando nessun flip aumenta \(g_\alpha\).

Algoritmo: Passo penalty flip per il KP

Input: \(n\) oggetti, profitti \(p[1..n]\), pesi \(w[1..n]\), capacità \(c\), penalità \(\alpha\), vettore \(x[1..n]\), regola
Output: true se a \(x\) è stato applicato un flip migliorante, false altrimenti
1Function KPPenaltyFlipStep(\(n, p, w, c, \alpha, x, \textit{rule}\))
2\(P := \sum_{j=1}^n p[j]\,x[j]\); \(W := \sum_{j=1}^n w[j]\,x[j]\) \(g := P - \alpha \max\{0, W-c\}\) \(\bar\Delta := 0\); \(\bar\jmath := 0\) ▹ profitto e peso di \(x\) valore di \(x\) miglior flip trovato finora
3for \(j := 1\) to \(n\) do
4\(P' := P+(1-2x[j])\,p[j]\); \(W' := W+(1-2x[j])\,w[j]\) \(\Delta := P' - \alpha \max\{0, W'-c\} - g\) ▹ flip dell'oggetto \(j\) variazione di \(g_\alpha\)
5if \(\Delta > \bar\Delta\) then
6\(\bar\Delta \leftarrow \Delta\); \(\bar\jmath \leftarrow j\) ▹ flip migliorante
7if \(\textit{rule}=\textit{first}\) then
8uscire dal ciclo
9end
10end
11end
12if \(\bar\jmath = 0\) then return false ▹ nessun flip migliorante: ottimo locale
13\(x[\bar\jmath] \leftarrow 1-x[\bar\jmath]\) ▹ applicare il flip
14return true

Esegui in Colab:PythonC++
  • L'ottimo locale può essere non ammissibile. La ricerca deve quindi ricordare la migliore soluzione ammissibile visitata, che è la soluzione che restituisce.

Esempio 31.8: Penalità sull'istanza di riferimento del KP

Partiamo dalla soluzione di \(GR\), \(x=(1,0,1,0)\), di peso \(8\) e profitto \(16\), che è un ottimo locale per l'intorno flip ristretto alle soluzioni ammissibili. I valori \(g_\alpha\) dei suoi quattro flip sono

flip vettore peso eccesso \(\alpha=1\) \(\alpha=2\) \(\alpha=\frac94\) \(\alpha=3\)
\(1\) \((0,0,1,0)\) \(3\) \(0\) \(6\) \(6\) \(6\) \(6\)
\(2\) \((1,1,1,0)\) \(12\) \(3\) \(20\) \(17\) \(\frac{65}{4}\) \(14\)
\(3\) \((1,0,0,0)\) \(5\) \(0\) \(10\) \(10\) \(10\) \(10\)
\(4\) \((1,0,1,1)\) \(11\) \(2\) \(18\) \(16\) \(\frac{31}{2}\) \(14\)

Le due regole eseguono le stesse mosse:

  • \(\alpha=1\): la ricerca aggiunge l'oggetto \(2\) (\(g_1=20\)), poi l'oggetto \(4\) (\(g_1=27-6=21\)), e si ferma in \((1,1,1,1)\), di peso \(15\): ogni suo flip toglie un oggetto e dà \(16\), \(18\), \(18\) o \(20\). La penalità è troppo piccola: l'ottimo locale non è ammissibile, e la migliore soluzione ammissibile visitata è quella di partenza, di profitto \(16\).

  • \(\alpha=2\): la ricerca aggiunge l'oggetto \(2\) (\(g_2=17>16\)) e si ferma in \((1,1,1,0)\), non ammissibile: togliere l'oggetto \(3\) dà \((1,1,0,0)\) con \(g_2=17\), non strettamente migliore.

  • \(\alpha=\frac94\): la ricerca aggiunge l'oggetto \(2\) (\(g=\frac{65}{4}=16.25>16\)) e poi toglie l'oggetto \(3\), raggiungendo \((1,1,0,0)\), di profitto \(17\): la soluzione ottima, attraverso un vettore non ammissibile (si veda la figura).

  • \(\alpha=3\): nessun flip migliora, e la ricerca si ferma subito in \((1,0,1,0)\), come la ricerca ammissibile.

Figura 8

Proposizione 31.7

Siano i dati interi e sia \(\alpha>\max_{j\in\mathscr{I}} p_j\). Allora:

  1. da un vettore ammissibile, nessun flip che produce un vettore non ammissibile aumenta \(g_\alpha\);

  2. ogni vettore non ammissibile ha un flip che aumenta \(g_\alpha\).

Dimostrazione

(1) Se aggiungere l'oggetto \(k\) a un vettore ammissibile produce un eccesso \(e\ge1\), allora \(g_\alpha\) varia di \(p_k-\alpha e\le p_k-\alpha<0\). (2) Sia \(x\) non ammissibile, con eccesso \(e\ge 1\), e sia \(j\) un oggetto selezionato. Togliere \(j\) diminuisce l'eccesso di \(\min\{w_j,e\}\ge 1\), quindi \(g_\alpha\) varia di \(-p_j+\alpha\min\{w_j,e\}\ge -p_j+\alpha>0\). □

  • Con una penalità grande gli ottimi locali sono ammissibili, ma la ricerca non lascia mai la regione ammissibile; con una penalità piccola attraversa la regione non ammissibile, ma può fermarsi lì. I valori utili dipendono dall'istanza (qui \(\frac94\) funziona, \(1\), \(2\) e \(3\) no), quindi in pratica \(\alpha\) si regola durante la ricerca: si aumenta finché la ricerca resta fra vettori non ammissibili, si diminuisce finché resta fra vettori ammissibili.

Avanti: 31.11 Variable neighbourhood descent