Ridurre al minimo l'overhead di compressione in un semplice algoritmo di compressione

4

Nota: questa domanda è stata riscritta per semplificare e generalizzare il problema. L'originale è disponibile sotto.

Supponiamo di aver creato un semplice schema di compressione per elenchi di numeri a 2 cifre. Ha 2 modalità:

  • Modo 0: i numeri sono scritti così come sono, non compressi.
  • Modalità 1: per ogni numero viene scritta solo la cifra, ma l'esecuzione dei numeri deve avere la stessa cifra delle decine. Ciò fornisce una compressione 2: 1 data una lista infinita di numeri con la stessa cifra delle decine.

La stringa di output compresso deve contenere solo le cifre 0-9, ad eccezione dei seguenti valori magici di 3 caratteri che devono essere utilizzati per cambiare la modalità di compressione:

  • *** : passa alla modalità 0
  • *x* : passa alla modalità 1, dove x è la cifra delle decine comune per i numeri che seguono. Se la cifra delle decine cambia, l'interruttore della modalità 1 deve essere scritto di nuovo, con una cifra delle decine comune diversa.

Il compressore può passare liberamente tra le due modalità di compressione. Quindi, in due modi che l'elenco di numeri 11 12 13 14 21 22 23 24 può essere codificato sono:

***1112131421222324 (only mode 0, each number written out as-is)
*1*1234*2*1234      (only mode 1, only ones digits are written after the mode switches, 
                     but mode 1 needed to be started twice, for each diff. tens digit)

Nell'esempio sopra, usando la modalità 1 hai salvato 5 caratteri, ma non è sempre così. Codifica dell'elenco 15 26 37 48 :

***15263748
*1*5*2*6*3*7*4*8

è più corto in modalità 0. E ovviamente, nei testi più complessi, le modalità devono essere mixate correttamente per fornire il risultato più breve. Ad esempio, codifica l'elenco 11 12 21 22 23 24 25 26 18 39 :

***11122122232425261839 (only mode 0)
*1*12*2*123456*1*8*3*9  (only mode 1)
*1*12*2*123456***1839   (mode 1 then mode 0)

la terza codifica fornisce il risultato più breve, mescolando correttamente le modalità di codifica.

Data questa specifica, un codificatore che cerca esaustivamente di mixare le 2 modalità mentre codifica una lista di numeri darà il risultato compresso più breve possibile. Ovviamente, un tale encoder impiega un tempo ridicolmente lungo - O (n ^ n). Cercando di pensare a un codificatore più efficiente, sono rimasto perplesso.

Quindi la mia domanda - è possibile, date le suddette specifiche, scrivere un codificatore che avrebbe prestazioni migliori di O (n ^ n) - che potrebbe prendere decisioni nel mixare le 2 modalità di compressione senza provare esaustivamente ogni singola combinazione? O l'algoritmo esaustivo è l'unico modo per ottenere la stringa compressa più corta possibile?

Grazie in anticipo a tutti coloro che condividono qualsiasi opinione su questo. Nota che il mio obiettivo è quello di capire il problema generale di compressione illustrato nella mia domanda, piuttosto che trovare / creare un efficiente compressore di liste di numeri.

=============================================================================

Below is my question as it was phrased originally, in terms of text encoding

=============================================================================

Ho ideato un semplice schema di compressione del testo UTF-16 con 2 modalità:

  • Modo 0: le coppie di byte UTF-16 vengono scritte così come sono, non compresse.
  • Modalità 1: per ogni carattere viene scritto solo il byte meno significativo, ma l'esecuzione dei caratteri deve avere lo stesso byte più significativo (essere dello stesso blocco unicode). Ciò fornisce una compressione 2: 1 data una stringa infinita di caratteri dallo stesso blocco unicode.

Supponiamo che occorra 3 byte per cambiare la modalità. Anche la commutazione del byte più significativo (blocco Unicode) sulla modalità 1 richiede 3 byte.

Di seguito sono riportati alcuni esempi di come il testo UTF-16 può essere codificato in base a questa specifica. Negli esempi,

"a" = any character from unicode block 1
"b" = any character from unicode block 2
"===" = 3-byte value indicating mode 0 is now active
"---" = 3-byte value indicating mode 1 is now active

Quindi il testo "aaaabbbb" (4 caratteri diversi dal blocco unicode1 e 4 caratteri diff. dal blocco unicode 2) può essere codificato come

===aaaaaaaabbbbbbbb  (each letter takes up 2 bytes)  -or-
---aaaa---bbbb       (each letter takes up 1 byte, but mode 1 needed to be started twice, because b is from a different block than a)

Nell'esempio precedente, l'utilizzo della modalità 1 ha salvato 5 byte, ma non è sempre il caso. Codifica del testo "abab",

===aabbaabb
---a---b---a---b

è più corto in modalità 0. E ovviamente, nei testi più complessi, le modalità devono essere mixate correttamente per fornire il risultato più breve. Ad esempio, codifica il testo "abbbbbbab",

===aabbbbbbbbbbbbaabb
---a---bbbbbb---a---b
---a---bbbbbb===aabb

la terza codifica fornisce il risultato più breve, mescolando correttamente le modalità di codifica.

Ho scritto un codificatore, data questa specifica, che cerca esaustivamente di mixare le 2 modalità mentre codifica una stringa e produce il risultato più breve. Ovviamente, questo richiede un tempo ridicolmente lungo - O (n ^ n). Cercando di scrivere un codificatore più efficiente, sono rimasto perplesso.

Quindi la mia domanda - è possibile, date le suddette specifiche, scrivere un codificatore che avrebbe prestazioni migliori di O (n ^ n) - che potrebbe prendere decisioni nel mixare le 2 modalità di compressione senza provare esaustivamente ogni singola combinazione? O l'algoritmo esaustivo è l'unico modo per ottenere la stringa compressa più corta possibile?

Grazie in anticipo a tutti coloro che condividono qualsiasi opinione su questo. Tieni presente che il mio obiettivo è capire il problema generale di compressione illustrato nella mia domanda, piuttosto che trovare / creare un codificatore di testo efficiente.

    
posta Duke Nukem 26.06.2015 - 04:32
fonte

1 risposta

4

Si consideri:

  • La modalità 1 è più efficiente quando hai una corsa della stessa cifra delle decine.
  • Il modo 1 salva 1 carattere per ciascuna stessa cifra di decine, tranne il primo
  • Costa 2 caratteri per passare alla modalità 1.
  • Pertanto, la modalità 1 diventa vantaggiosa solo dopo 4 caratteri 10s simili (costi 2, salvati 3)

Ad esempio, considera se stai correndo in modalità 0. Un passaggio alla modalità 1 si interrompe anche dopo 3 decine di caratteri:

818283
*8*123

e diventa vantaggioso dopo 4 decine di caratteri

81828384
*8*1234

Tuttavia,

  • Costa 3 caratteri per tornare alla modalità 0

Pertanto, vale la pena passare alla modalità 1, se:

Hai 7 o più caratteri di decine simili (costo 2 + 3, risparmi 6), ad esempio

102010208182838485868710201020
10201020*8*1234567***10201020

O hai a disposizione decine di caratteri adiacenti che ti fanno risparmiare più del costo per tornare alla modalità 0 (3). Di nuovo, le corse di 3 non ti fanno nulla, le corse di 4 ti fanno guadagnare 1 ecc. Nell'esempio qui sotto ci sono 4 serie di 4 10s adiacenti, quindi salviamo 4 caratteri. Uno più dei tre dobbiamo tornare indietro.

102010206162636471727374818283849192939410201020
10201020*6*1234*7*1234*8*1234*9*1234***10201020

Ora le regole precedenti presuppongono un flusso infinito. In realtà puoi guadagnare all'inizio dello stream scegliendo qualsiasi codifica che desideri per la prima sequenza, e alla fine dello stream non dovrai tornare alla modalità 0 se hai 10 secondi duplicati fino alla fine. Questo è il motivo per cui i tuoi esempi sembrano così arbitrari. Sono così brevi che le ottimizzazioni iniziali e finali prevalgono sulle regole principali.

    
risposta data 27.06.2015 - 01:10
fonte

Leggi altre domande sui tag