lrq3000 / unireedsolomon

Universal errors-and-erasures Reed Solomon codec (error correcting code) in pure Python with extensive documentation
MIT License
26 stars 18 forks source link

GF2int is a a global singleton and does not allow multiple RSCoder instances with different field generator polynomials. #6

Open jason-s opened 6 years ago

jason-s commented 6 years ago

GF2int is a a global singleton and does not allow multiple RSCoder instances with different field generator polynomials.

import unireedsolomon as rs

def codeword_symbols(msg):
    return [ord(c) for c in msg]

def find_generator(rscoder):
    """ Returns the generator polynomial of an RSCoder class """
    msg = [0]*(rscoder.k - 1) + [1]
    degree = rscoder.n - rscoder.k
    codeword = rscoder.encode(msg)
    # look at the trailing elements of the codeword
    return codeword_symbols(codeword[(-degree-1):])

rs4 = rs.RSCoder(15,11,generator=2,prim=0x13,fcr=0,c_exp=4)
print "g4(x) = %s" % find_generator(rs4)
encmsg15 = codeword_symbols(rs4.encode([1,2,3,4,5,6,7,8,9,10,11]))
print "RS(15,11) encoded example message from BBC WHP031:\n", encmsg15

rs8 = rs.RSCoder(255,239,generator=2,prim=0x11d,fcr=0,c_exp=8)
print "g8(x) = %s" % find_generator(rs8)
encmsg15 = codeword_symbols(rs4.encode([1,2,3,4,5,6,7,8,9,10,11]))
print "RS(15,11) encoded example message from BBC WHP031:\n", encmsg15
rs4 = rs.RSCoder(15,11,generator=2,prim=0x13,fcr=0,c_exp=4)
encmsg15 = codeword_symbols(rs4.encode([1,2,3,4,5,6,7,8,9,10,11]))
print "RS(15,11) encoded example message from BBC WHP031:\n", encmsg15

results in:

g4(x) = [1, 15, 3, 1, 12]
RS(15,11) encoded example message from BBC WHP031:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 3, 3, 12, 12]
g8(x) = [1, 59, 13, 104, 189, 68, 209, 30, 8, 163, 65, 41, 229, 98, 50, 36, 59]
RS(15,11) encoded example message from BBC WHP031:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 187, 6, 230, 91]
RS(15,11) encoded example message from BBC WHP031:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 3, 3, 12, 12]
jason-s commented 6 years ago

Shorter example, without my helper functions:

import unireedsolomon as rs
rs4 = rs.RSCoder(15,11,generator=2,prim=0x13,fcr=0,c_exp=4)
print repr(rs4.encode('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b'))
rs8 = rs.RSCoder(255,239,generator=2,prim=0x11d,fcr=0,c_exp=8)
print repr(rs4.encode('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b'))

which prints

'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x03\x03\x0c\x0c'
'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xbb\x06\xe6['

The creation of rs8 somehow causes rs4 to behave incorrectly.

jason-s commented 6 years ago

Oh, I see the problem, they're using a singleton lookup table:

        # Initialize the look-up tables for logarithm and anti-log
        init_lut(generator=generator, prim=prim, c_exp=self.gf2_c_exp)

Bad.

lrq3000 commented 6 years ago

@jason-s Yes this is a leftover of the original implementation that I did not make. I can't remember exactly why I did not factor this directly into the RSCoder class, but I think I tried and it led to duplicated code and a performance drop...

Anyway, this library is mostly for educational usage, as I think the object-oriented approach is more intuitive to tackle error correction codes. If you want a library for practical use, with good enough (for a pure python) performances and the possibility to use multiple codecs at the same time, you can checkout this library that share the exact same features as unireedsolomon:

https://github.com/lrq3000/reedsolomon