pyadess

Python distribution matcher module implemented in Rust.

This module matches strings of bits to strings of amplitudes. While the marginal distributions of the bits are assumed to be uniform, the distribution of the amplitudes can be adapted to a channel.

Amplitudes are denoted $a \in \{1, 3, 5, 7, \dots\}$ in the following.

For a usage example see the example.py script in the repo (https://github.com/kit-cel/ad-ess)

1from .pyadess import *
2
3__doc__ = pyadess.__doc__
4if hasattr(pyadess, "__all__"):
5    __all__ = pyadess.__all__
class AdEss:

Encoder/decoder capable of arbitrary distributions

  • threshold: Maximum weight level in the trellis
  • n_max: Number of symbols/amplitudes
  • weights: Array of weights, weights[0] is the weight for $a=1$, weights[1] for $a=3$, ...
AdEss( threshold: int, n_max: int, weights: numpy.ArrayLike)
def new_for_distribution_threshold( threshold: int, n_max: int, distribution: numpy.ArrayLike, res_factor: float) -> AdEss:

Returns a new instance for a given distribution and threshold

  • threshold: Maximum weight level in the trellis
  • n_max: Number of symbols/amplitudes
  • distribution: Array of probabilities $[P(a=1), P(a=3), P(a=5), ...]$
  • The res_factor controls a trade off between trellis size and distribution quantisation. High res_factor leads to fine quantisation but a potentially large trellis.
def new_for_distribution_num_bits( num_bits: int, n_max: int, distribution: numpy.ArrayLike, res_factor: float) -> AdEss:

Returns a new instance for a given distribution and minimum number of encoded bits

  • num_bits: Number of data bits that can be encoded
  • n_max: Number of symbols/amplitudes
  • distribution: Array of probabilities $[P(a=1), P(a=3), P(a=5), ...]$
  • The res_factor controls a trade off between trellis size and distribution quantisation. High res_factor leads to fine quantisation but a potentially large trellis.
def new_for_distribution_optimal_threshold( n_max: int, distribution: numpy.ArrayLike, res_factor: float, search_width: int, rev_trellis_calculation_fraction: float) -> AdEss:

Returns a new instance for a given distribution using the optimal threshold

According to formulas (13) and (14) in https://doi.org/10.1109/LWC.2018.2890595

  • n_max: Number of symbols/amplitudes
  • distribution: Array of probabilities $[P(a=1), P(a=3), P(a=5), ...]$
  • The res_factor controls a trade off between trellis size and distribution quantisation. High res_factor leads to fine quantisation but a potentially large trellis.
  • search_width: Number of weight levels to check below and above the initial estimated optimal threshold
  • rev_trellis_calculation_fraction: The fraction of the reverse trellis that should be calculated. If the calculated fraction is to small, the optimal threshold can not be found.
def weights_from_distribution( self, distribution: numpy.ArrayLike, res_factor: float) -> numpy.ndarray[numpy.uint64]:

Calculates the trellis weights for a given distribution

  • distribution: Array of probabilities $[P(a=1), P(a=3), P(a=5), ...]$
  • The res_factor controls a trade off between trellis size and distribution quantisation. High res_factor leads to fine quantisation but a potentially large trellis.
def encode( self, index_bits: numpy.ArrayLike) -> numpy.ndarray[numpy.uint64]:

Returns the amplitude sequence for the given bits as a numpy array

The values in index_bits should be either 1 or 0. (Currently other values are possible but this may change.)

This function raises an exception if index_bits is invalid.

def multi_encode( self, multi_index_bits: numpy.ArrayLike) -> numpy.ndarray[numpy.uint64]:

Returns the amplitude sequences for multiple given bit strings as a 2D numpy array

The values in multi_index_bits should be either 1 or 0.

This function raises an exception if one of the index bit strings in multi_index_bits is invalid.

def decode( self, sequence: numpy.ArrayLike) -> numpy.ndarray[numpy.uint64]:

Returns the index corresponding to the provided amplitude sequence as a numpy array of 1s and 0s

Raises an exception if sequence is invalid.

  • sequence - numpy array or list of length n_max (as passed to constructor)
def multi_decode( self, sequences: numpy.ArrayLike) -> numpy.ndarray[numpy.uint64]:

Returns the indexes corresponding to the provided amplitude sequence as a 2D numpy array of 1s and 0s

Raises an exception if any amplitude sequence in sequences is invalid.

  • sequences - 2D numpy array of dimension [arbitrary, n_max (as passed to constructor)]
def num_data_bits(self) -> int:

Returns the number of bits encoded per amplitude sequence

def get_weights(self) -> numpy.ndarray[numpy.uint64]:

Returns the weights used by the internal trellis

def get_distribution( self, res_factor: float) -> numpy.ndarray[numpy.float32]:

Returns the distribution AdEss is optimizing for

def amplitude_distribution( self) -> numpy.ndarray[numpy.float32]:

Returns the probabilities of the amplitude values

The probabilities are returned as an array with the lowest index corresponding to the lowest amplitude.

def average_energy(self) -> float:

Returns the average energy of amplitude sequences

def num_sequences_possible(self) -> str:

Returns the maximum number of possible amplitude sequences as a string

WARNING: Effect of limiting the used indexes to a power of two is not regarded!!!