reedsolo

repository·master·Indexed 19 days ago

https://github.com/tomerfiliba-org/reedsolomon

A Pythonic Reed-Solomon error correction codec designed to protect data from errors and bitrot. It provides a pure-Python implementation for compatibility and an optional, speed-optimized Cython/C extension for performance. The library includes the high-level RSCodec class for encoding and decoding, as well as low-level math functions for advanced control over Galois Field parameters and generator polynomials.

Tokens
4.8K
Snippets
14
Records
18
Agent score
15%

What's inside reedsolo

  1. Understanding Galois Field limits and chunking

    master

    The algorithm's capacity is constrained by the Galois Field exponent (c_exp). The maximum message length (including ECC symbols) and the maximum value of any single symbol is (2^c_exp) - 1.

    • Default (GF(2^8)): Symbols are limited to values between 0 and 255. This is ideal for binary streams. The maximum total length (message + ECC) is 255.
    • Chunking: If your message exceeds the length limit of the chosen field, the RSCodec class automatically applies chunking by splitting the message into smaller chunks and encoding/decoding them separately. This is transparent to the user.
    • Performance Note: Using higher fields (larger c_exp) will slow down the algorithm because it cannot use the optimized bytearray structure and must use array.array('i', ...) instead. Additionally, Reed-Solomon complexity is quadratic, so longer messages increase processing time quadratically.
  2. How Reed-Solomon error correction works

    master

    The Reed-Solomon algorithm corrects errors and erasures based on the number of ECC (Error Correction Code) symbols, defined as nsym = n - k.

    It follows the Singleton Bound, which is the maximum theoretical capacity for error correction. The algorithm can correct a combination of errors (e) and erasures (v) as long as:

    2*e + v <= nsym

    This means you can:

    • Correct exactly floor(nsym/2) errors.
    • Correct up to nsym erasures (where the position of the error is known).
    • Correct a combination of both.

    Note on Universality: This codec is universal and can decode messages from other RS encoders if the correct parameters are provided. If an external encoder uses specific internal constants (like fcr), you can supply them to reedsolo to ensure compatibility.

  3. Install reedsolo via pip

    master

    You can install the reedsolo package using pip. Depending on your requirements, choose one of the following versions:

    • Latest stable release (Python >= 3.7): Use the standard upgrade command.
    • Latest development release: Use the --pre flag to include pre-release versions.
    • Cutting-edge code: Install directly from the GitHub repository (unstable, not for production).
    • Legacy versions: For Python 2.7 or Python <= 3.6, install version 1.7.0.
    # Latest stable release
    pip install --upgrade reedsolo
    
    # Latest development release
    pip install --upgrade reedsolo --pre
    
    # Cutting-edge code (unstable)
    pip install --upgrade git+https://github.com/tomerfiliba-org/reedsolomon
    
    # Legacy (Python 2.7 or Python <= 3.6)
    pip install --upgrade reedsolo==1.7.0
  4. How to use the high-performance Cython implementation

    master

    For significantly faster encoding (up to 14.3 MB/s on specific hardware), you can use the Cython extension creedsolo.

    Requirements:

    • pip install cython==3.0.0b2
    • A C++ compiler (e.g., Microsoft Visual C++ 14.x for Windows).

    Setup Steps:

    1. Navigate to the directory containing creedsolo.pyx.
    2. Run the following command to compile the extension in-place:
      python setup.py build_ext --inplace --cythonize

    Usage Differences:

    • Import: Use from creedsolo import RSCodec instead of from reedsolo import RSCodec.
    • Data Type: You must feed bytearray() objects to the RSCodec object. The Cython implementation is optimized specifically for bytearray and will not work with other types.
    • Limitation: The Cython implementation only supports Galois Fields up to 8 (values up to 255) because it relies on bytearray.
    # After compiling creedsolo.pyx
    from creedsolo import RSCodec
    
    codec = RSCodec(nsym=10)
    # Use bytearray exclusively for speed
    data = bytearray("Hello World", "UTF-8")
    encoded = codec.encode(data)
  5. Use the high-level RSCodec class for encoding and decoding

    master

    The RSCodec class provides a high-level API for Reed-Solomon error correction. You can initialize it with the number of error correction symbols (ECC) you want to use.

    Encoding

    RSCodec.encode() accepts lists of numbers, bytearray objects, or byte strings.

    • Recommendation: Use bytearray for performance and predictable sizing, especially if you need to store or send the data in a fixed-size field.
    • Transparent Chunking: The codec automatically handles strings longer than the Galois field size using transparent chunking.

    Decoding (Repairing)

    RSCodec.decode() repairs corrupted data.

    • If the number of errors exceeds the codec's capacity, it raises a reedsolo.ReedSolomonError.
    • You can provide erase_pos (a list of indices) to specify known error locations. Providing erasures allows the codec to correct up to twice as many errors compared to unknown error locations.

    Return Values of decode()

    For versions 1.0 and later, decode() returns a tuple of three values:

    1. decoded_msg: The corrected message.
    2. decoded_msgecc: The corrected message combined with the corrected ECC symbols.
    3. errata_pos: A bytearray containing the positions of errors/erasures. Convert this to a list to get integer indices.
    from reedsolo import RSCodec, ReedSolomonError
    
    # Initialize with 10 ECC symbols
    rsc = RSCodec(10)
    
    # Encoding
    encoded = rsc.encode(b'hello world')
    
    # Decoding
    try:
        decoded_msg, decoded_msgecc, errata_pos = rsc.decode(encoded)
        print(list(errata_pos))  # Get error positions as integer indices
    except ReedSolomonError:
        print("Too many errors to correct")
  6. Build reedsolo locally using build tool

    master

    For local development or manual builds, you can use the build tool. You can either perform full cythonization (converting *.pyx to *.c to *.pyd) or skip cythonization if you only want to compile already transpiled C extensions.

    Note: When using the build command, use the singular --config-setting (unlike pip which accepts the plural form).

    pip install build
    
    # Full cythonization (from *.pyx to *.c to *.pyd)
    python -sBm build --config-setting="--build-option=--cythonize"
    
    # Skip cythonization (compile already transpiled c extension from *.c to *.pyd)
    python -sBm build --config-setting="--build-option=--native-compile"
  7. Migrate from reedsolo v1.x to v2.x

    master

    Upgrading from v1.x to v2.x involves several changes to build requirements, packaging, and API usage:

    Build Requirements

    • Cython: Requires Cython>=v3.0.0b2 to cythonize creedsolo.pyx.
    • Packaging: The project now uses a src-layout and is PEP 517 compliant, supporting build isolation by default.

    API Changes

    • Imports: The standard import API remains similar:
      • Pure Python: import reedsolo as rs; codec = rs.RSCodec(10)
      • Cython extension: import creedsolo as crs
    • Cython C-Imports: If you use the fast Cython cimport system, you must change the path:
      • Old: cimport creedsolo as crs
      • New: cimport creedsolo.creedsolo as crs

    Data Type Requirements (Breaking Change)

    • creedsolo (Cython extension): You must always supply a bytearray object for both data and erasures_pos. Providing list or string objects will result in errors.
    • reedsolo (Pure Python): Still supports list objects as it transparently converts them to bytearray internally (specifically within RSCodec).

    Compatibility

    • Python Versions: Support for Python 2.7 and Python <= 3.6 has been dropped. For these versions, use reedsolo v1.7.0.
    # Standard import for pure python
    import reedsolo as rs
    codec = rs.RSCodec(10)
    
    # Standard import for cython extension
    import creedsolo as crs
    
    # New cimport path for Cython users
    cimport creedsolo.creedsolo as crs
    
    # CRITICAL: When using creedsolo, always use bytearray
    data = bytearray([1, 2, 3, 4])
    # erasures_pos = bytearray([0, 2])
  8. Install with Cython optimization via pip

    master

    By default, pip installs the pure-python reedsolo module. To build the speed-optimized Cython/C extension (creedsolo), you must force pip to use the source distribution (sdist) instead of wheels and pass the --cythonize configuration setting. This requires cython>=3.0.0b2 and a C compiler.

    If you encounter installation issues, use the --no-binary="reedsolo" and --no-cache flags to ensure a fresh build from source.

    # Compile from the latest stable release with Cythonization
    pip install --upgrade reedsolo --no-binary "reedsolo" --no-cache --config-setting="--build-option=--cythonize" --use-pep517 --isolated --verbose
    
    # Compile from the latest development release with Cythonization
    pip install --upgrade reedsolo --no-binary "reedsolo" --no-cache --config-setting="--build-option=--cythonize" --use-pep517 --isolated --pre --verbose
    
    # Compile from cutting-edge code with Cythonization
    pip install --upgrade "reedsolo @ git+https://github.com/tomerfiliba-org/reedsolomon" --no-binary "reedsolo" --no-cache --config-setting="--build-option=--cythonize" --use-pep517 --isolated --pre --verbose
  9. Optimize Cython loops with boundscheck and wraparound

    master

    When writing performance-critical Cython code (like Reed-Solomon encoding loops), you can disable safety checks to gain speed. Use these compiler directives at the top of your .pyx file or cell:

    • boundscheck=False: Disables checking if an index is within the array bounds.
    • wraparound=False: Disables negative indexing (e.g., arr[-1]).

    Warning: Disabling these can lead to segmentation faults if your logic is incorrect.

    # cython: boundscheck=False
    # cython: wraparound=False
  10. Configure custom Galois Field size and parameters

    master

    By default, the codec is limited to 256-bit characters and a maximum length of 256. You can increase these limits by adjusting the Galois Field parameters.

    • nsize or c_exp: Use these to increase the maximum length (always use a power of 2 minus 1, e.g., nsize=4095 or c_exp=12).
    • MATLAB Compatibility: To match MATLAB's rsenc, use prim=285 and fcr=1.
    • Variable ECC: You can use variable numbers of ECC symbols by initializing with single_gen=False and specifying nsym during encode() and decode() calls.
    # Larger chunks (max length 4095)
    rsc = RSCodec(12, nsize=4095)
    
    # MATLAB compatibility
    rsc_matlab = RSCodec(12, prim=285, fcr=1)
    
    # Variable ECC symbols
    rsc_var = RSCodec(10, single_gen=False)
    encoded = rsc_var.encode(b'data', nsym=12)
  11. Prevent dead code elimination in benchmarks

    master

    When benchmarking Cython code, the compiler may optimize away loops or operations if the result is not used. To ensure your code actually runs during a speed test, perform a dummy operation on the result (e.g., converting it to a string) to force the compiler to keep the code.

    # Example of preventing dead code elimination
    for i in range(L):
        d = arr[i]
    
    # Force usage of 'd'
    str(d)