Errori corretti usando Hamming (7,4)


19

Il codice Hamming (7,4) risale al 1950. All'epoca Richard Hamming lavorava come matematico presso i Bell Labs. Ogni venerdì Hamming imposta le macchine calcolatrici per eseguire una serie di calcoli e raccoglie i risultati il ​​lunedì successivo. Utilizzando i controlli di parità, queste macchine sono state in grado di rilevare errori durante il calcolo. Frustrato, poiché ha ricevuto messaggi di errore troppo spesso, Hamming ha deciso di migliorare il rilevamento degli errori e ha scoperto i famosi codici Hamming.

Mechanics of the Hamming (7,4)

L'obiettivo dei codici Hamming è quello di creare un insieme di bit di parità che si sovrappongono in modo tale che sia possibile rilevare e correggere un errore a bit singolo (un bit viene capovolto) in un bit di dati o un bit di parità. Solo se si verificano più errori, il codice Hamming non riesce a recuperare i dati originali. Potrebbe non notare affatto un errore o addirittura correggerlo erroneamente. Pertanto in questa sfida ci occuperemo solo di errori a bit singolo.

Come esempio dei codici di Hamming, vedremo il codice di Hamming (7,4). Oltre a 4 bit di dati d1, d2, d3, d4utilizza 3 bit di parità p1, p2, p3, che vengono calcolati utilizzando le seguenti equazioni:

p1 = (d1 + d2 + d4) % 2
p2 = (d1 + d3 + d4) % 2
p3 = (d2 + d3 + d4) % 2

La parola in codice risultante (dati + bit di parità) è nel formato p1 p2 d1 p3 d2 d3 d4.

Il rilevamento di un errore funziona nel modo seguente. Si ricalcola i bit di parità e si controlla se corrispondono ai bit di parità ricevuti. Nella tabella seguente puoi vedere che ogni varietà di un errore a bit singolo produce una corrispondenza diversa dei bit di parità. Pertanto, ogni errore a singolo bit può essere localizzato e corretto.

error in bit | p1 | p2 | d1 | p3 | d2 | d3 | d4 | no error
-------------|---------------------------------------------
p1 matches   | no | yes| no | yes| no | yes| no | yes
p2 matches   | yes| no | no | yes| yes| no | no | yes
p3 matches   | yes| yes| yes| no | no | no | no | yes

Esempio

Lascia che i tuoi dati siano 1011. I bit di parità sono p1 = 1 + 0 + 1 = 0, p2 = 1 + 1 + 1 = 1e p3 = 0 + 1 + 1 = 0. Combina i dati e i bit di parità e otterrai la parola chiave 0110011.

data bits   |   1 011
parity bits | 01 0
--------------------
codeword    | 0110011

Diciamo durante una trasmissione o un calcolo il sesto bit (= terzo bit di dati) capovolge. Tu ricevi la parola 0110001. I presunti dati ricevuti sono 1001. Si calcola nuovamente i bit di parità p1 = 1 + 0 + 1 = 0, p2 = 1 + 0 + 1 = 0, p3 = 0 + 0 + 1 = 1. p1Corrisponde solo ai bit di parità della parola chiave 0110001. Pertanto si è verificato un errore. Guardando la tabella sopra, ci dice che si è verificato l'errore d3e puoi recuperare i dati originali 1011.

Sfida:

Scrivi una funzione o un programma che riceve una parola (7 bit), uno dei bit potrebbe essere errato e recupera i dati originali. Il formato di input (tramite STDIN, argomento della riga di comando, argomento prompt o funzione) può essere una stringa "0110001", un elenco o un array [0, 1, 1, 0, 0, 0, 1]o un numero intero in MSB 0b0110001 = 49. Come descritto sopra, l'ordine dell'input è p1 p2 d1 p3 d2 d3 d4. L'output (tramite valore di ritorno o STDOUT) deve essere dello stesso formato, ma nell'ordine d1 d2 d3 d4. Restituisce / emette solo i 4 bit di dati.

Questo è code-golf. Pertanto vince il codice più breve.

Casi test:

1110000 -> 1000  # no error
1100000 -> 1000  # error at 1st data bit
1111011 -> 1111  # error at 2nd data bit
0110001 -> 1011  # error at 3rd data bit (example)
1011011 -> 1010  # error at 4th data bit
0101001 -> 0001  # error at 1st parity bit
1010000 -> 1000  # error at 2nd parity bit
0100010 -> 0010  # error at 3rd parity bit


1
C'è un motivo particolare per cui viene dato l'ultimo bit di parità dopo il primo bit di dati?
xnor

2
@xnor Matematicamente non fa alcuna differenza, in quale posizione si trovano i bit di parità. Storicamente sono posti sulle posizioni di poteri di due. Ad esempio, Hamming (15,11) ha i bit di parità nelle posizioni 1, 2, 4 e 8.
Jakube,

4
@xnor Se prendi la [is_p3_wrong][is_p2_wrong][is_p1_wrong]base due, indica la posizione del bit errato nella parola. (Basato sulla tabella nella domanda.) Questo probabilmente sarà utile per alcuni algoritmi.
randomra,

Molto bello :) Quando scrivi "Scrivi una funzione o un programma, che riceve una parola (7 bit), uno di essi potrebbe essere sbagliato, [...]" Penso che intendi che uno dei bit potrebbe essere sbagliato ma tu in realtà dire che una delle parole potrebbe essere.

@Lembik Certo, lo ha chiarito.
Jakube,

Risposte:


6

Ottava, 70 66 55 byte

Questa funzione Fimposta la matrice di decodifica H, trova l'errore e corregge la posizione dell'errore (se presente). Quindi restituisce i bit di dati corretti. L'input è un vettore di riga standard.

@Jakube mi ha suggerito di usare Octave invece di Matlab, dove puoi usare gli indici sulle espressioni, il che rende il tutto ancora più breve di 11 byte:

F=@(c)xor(c,1:7==bi2de(mod(c*de2bi(1:7,3),2)))([3,5:7])

Di seguito è la soluzione più breve in Matlab , poiché non è possibile utilizzare direttamente l'indicizzazione sulle espressioni. (Funziona anche in Octave, ovviamente.) È stato in grado di sostituire l'addizione / mod2 con xor:

f=@(c)c([3,5:7]);F=@(c)f(xor(c,1:7==bi2de(mod(c*de2bi(1:7,3),2))))

Vecchio:

f=@(c)c([3,5:7]);F=@(c)f(mod(c+(1:7==bi2de(mod(c*de2bi(1:7,3),2))),2))

Grazie, ma questo non funziona, sfortunatamente puoi accedere solo alle variabili in questo modo ...
flawr

1
Non ho installato Matlab, l'ho usato solo http://octave-online.net/dove funziona. Forse cambi la lingua?
Jakube,

Oh, stavo già sospettando che l'ottava potesse farlo, ma ovviamente cambierò la lingua, grazie mille!
Flawr,

14

Piet 50x11 = 550

inserisci qui la descrizione dell'immagine

la dimensione del codice è 15. Non troppo preoccupato per la dimensione, ma ha superato tutti i test.


4
Preferisco questo dato il contesto del problema.

1
@Optimizer "dimensione del codice" è essenzialmente il fattore di ingrandimento di un programma piet. Qui, ogni pixel logico (o codel) è stato espanso in un blocco 15x15 per facilitare la visibilità. Questo è ciò che intendo, non "dimensione del codice"
captncraig,

ah ..... mio male.
Ottimizzatore,

8

Python, 79

f=lambda x,n=0,e=3:e&~-e and f(x,n+1,(n&8)*14^(n&4)*19^(n&2)*21^n%2*105^x)or~-n

Prendi input e output come numeri con il bit meno significativo sulla destra.

Invece di tentare il recupero degli errori, proviamo semplicemente a codificare ogni possibile messaggio nda 0 a 15 fino a quando non otteniamo una codifica che è un po 'distante da ciò che viene dato. La ricorsione continua ad aumentare nfino a quando non trova quella che funziona e la restituisce. Sebbene non vi sia una terminazione esplicita, deve terminare entro 16 loop.

L'espressione (n&8)*14^(n&4)*19^(n&2)*21^n%2*105implementa la matrice di Hamming bit a bit.

Per verificare la presenza di un singolo errore, otteniamo il messaggio specificato con un messaggio calcolato da ottenere ee controlliamo se è una potenza di due (o 0) con il classico bit-trick e&~-e==0. Ma in realtà non possiamo assegnare alla variabile eall'interno di una lambda e ci riferiamo due volte in questa espressione, quindi facciamo un hack di passarla come argomento opzionale al prossimo passaggio ricorsivo.


7

JavaScript (ES6), 92 87 81

Funzione che ottiene e restituisce un numero intero in MSB.
L'implementazione è semplice dopo il commento di @randomra:

  • calc p3wrong | p2wrong | p1wrong (riga 2,3,4)
  • usalo come maschera di bit per capovolgere il bit errato (riga 1),
  • quindi restituisce solo i bit di dati (ultima riga)
F=w=>(w^=128>>(
  (w^w*2^w*4^w/2)&4|
  (w/8^w^w*2^w/16)&2|
  (w/16^w/4^w^w/64)&1
))&7|w/2&8

Test nella console Frefox / FireBug

;[0b1110000,0b1100000,0b1111011,0b0110001,
0b1011011,0b0101001,0b1010000,0b0100010]
.map(x=>x.toString(2)+'->'+F(x).toString(2))

Produzione

["1110000->1000", "1100000->1000", "1111011->1111", "110001->1011", "1011011->1010", "101001->1", "1010000->1000", "100010->10"]

1
Mi piace molto la tua soluzione operativa bit a bit compatta =)
flawr

4

Python 2, 71

f=lambda i,b=3:i&7|i/2&8if chr(i)in'\0%*3<CLUZfip'else f(i^b/2,b*2)

Diversi caratteri sono ASCII non stampabili, quindi ecco una versione con escape:

f=lambda i,b=3:i&7|i/2&8if chr(i)in'\0\x0f\x16\x19%*3<CLUZfip\x7f'else f(i^b/2,b*2)

L'input e l'output della funzione vengono eseguiti come numeri interi.

Sto sfruttando il fatto che il numero di messaggi validi è solo 16 e li codifico tutti. Quindi provo a lanciare bit diversi fino a quando non ne ottengo uno.


3

Haskell, 152 byte

a(p,q,d,r,e,f,g)=b$(d+e)#p+2*(d+f)#q+4*(e+f)#r where b 3=(1-d,e,f,g);b 5=(d,1-e,f,g);b 6=(d,e,1-f,g);b 7=(d,e,f,g-1);b _=(d,e,f,g);x#y=abs$(x+g)`mod`2-y

Utilizzo: a (1,1,1,1,0,1,1)quali output(1,1,1,1)

Soluzione semplice: se p<x>non corrisponde, impostare il bit <x>in un numero. Se questo numero è 3, 5, 6o 7, capovolgere il corrispondente d<y>.


Puoi aggiungere altre istruzioni su come chiamare il tuo codice (ad esempio utilizzando un compilatore online come ideone.com )? Ricevo sempre degli strani errori (molto probabilmente per colpa mia).
Jakube,

@Jakube: Salvare il codice in un file, dicono hamming.hse caricarlo nella ghci Haskell REPL: ghci hamming.hs. Chiamare la funzione acome descritto sopra. L'unico interprete di haskell online che conosco ( tryhaskell.org ) richiede altro codice:let a(p,q, ... 2-y in a (1,1,1,1,0,1,1)
nimi

3

Codice macchina IA-32, 36 byte

hexdump:

33 c0 40 91 a8 55 7a 02 d0 e1 a8 66 7a 03 c0 e1
02 a8 78 7a 03 c1 e1 04 d0 e9 32 c1 24 74 04 04
c0 e8 03 c3

Codice C equivalente:

unsigned parity(unsigned x)
{
    if (x == 0)
        return 0;
    else
        return x & 1 ^ parity(x >> 1);
}

unsigned fix(unsigned x)
{
    unsigned e1, e2, e3, err_pos, data;
    e1 = parity(x & 0x55);
    e2 = parity(x & 0x66);
    e3 = parity(x & 0x78);
    err_pos = e1 + e2 * 2 + e3 * 4;
    x ^= 1 << err_pos >> 1;
    data = x;
    data &= 0x74;
    data += 4;
    data >>= 3;
    return data;
}

La CPU x86 calcola automaticamente la parità di ciascun risultato intermedio. Ha un'istruzione dedicata jpche salta o non salta a seconda della parità.

Non è stato specificato esplicitamente nella sfida, ma la proprietà conveniente dei codici di hamming è che è possibile interpretare i bit di parità come un numero binario, e questo numero indica quale bit è stato rovinato durante la trasmissione. In realtà, questo numero è basato su 1, con 0 significa che non ci sono stati errori di trasmissione. Questo viene implementato spostando 1 a sinistra err_pose poi a destra 1.

Dopo aver corretto l'errore di trasmissione, il codice dispone i bit di dati nell'ordine necessario. Il codice è ottimizzato per le dimensioni e all'inizio potrebbe non essere chiaro come funzioni. Per spiegarlo, io indichiamo con a, b, c, di bit di dati, e P, Qe Ri bit di parità. Poi:

    data = x;     // d  c  b  R  a  Q  P
    data &= 0x74; // d  c  b  0  a  0  0
    data += 4;    // d  c  b  a ~a  0  0
    data >>= 3;   // d  c  b  a

Fonte dell'assembly (fastcall convenzione, con input in ecxe output in eax):

    xor eax, eax;
    inc eax;
    xchg eax, ecx;

    test al, 0x55;
    jp skip1;
    shl cl, 1;

skip1:
    test al, 0x66;
    jp skip2;
    shl cl, 2;

skip2:
    test al, 0x78;
    jp skip3;
    shl ecx, 4;

skip3:
    shr cl, 1;
    xor al, cl;

    and al, 0x74;
    add al, 4;
    shr al, 3;

    ret;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.