Turn Off Systematic CodingΒΆ

A simple, yet clever technique called systematic encoding can be used to improve the performance of network coding. The way it works is to initially send everything uncoded, and then start the encoding. The benefit of this is that as the receivers initially has no data, all data will be useful for them. So if the symbols are safely received by the decoder, it can get the data “for free” without the need for decoding. The Kodo library has built-in support for this approach. The sample code, for this is again build based on the basic example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Copyright Steinwurf ApS 2013.
// Distributed under the "STEINWURF RESEARCH LICENSE 1.0".
// See accompanying file LICENSE.rst or
// http://www.steinwurf.com/licensing

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <vector>

#include <kodo_rlnc/full_vector_codes.hpp>
#include <kodo_core/is_systematic_on.hpp>
#include <kodo_core/set_systematic_off.hpp>

#include <storage/storage.hpp>


int main()
{
    // Set the number of symbols (i.e. the generation size in RLNC
    // terminology) and the size of a symbol in bytes
    uint32_t max_symbols = 16;
    uint32_t max_symbol_size = 1400;
    fifi::api::field field = fifi::api::field::binary8;

    using rlnc_encoder = kodo_rlnc::full_vector_encoder;
    using rlnc_decoder = kodo_rlnc::full_vector_decoder;

    // In the following we will make an encoder/decoder factory.
    // The factories are used to build actual encoders/decoders
    rlnc_encoder::factory encoder_factory(field, max_symbols, max_symbol_size);
    auto encoder = encoder_factory.build();

    rlnc_decoder::factory decoder_factory(field, max_symbols, max_symbol_size);
    auto decoder = decoder_factory.build();

    std::vector<uint8_t> payload(encoder->payload_size());
    std::vector<uint8_t> block_in(encoder->block_size());

    // Just for fun - fill the data with random data
    std::generate(block_in.begin(), block_in.end(), rand);

    // Assign the data buffer to the encoder so that we may start
    // to produce encoded symbols from it
    encoder->set_const_symbols(storage::storage(block_in));

    // Define a data buffer where the symbols should be decoded
    std::vector<uint8_t> block_out(decoder->block_size());
    decoder->set_mutable_symbols(storage::storage(block_out));

    uint32_t encoded_count = 0;
    uint32_t dropped_count = 0;

    //! [0]
    // We switch any systematic operations off so we code
    // symbols from the beginning
    if (kodo_core::is_systematic_on(*encoder))
        kodo_core::set_systematic_off(*encoder);
    //! [1]

    while (!decoder->is_complete())
    {
        // Encode a packet into the payload buffer
        uint32_t bytes_used = encoder->write_payload(payload.data());
        std::cout << "Bytes used = " << bytes_used << std::endl;

        ++encoded_count;

        if (rand() % 2)
        {
            ++dropped_count;
            continue;
        }

        // Pass that packet to the decoder
        decoder->read_payload(payload.data());
    }

    std::cout << "Encoded count = " << encoded_count << std::endl;
    std::cout << "Dropped count = " << dropped_count << std::endl;

    return 0;
}

What’s added in this example here is the use of is_systematic_on and set_systematic_off.

1
2
3
4
    // We switch any systematic operations off so we code
    // symbols from the beginning
    if (kodo_core::is_systematic_on(*encoder))
        kodo_core::set_systematic_off(*encoder);

Initially Kodo’s Full RLNC encoder has the systematic phase enabled per default. As seen in the previous example, this is automatically turned off when all symbols has been send once. In this example we turn off the systematic phase before entering the coding loop. This can easily seen from the output when running the example:

Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Bytes used = 1417
Encoded count = 27
Dropped count = 11

Here the bytes used is always the same as all the symbols are encoded by the encoder. For most use cases the systematic phase is beneficial. However it should be avoided if

  • The state of receivers is unknown. If that’s the case, using the systematic approach might result in sending redundant data, as the receivers might already have some of the data.
  • The setup has multiple sources. If this is the case, the sources should not send the same data, as this can be redundant for the receivers.