Warning: This is a development version. The latest stable version is Version 1.3.0.

RLNC Encode, Recode and Decode

In this example shows how to use the API of pyerasure to encode, recode and decode with using the RLNC coefficient generator.

  1#!/usr/bin/env python
  2# encoding: utf-8
  3
  4# License for Commercial Usage
  5# Distributed under the "PYERASURE EVALUATION LICENSE 1.3"
  6# Licensees holding a valid commercial license may use this project in
  7# accordance with the standard license agreement terms provided with the
  8# Software (see accompanying file LICENSE.rst or
  9# https://www.steinwurf.com/license), unless otherwise different terms and
 10# conditions are agreed in writing between Licensee and Steinwurf ApS in which
 11# case the license will be regulated by that separate written agreement.
 12#
 13# License for Non-Commercial Usage
 14# Distributed under the "PYERASURE RESEARCH LICENSE 1.2"
 15# Licensees holding a valid research license may use this project in accordance
 16# with the license agreement terms provided with the Software
 17# See accompanying file LICENSE.rst or https://www.steinwurf.com/license
 18
 19import os
 20import sys
 21import random
 22
 23import pyerasure
 24import pyerasure.finite_field
 25import pyerasure.generator
 26
 27
 28def main():
 29    """
 30    Encode recode decode example.
 31
 32    In Network Coding applications, one of the key features is the
 33    ability of intermediate nodes in the network to recode packets
 34    as they traverse them. Using pyerasure, it is possible to recode
 35    packets in decoders with the recode_symbol function.
 36
 37    This example shows how to use one encoder and two decoders to
 38    simulate a simple relay network as shown below:
 39
 40            +-----------+     +-----------+     +-----------+
 41            |  encoder  |+--->|  recoder  |+--->|  decoder  |
 42            +-----------+     +-----------+     +-----------+
 43
 44    In a practical application recoding can be used in several different
 45    ways and one must consider several different factors, such as
 46    reducing linear dependency by coordinating several recoding nodes
 47    in the network.
 48    Suggestions for dealing with such issues can be found in current
 49    research literature (e.g. MORE: A Network Coding Approach to
 50    Opportunistic Routing).
 51    """
 52    # Choose the finite field, the number of symbols (i.e. generation size)
 53    # and the symbol size in bytes
 54    field = pyerasure.finite_field.Binary8()
 55    symbols = 42
 56    symbol_bytes = 160
 57
 58    # Create an encoder and two decoders
 59    encoder = pyerasure.Encoder(field, symbols, symbol_bytes)
 60    recoder = pyerasure.Decoder(field, symbols, symbol_bytes)
 61    decoder = pyerasure.Decoder(field, symbols, symbol_bytes)
 62
 63    # Create generator
 64    generator = pyerasure.generator.RandomUniform(field, symbols)
 65
 66    # Generate some random data to encode. We create a bytearray of the same
 67    # size as the encoder's block size and assign it to the encoder.
 68    # This bytearray must not go out of scope while the encoder exists!
 69    data_in = bytearray(os.urandom(encoder.block_bytes))
 70    encoder.set_symbols(data_in)
 71
 72    coefficients = None
 73
 74    loss_probability = 25
 75    systematic_index = 0
 76
 77    while not decoder.is_complete():
 78
 79        if encoder.rank > systematic_index:
 80            print("systematic symbol", end="")
 81
 82            index = systematic_index
 83            systematic_index += 1
 84            symbol = encoder.symbol_data(index)
 85
 86            # Drop packet based on loss probability
 87            if random.randint(0, 100) < loss_probability:
 88                print(" - lost")
 89            else:
 90                recoder.decode_systematic_symbol(symbol, index)
 91                print(f" - decoded, rank now {recoder.rank}")
 92        elif not recoder.is_complete():
 93
 94            # The RLNC code is rateless, which means, in theory, that it can
 95            # generate an infinite number of coded packets.
 96            print("coded symbol", end="")
 97
 98            # Generate the coefficients into the symbol buffer
 99            coefficients = generator.generate()
100
101            # Encode a symbol into the symbol buffer
102            symbol = encoder.encode_symbol(coefficients)
103
104            # Drop packet based on loss probability
105            if random.randint(0, 100) < loss_probability:
106                print(" - lost")
107            else:
108                # Note, in this example the coefficients are available, but in
109                # certain use cases - especially network based it might not be
110                # feasible to transmit the coefficients. In this case the seed
111                # can be used for generating the coefficients again.
112                recoder.decode_symbol(symbol, bytearray(coefficients))
113                print(f" - decoded, rank now {recoder.rank}")
114
115        if recoder.rank != 0:
116            print("recoded symbol", end="")
117            recoding_coefficients = generator.generate_recode(recoder)
118            symbol, coefficients = recoder.recode_symbol(
119                bytearray(recoding_coefficients)
120            )
121
122            if random.randint(0, 100) < loss_probability:
123                print(" - lost")
124            else:
125                # When recoding sending the whole coefficient vector is often
126                # needed as the state of the recorder determines the
127                # coefficients.
128                decoder.decode_symbol(symbol, coefficients)
129                print(f" - decoded, rank now {decoder.rank}")
130
131    # Both recoder and decoder should now be complete,
132    # check if the output buffers match the data_in buffer
133    if recoder.block_data() == data_in and decoder.block_data() == data_in:
134        print("Data decoded correctly")
135    else:
136        print("Unexpected failure to decode please file a bug report :)")
137        sys.exit(1)
138
139
140if __name__ == "__main__":
141    main()
Fork me on GitHub
Versions
1.3.0
1.2.0
1.1.0
1.0.1
1.0.0
Development
latest