From f6754899cceb7efbfc3b9800b558d3e250e4424a Mon Sep 17 00:00:00 2001 From: Roberto Nobrega Date: Thu, 31 Oct 2024 23:12:38 -0300 Subject: [PATCH] Fixes Griffe issue with Google-style sections --- src/komm/_algebra/BinaryPolynomial.py | 16 ---------------- src/komm/_algebra/FiniteBifield.py | 4 ---- src/komm/_algebra/RationalPolynomial.py | 12 ------------ src/komm/_channels/AWGNChannel.py | 3 --- src/komm/_channels/BinaryErasureChannel.py | 3 --- src/komm/_channels/BinarySymmetricChannel.py | 3 --- src/komm/_channels/DiscreteMemorylessChannel.py | 8 -------- src/komm/_error_control_block/BCHCode.py | 3 --- src/komm/_error_control_block/BlockCode.py | 13 ------------- src/komm/_error_control_block/BlockDecoder.py | 11 +++-------- src/komm/_error_control_block/BlockEncoder.py | 6 +----- .../_error_control_block/CordaroWagnerCode.py | 2 -- src/komm/_error_control_block/CyclicCode.py | 2 -- src/komm/_error_control_block/GolayCode.py | 3 --- src/komm/_error_control_block/HammingCode.py | 3 --- src/komm/_error_control_block/ReedMullerCode.py | 4 ---- src/komm/_error_control_block/RepetitionCode.py | 3 --- src/komm/_error_control_block/SimplexCode.py | 3 --- .../SingleParityCheckCode.py | 3 --- .../_error_control_block/SystematicBlockCode.py | 2 -- .../TerminatedConvolutionalCode.py | 2 -- .../ConvolutionalCode.py | 2 -- .../ConvolutionalStreamDecoder.py | 4 ---- .../ConvolutionalStreamEncoder.py | 4 ---- .../_finite_state_machine/FiniteStateMachine.py | 13 ------------- src/komm/_modulation/APSKModulation.py | 2 -- src/komm/_modulation/ASKModulation.py | 2 -- src/komm/_modulation/Modulation.py | 16 ---------------- src/komm/_modulation/PAModulation.py | 2 -- src/komm/_modulation/PSKModulation.py | 2 -- src/komm/_modulation/QAModulation.py | 2 -- src/komm/_pulses/FormattingPulse.py | 1 - src/komm/_pulses/GaussianPulse.py | 2 -- src/komm/_pulses/ManchesterPulse.py | 1 - src/komm/_pulses/RaisedCosinePulse.py | 2 -- src/komm/_pulses/RectangularPulse.py | 2 -- src/komm/_pulses/RootRaisedCosinePulse.py | 2 -- src/komm/_pulses/SincPulse.py | 2 -- src/komm/_pulses/TransmitFilter.py | 3 --- src/komm/_quantization/ScalarQuantizer.py | 2 -- src/komm/_quantization/UniformQuantizer.py | 2 -- src/komm/_sequences/BarkerSequence.py | 3 --- src/komm/_sequences/BinarySequence.py | 8 -------- src/komm/_sequences/ComplexSequence.py | 8 -------- src/komm/_sequences/LFSRSequence.py | 5 ----- src/komm/_sequences/WalshHadamardSequence.py | 3 --- src/komm/_sequences/ZadoffChuSequence.py | 3 --- src/komm/_source_coding/FixedToVariableCode.py | 12 ------------ .../_source_coding/FixedToVariableDecoder.py | 4 ---- .../_source_coding/FixedToVariableEncoder.py | 4 ---- src/komm/_source_coding/HuffmanCode.py | 2 -- src/komm/_source_coding/TunstallCode.py | 2 -- src/komm/_source_coding/VariableToFixedCode.py | 11 ----------- .../_source_coding/VariableToFixedDecoder.py | 4 ---- .../_source_coding/VariableToFixedEncoder.py | 4 ---- src/komm/_sources/DiscreteMemorylessSource.py | 4 ---- src/komm/_util/bit_operations.py | 6 ------ src/komm/_util/correlation.py | 6 ------ src/komm/_util/information_theory.py | 3 --- src/komm/_util/special_functions.py | 7 +------ 60 files changed, 5 insertions(+), 271 deletions(-) diff --git a/src/komm/_algebra/BinaryPolynomial.py b/src/komm/_algebra/BinaryPolynomial.py index 390a5d97..fa0e4d94 100644 --- a/src/komm/_algebra/BinaryPolynomial.py +++ b/src/komm/_algebra/BinaryPolynomial.py @@ -12,7 +12,6 @@ class BinaryPolynomial: Binary polynomial. A *binary polynomial* is a polynomial whose coefficients are elements in the finite field $\mathbb{F}_2 = \\{ 0, 1 \\}$. This class supports addition, multiplication, division, and exponentiation. Examples: - >>> poly1 = komm.BinaryPolynomial(0b10100) # X^4 + X^2 >>> poly2 = komm.BinaryPolynomial(0b11010) # X^4 + X^3 + X >>> poly1 + poly2 # X^3 + X^2 + X @@ -28,11 +27,9 @@ def __init__(self, integer): Default constructor for the class. Parameters: - integer (int): An integer whose binary digits represent the coefficients of the polynomial—the leftmost bit standing for the highest degree term. For example, the binary polynomial $X^4 + X^3 + X$ is represented by the integer `0b11010` = `0o32` = `26`. Examples: - >>> komm.BinaryPolynomial(0b11010) # X^4 + X^3 + X BinaryPolynomial(0b11010) @@ -46,11 +43,9 @@ def from_coefficients(cls, coefficients): Constructs a binary polynomial from its coefficients. Parameters: - coefficients (Array1D[int]): The coefficients of the binary polynomial—the $i$-th element of the array standing for the coefficient of $X^i$. For example, `[0, 1, 0, 1, 1]` represents the binary polynomial $X^4 + X^3 + X$. Examples: - >>> komm.BinaryPolynomial.from_coefficients([0, 1, 0, 1, 1]) # X^4 + X^3 + X BinaryPolynomial(0b11010) """ @@ -62,11 +57,9 @@ def from_exponents(cls, exponents): Constructs a binary polynomial from its exponents. Parameters: - exponents (Array1D[int]): The exponents of the nonzero terms of the binary polynomial. For example, `[1, 3, 4]` represents the binary polynomial $X^4 + X^3 + X$. Examples: - >>> komm.BinaryPolynomial.from_exponents([1, 3, 4]) # X^4 + X^3 + X BinaryPolynomial(0b11010) """ @@ -78,7 +71,6 @@ def degree(self): The degree of the polynomial. Examples: - >>> poly = komm.BinaryPolynomial(0b11010) # X^4 + X^3 + X >>> poly.degree 4 @@ -90,15 +82,12 @@ def coefficients(self, width=None): Returns the coefficients of the binary polynomial. Parameters: - width (Optional[int]): If this parameter is specified, the output will be filled with zeros on the right so that the its length will be the specified value. Returns: - coefficients (Array1D[int]): Coefficients of the binary polynomial. The $i$-th element of the array stands for the coefficient of $X^i$. Examples: - >>> poly = komm.BinaryPolynomial(0b11010) # X^4 + X^3 + X >>> poly.coefficients() array([0, 1, 0, 1, 1]) @@ -112,11 +101,9 @@ def exponents(self): Returns the exponents of the binary polynomial. Returns: - exponents (Array1D[int]): Exponents of the nonzero terms of the binary polynomial. The exponents are returned in ascending order. Examples: - >>> poly = komm.BinaryPolynomial(0b11010) # X^4 + X^3 + X >>> poly.exponents() array([1, 3, 4]) @@ -172,15 +159,12 @@ def evaluate(self, point): Evaluates the polynomial at a given point. Uses Horner's method. Parameters: - point (RingElement): Any Python object supporting the operations of addition, subtraction, and multiplication. Returns: - result (RingElement): The result of evaluating the binary polynomial at `point`. It has the same type as `point`. Examples: - >>> poly = komm.BinaryPolynomial(0b11010) # X^4 + X^3 + X >>> poly.evaluate(7) # same as 7**4 + 7**3 + 7 np.int64(2751) diff --git a/src/komm/_algebra/FiniteBifield.py b/src/komm/_algebra/FiniteBifield.py index 9f9833a6..c7b202d6 100644 --- a/src/komm/_algebra/FiniteBifield.py +++ b/src/komm/_algebra/FiniteBifield.py @@ -13,7 +13,6 @@ class FiniteBifield: To construct *elements* of the finite field, call the finite field object. For example, `field(0b1101)` will construct the element whose polynomial representation is $X^3 + X^2 + 1$. Examples: - >>> field = komm.FiniteBifield(4) >>> x = field(0b1011) >>> y = field(0b1100) @@ -30,7 +29,6 @@ def __init__(self, degree, modulus=None): Constructor for the class. Parameters: - degree (int): Degree $k$ of the finite field. Must be a positive integer. modulus (Optional[BinaryPolynomial | int]): Modulus (primitive polynomial) $p(X)$ of the field, specified either as a [binary polynomial](/ref/BinaryPolynomial) or as an integer to be converted to the former. Must be an irreducible polynomial. If not specified, the modulus is chosen from the table below LC04, p.42. @@ -47,7 +45,6 @@ def __init__(self, degree, modulus=None): | $8$ | `0b100011101` | $16$ | `0b10001000000001011` | Examples: - >>> field = komm.FiniteBifield(4) >>> field FiniteBifield(4) @@ -108,7 +105,6 @@ def primitive_element(self): A primitive element $\alpha$ of the finite field. It satisfies $p(\alpha) = 0$, where $p(X)$ is the modulus (primitive polynomial) of the finite field. Examples: - >>> field1 = komm.FiniteBifield(3, modulus=0b1011) >>> alpha1 = field1.primitive_element >>> [alpha1**i for i in range(7)] diff --git a/src/komm/_algebra/RationalPolynomial.py b/src/komm/_algebra/RationalPolynomial.py index d894896c..f9eea864 100644 --- a/src/komm/_algebra/RationalPolynomial.py +++ b/src/komm/_algebra/RationalPolynomial.py @@ -12,7 +12,6 @@ class RationalPolynomial: Rational polynomial. A *rational polynomial* is a polynomial whose coefficients are all rational numbers. This class supports addition, subtraction, multiplication, division, and exponentiation. Examples: - >>> poly1 = komm.RationalPolynomial(['1/2', '0', '3']) # 1/2 + 3 X^2 >>> poly1 RationalPolynomial(['1/2', '0', '3']) @@ -30,11 +29,9 @@ def __init__(self, coefficients): Constructor for the class. Parameters: - coefficients (Array1D[int | str | Fraction]): The coefficients of the rational polynomial—the $i$-th element of the array standing for the coefficient of $X^i$. For example, `['1/2', '0', '3']` represents the rational polynomial $1/2 + 3 X^2$. Examples: - >>> komm.RationalPolynomial(['1/2', '0', '3']) # 1/2 + 3 X^2 RationalPolynomial(['1/2', '0', '3']) """ @@ -54,13 +51,11 @@ def monomial(cls, degree, coefficient=1): Constructs a monomial. This is an polynomial of the form $cX^d$. Parameters: - degree (int): The degree $d$ of the monomial. coefficient (Optional[int]): The coefficient $c$ of the monomial. The default value is $1$. Examples: - >>> komm.RationalPolynomial.monomial(4, 2) # 2 X^4 RationalPolynomial(['0', '0', '0', '0', '2']) """ @@ -71,15 +66,12 @@ def coefficients(self, width=None): Returns the coefficients of the polynomial. Parameters: - width (Optional[int]): If this parameter is specified, the output will be filled with zeros on the right so that the its length will be the specified value. Returns: - coefficients (Array1D[int]): Coefficients of the polynomial. The $i$-th element of the array stands for the coefficient of $X^i$. Examples: - >>> poly = komm.RationalPolynomial(['0', '1/3', '2/3']) # (1/3) X + (2/3) X^2 >>> poly.coefficients() array([Fraction(0, 1), Fraction(1, 3), Fraction(2, 3)], dtype=object) @@ -100,7 +92,6 @@ def degree(self): The degree of the polynomial. Examples: - >>> poly = komm.RationalPolynomial([1, 0, 3]) # 1 + 3 X^2 >>> poly.degree 2 @@ -180,15 +171,12 @@ def evaluate(self, point): Evaluates the polynomial at a given point. Uses Horner's method. Parameters: - point (RingElement): Any Python object supporting the operations of addition, subtraction, and multiplication. Returns: - result (RingElement): The result of evaluating the binary polynomial at `point`. It has the same type as `point`. Examples: - >>> poly = komm.RationalPolynomial([0, 1, 0, -1, 2]) # X - X^3 + 2 X^4 >>> poly.evaluate(7) # same as 7 - 7**3 + 2 * 7**4 Fraction(4466, 1) diff --git a/src/komm/_channels/AWGNChannel.py b/src/komm/_channels/AWGNChannel.py index 6a61e0cd..7d53edf3 100644 --- a/src/komm/_channels/AWGNChannel.py +++ b/src/komm/_channels/AWGNChannel.py @@ -20,13 +20,11 @@ def __init__(self, signal_power, snr=np.inf): r"""Constructor for the class. Parameters: - signal_power (float | str): The input signal power $P$. If equal to the string `'measured'`, then every time the channel is invoked the input signal power will be computed from the input itself (i.e., its squared Euclidean norm). snr (Optional[float]): The channel signal-to-noise ratio $\snr$ (linear, not decibel). The default value is `np.inf`, which corresponds to a noiseless channel. Examples: - >>> np.random.seed(1) >>> awgn = komm.AWGNChannel(snr=200.0, signal_power=5.0) >>> x = [1.0, 3.0, -3.0, -1.0, -1.0, 1.0, 3.0, 1.0, -1.0, 3.0] @@ -73,7 +71,6 @@ def capacity(self): Returns the channel capacity $C$. It is given by $C = \frac{1}{2}\log_2(1 + \snr)$, in bits per dimension. Examples: - >>> awgn = komm.AWGNChannel(signal_power=1.0, snr=63.0) >>> awgn.capacity() np.float64(3.0) diff --git a/src/komm/_channels/BinaryErasureChannel.py b/src/komm/_channels/BinaryErasureChannel.py index a786e7f1..c9895dca 100644 --- a/src/komm/_channels/BinaryErasureChannel.py +++ b/src/komm/_channels/BinaryErasureChannel.py @@ -23,11 +23,9 @@ def __init__(self, erasure_probability=0.0): Constructor for the class. Parameters: - erasure_probability (Optional[float]): The channel erasure probability $\epsilon$. Must satisfy $0 \leq \epsilon \leq 1$. Default value is `0.0`, which corresponds to a noiseless channel. Examples: - >>> np.random.seed(1) >>> bec = komm.BinaryErasureChannel(0.1) >>> x = [1, 1, 1, 0, 0, 0, 1, 0, 1, 0] @@ -53,7 +51,6 @@ def capacity(self): Returns the channel capacity $C$. It is given by $C = 1 - \epsilon$. See CT06, Sec. 7.1.5. Examples: - >>> bec = komm.BinaryErasureChannel(0.25) >>> bec.capacity() 0.75 diff --git a/src/komm/_channels/BinarySymmetricChannel.py b/src/komm/_channels/BinarySymmetricChannel.py index 44086ff1..31383d1b 100644 --- a/src/komm/_channels/BinarySymmetricChannel.py +++ b/src/komm/_channels/BinarySymmetricChannel.py @@ -24,11 +24,9 @@ def __init__(self, crossover_probability=0.0): Constructor for the class. Parameters: - crossover_probability (Optional[float]): The channel crossover probability $p$. Must satisfy $0 \leq p \leq 1$. The default value is `0.0`, which corresponds to a noiseless channel. Examples: - >>> np.random.seed(1) >>> bsc = komm.BinarySymmetricChannel(0.1) >>> x = [0, 1, 1, 1, 0, 0, 0, 0, 0, 1] @@ -54,7 +52,6 @@ def capacity(self): Returns the channel capacity $C$. It is given by $C = 1 - \mathcal{H}(p)$. See CT06, Sec. 7.1.4. Examples: - >>> bsc = komm.BinarySymmetricChannel(0.25) >>> bsc.capacity() np.float64(0.18872187554086717) diff --git a/src/komm/_channels/DiscreteMemorylessChannel.py b/src/komm/_channels/DiscreteMemorylessChannel.py index 0b01ea11..adbb2280 100644 --- a/src/komm/_channels/DiscreteMemorylessChannel.py +++ b/src/komm/_channels/DiscreteMemorylessChannel.py @@ -15,11 +15,9 @@ def __init__(self, transition_matrix): Constructor for the class. Parameters: - transition_matrix (Array2D[float]): The channel transition probability matrix $p_{Y \mid X}$. The element in row $x \in \mathcal{X}$ and column $y \in \mathcal{Y}$ must be equal to $p_{Y \mid X}(y \mid x)$. Examples: - >>> np.random.seed(1) >>> dmc = komm.DiscreteMemorylessChannel([[0.9, 0.05, 0.05], [0.0, 0.5, 0.5]]) >>> x = [0, 1, 0, 1, 1, 1, 0, 0, 0, 1] @@ -66,17 +64,14 @@ def mutual_information(self, input_pmf, base=2.0): where $\mathrm{H}(X)$ is the the entropy of $X$ and $\mathrm{H}(X \mid Y)$ is the conditional entropy of $X$ given $Y$. By default, the base of the logarithm is $2$, in which case the mutual information is measured in bits. See CT06, Ch. 2. Parameters: - input_pmf (Array1D[float]): The probability mass function $p_X$ of the channel input $X$. It must be a valid pmf, that is, all of its values must be non-negative and sum up to $1$. base (Optional[float | str]): The base of the logarithm to be used. It must be a positive float or the string `'e'`. The default value is `2.0`. Returns: - mutual_information (float): The mutual information $\mathrm{I}(X ; Y)$ between the input $X$ and the output $Y$. Examples: - >>> dmc = komm.DiscreteMemorylessChannel([[0.6, 0.3, 0.1], [0.7, 0.1, 0.2], [0.5, 0.05, 0.45]]) >>> dmc.mutual_information([1/3, 1/3, 1/3]) # doctest: +NUMBER np.float64(0.123811098798) @@ -90,15 +85,12 @@ def capacity(self, base=2.0): Returns the channel capacity $C$. It is given by $C = \max_{p_X} \mathrm{I}(X;Y)$. This method computes the channel capacity via the Arimoto–Blahut algorithm. See CT06, Sec. 10.8. Parameters: - base (Optional[float | str]): The base of the logarithm to be used. It must be a positive float or the string `'e'`. The default value is `2.0`. Returns: - capacity (float): The channel capacity $C$. Examples: - >>> dmc = komm.DiscreteMemorylessChannel([[0.6, 0.3, 0.1], [0.7, 0.1, 0.2], [0.5, 0.05, 0.45]]) >>> dmc.capacity() # doctest: +NUMBER np.float64(0.1616318610) diff --git a/src/komm/_error_control_block/BCHCode.py b/src/komm/_error_control_block/BCHCode.py index b97f979b..4f82f36e 100644 --- a/src/komm/_error_control_block/BCHCode.py +++ b/src/komm/_error_control_block/BCHCode.py @@ -38,17 +38,14 @@ class BCHCode(CyclicCode): | $10$ | $1023$ | $3$, $5$, $7$, $9$, $11$, $13$, $15$, $17$, $19$, $21$, $23$, $25$, $27$, $29$, $31$, $33$, $35$, $37$, $39$, $41$, $43$, $45$, $47$, $49$, $51$, $53$, $55$, $57$, $59$, $61$, $63$, $69$, $71$, $73$, $75$, $77$, $79$, $83$, $85$, $87$, $89$, $91$, $93$, $95$, $99$, $101$, $103$, $105$, $107$, $109$, $111$, $115$, $117$, $119$, $121$, $123$, $125$, $127$, $147$, $149$, $151$, $155$, $157$, $159$, $165$, $167$, $171$, $173$, $175$, $179$, $181$, $183$, $187$, $189$, $191$, $205$, $207$, $213$, $215$, $219$, $221$, $223$, $231$, $235$, $237$, $239$, $245$, $247$, $251$, $253$, $255$, $341$, $343$, $347$, $351$, $363$, $367$, $375$, $379$, $383$, $439$, $447$, $479$, $495$, $511$, $1023$ | Notes: - - For $\delta = 3$ it reduces to the [Hamming code](/ref/HammingCode). - For $\delta = 2^{\mu} - 1$ it reduces to the [repetition code](/ref/RepetitionCode). Attributes: - mu (int): The parameter $\mu$ of the BCH code. delta (int): The Bose distance $\delta$ of the BCH code. Examples: - >>> code = komm.BCHCode(mu=5, delta=7) >>> (code.length, code.dimension, code.minimum_distance) (31, 16, np.int64(7)) diff --git a/src/komm/_error_control_block/BlockCode.py b/src/komm/_error_control_block/BlockCode.py index d67f5b7b..ee8643a3 100644 --- a/src/komm/_error_control_block/BlockCode.py +++ b/src/komm/_error_control_block/BlockCode.py @@ -17,12 +17,10 @@ class BlockCode: The constructor expects either the generator matrix or the check matrix. Parameters: - generator_matrix (Array2D[int]): The generator matrix $G$ of the code, which is a $k \times n$ binary matrix. check_matrix (Array2D[int]): The check matrix $H$ of the code, which is a $m \times n$ binary matrix. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> (code.length, code.dimension, code.redundancy) (6, 3, 3) @@ -115,7 +113,6 @@ def rate(self) -> float: The rate $R = k/n$ of the code. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.rate 0.5 @@ -127,7 +124,6 @@ def enc_mapping(self, u: npt.ArrayLike) -> np.ndarray: The encoding mapping $\Enc : \mathbb{B}^k \to \mathbb{B}^n$ of the code. This is a function that takes a message $u \in \mathbb{B}^k$ and returns the corresponding codeword $v \in \mathbb{B}^n$. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> enc_mapping = code.enc_mapping >>> enc_mapping([1, 0, 1]) @@ -141,7 +137,6 @@ def inv_enc_mapping(self, v: npt.ArrayLike) -> np.ndarray: The inverse encoding mapping $\Enc^{-1} : \mathbb{B}^n \to \mathbb{B}^k$ of the code. This is a function that takes a codeword $v \in \mathbb{B}^n$ and returns the corresponding message $u \in \mathbb{B}^k$. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> inv_enc_mapping = code.inv_enc_mapping >>> inv_enc_mapping([1, 0, 1, 1, 0, 1]) @@ -162,7 +157,6 @@ def codewords(self) -> np.ndarray: The codewords of the code. This is a $2^k \times n$ matrix whose rows are all the codewords. The codeword in row $i$ corresponds to the message whose binary representation (MSB in the right) is $i$. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.codewords array([[0, 0, 0, 0, 0, 0], @@ -184,7 +178,6 @@ def codeword_weight_distribution(self) -> np.ndarray: The codeword weight distribution of the code. This is an array of shape $(n + 1)$ in which element in position $w$ is equal to the number of codewords of Hamming weight $w$, for $w \in [0 : n]$. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.codeword_weight_distribution array([1, 0, 0, 4, 3, 0, 0]) @@ -196,7 +189,6 @@ def chk_mapping(self, r: npt.ArrayLike) -> np.ndarray: The check mapping $\mathrm{Chk}: \mathbb{B}^n \to \mathbb{B}^m$ of the code. This is a function that takes a received word $r \in \mathbb{B}^n$ and returns the corresponding syndrome $s \in \mathbb{B}^m$. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> chk_mapping = code.chk_mapping >>> chk_mapping([1, 0, 1, 1, 0, 1]) @@ -211,7 +203,6 @@ def coset_leaders(self) -> np.ndarray: The coset leaders of the code. This is a $2^m \times n$ matrix whose rows are all the coset leaders. The coset leader in row $i$ corresponds to the syndrome whose binary representation (MSB in the right) is $i$, and whose Hamming weight is minimal. This may be used as a LUT for syndrome-based decoding. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.coset_leaders array([[0, 0, 0, 0, 0, 0], @@ -245,7 +236,6 @@ def coset_leader_weight_distribution(self) -> np.ndarray: The coset leader weight distribution of the code. This is an array of shape $(n + 1)$ in which element in position $w$ is equal to the number of coset leaders of weight $w$, for $w \in [0 : n]$. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.coset_leader_weight_distribution array([1, 6, 1, 0, 0, 0, 0]) @@ -260,7 +250,6 @@ def minimum_distance(self) -> int: The minimum distance $d$ of the code. This is equal to the minimum Hamming weight of the non-zero codewords. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.minimum_distance 3 @@ -273,7 +262,6 @@ def packing_radius(self) -> int: The packing radius of the code. This is also called the *error-correcting capability* of the code, and is equal to $\lfloor (d - 1) / 2 \rfloor$. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.packing_radius 1 @@ -286,7 +274,6 @@ def covering_radius(self) -> int: The covering radius of the code. This is equal to the maximum Hamming weight of the coset leaders. Examples: - >>> code = komm.BlockCode(generator_matrix=[[1, 0, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1], [0, 0, 1, 1, 1, 0]]) >>> code.covering_radius 2 diff --git a/src/komm/_error_control_block/BlockDecoder.py b/src/komm/_error_control_block/BlockDecoder.py index 09f8ed34..b4f4e506 100644 --- a/src/komm/_error_control_block/BlockDecoder.py +++ b/src/komm/_error_control_block/BlockDecoder.py @@ -12,14 +12,12 @@ class BlockDecoder: Decoder for [linear block codes](/ref/BlockCode). Attributes: - code: The [block code](/ref/BlockCode) to be considered. method: The identifier of the method to be used for decoding. The default corresponds to `code.default_decoder`. decoder_kwargs: Additional keyword arguments to be passed to the decoder. - Note: - - To see the default decoding method for a given code, use `code.default_decoder`; to see the available decoding methods for a given code, use `code.supported_decoders()`. + Notes: + - To see the default decoding method for a given code, use `code.default_decoder`; to see the available decoding methods for a given code, use `code.supported_decoders()`. ??? info "Available decoding methods" @@ -107,16 +105,13 @@ class BlockDecoder: - Target: message - Supported by: [`ReedMullerCode`](/ref/ReedMullerCode). - Parameters: Input - + Parameters: Input: in0 (Array1D[int] | Array1D[float]): The (hard or soft) bit sequence to be decoded. Its length must be a multiple of the code's block length $n$. Parameters: Output: - out0 (Array1D[int]): The decoded bit sequence. Its length is a multiple of the code's dimension $k$. Examples: - >>> code = komm.HammingCode(3) >>> code.default_decoder 'syndrome_table' diff --git a/src/komm/_error_control_block/BlockEncoder.py b/src/komm/_error_control_block/BlockEncoder.py index a470bf3a..ed478aeb 100644 --- a/src/komm/_error_control_block/BlockEncoder.py +++ b/src/komm/_error_control_block/BlockEncoder.py @@ -11,19 +11,15 @@ class BlockEncoder: Encoder for [linear block codes](/ref/BlockCode). Attributes: - code: The [block code](/ref/BlockCode) to be considered. - Parameters: Input - + Parameters: Input: in0 (Array1D[int]): The bit sequence to be encoded. Its length must be a multiple of the code's dimension $k$. Parameters: Output: - out0 (Array1D[int]): The encoded bit sequence. Its length is a multiple of the code's block length $n$. Examples: - >>> code = komm.HammingCode(3) >>> encoder = komm.BlockEncoder(code) >>> encoder([1, 1, 0, 0, 1, 0, 1, 1]) diff --git a/src/komm/_error_control_block/CordaroWagnerCode.py b/src/komm/_error_control_block/CordaroWagnerCode.py index 1609ae63..a18bb700 100644 --- a/src/komm/_error_control_block/CordaroWagnerCode.py +++ b/src/komm/_error_control_block/CordaroWagnerCode.py @@ -17,11 +17,9 @@ class CordaroWagnerCode(BlockCode): - Minimum distance: $d = \left\lceil 2n / 3 \right\rceil - 1$ Attributes: - n: The length $n$ of the code. Must satisfy $n \geq 2$. Examples: - >>> code = komm.CordaroWagnerCode(11) >>> (code.length, code.dimension, code.minimum_distance) (11, 2, 7) diff --git a/src/komm/_error_control_block/CyclicCode.py b/src/komm/_error_control_block/CyclicCode.py index bc5198e0..febf2e9d 100644 --- a/src/komm/_error_control_block/CyclicCode.py +++ b/src/komm/_error_control_block/CyclicCode.py @@ -28,7 +28,6 @@ class CyclicCode(BlockCode): The constructor expects either the generator polynomial or the check polynomial. Parameters: - length: The length $n$ of the code. generator_polynomial: The generator polynomial $g(X)$ of the code, of degree $m$ (the redundancy of the code), specified either as a [binary polynomial](/ref/BinaryPolynomial) or as an integer to be converted to the former. @@ -38,7 +37,6 @@ class CyclicCode(BlockCode): systematic: Whether the encoder is systematic. Default is `True`. Examples: - >>> code = komm.CyclicCode(length=23, generator_polynomial=0b101011100011) # Golay (23, 12) >>> (code.length, code.dimension, code.redundancy) (23, 12, 11) diff --git a/src/komm/_error_control_block/GolayCode.py b/src/komm/_error_control_block/GolayCode.py index 7ea561f1..a3979436 100644 --- a/src/komm/_error_control_block/GolayCode.py +++ b/src/komm/_error_control_block/GolayCode.py @@ -34,17 +34,14 @@ class GolayCode(SystematicBlockCode): - Minimum distance: $7$ Notes: - - The binary Golay code is a perfect code. Attributes: - extended: If `True`, constructs the code in extended version. The default value is `False`. This function returns the code in systematic form, with the information set on the left. Examples: - >>> code = komm.GolayCode() >>> (code.length, code.dimension, code.redundancy) (23, 12, 11) diff --git a/src/komm/_error_control_block/HammingCode.py b/src/komm/_error_control_block/HammingCode.py index 1780cff9..8cd8242e 100644 --- a/src/komm/_error_control_block/HammingCode.py +++ b/src/komm/_error_control_block/HammingCode.py @@ -26,20 +26,17 @@ class HammingCode(SystematicBlockCode): For more details, see LC04, Sec. 4.1. Notes: - - For $\mu = 2$ it reduces to the [repetition code](/ref/RepetitionCode) of length $3$. - Its dual is the [simplex code](/ref/SimplexCode). - Hamming codes are perfect codes. Attributes: - mu: The parameter $\mu$ of the code. Must satisfy $\mu \geq 2$. extended: Whether to use the extended version of the Hamming code. Default is `False`. This function returns the code in systematic form, with the information set on the left. Examples: - >>> code = komm.HammingCode(3) >>> (code.length, code.dimension, code.redundancy) (7, 4, 3) diff --git a/src/komm/_error_control_block/ReedMullerCode.py b/src/komm/_error_control_block/ReedMullerCode.py index 79eeeeb5..944c1700 100644 --- a/src/komm/_error_control_block/ReedMullerCode.py +++ b/src/komm/_error_control_block/ReedMullerCode.py @@ -20,21 +20,18 @@ class ReedMullerCode(BlockCode): For more details, see LC04, Sec. 4.3. Notes: - - For $\rho = 0$ it reduces to a [repetition code](/ref/RepetitionCode). - For $\rho = 1$ it reduces to a lengthened [simplex code](/ref/SimplexCode). - For $\rho = \mu - 2$ it reduces to an extended [Hamming code](/ref/HammingCode). - For $\rho = \mu - 1$ it reduces to a [single parity check code](/ref/SingleParityCheckCode). Attributes: - rho: The parameter $\rho$ of the code. mu: The parameter $\mu$ of the code. The parameters must satisfy $0 \leq \rho < \mu$. Examples: - >>> code = komm.ReedMullerCode(1, 5) >>> (code.length, code.dimension, code.redundancy) (32, 6, 26) @@ -97,7 +94,6 @@ def reed_partitions(self): The Reed partitions of the code. See LC04, Sec. 4.3. Examples: - >>> code = komm.ReedMullerCode(2, 4) >>> code.reed_partitions[1] array([[ 0, 1, 4, 5], diff --git a/src/komm/_error_control_block/RepetitionCode.py b/src/komm/_error_control_block/RepetitionCode.py index 7227d903..5267d98b 100644 --- a/src/komm/_error_control_block/RepetitionCode.py +++ b/src/komm/_error_control_block/RepetitionCode.py @@ -18,15 +18,12 @@ class RepetitionCode(BlockCode): - Minimum distance: $d = n$ Notes: - - Its dual is the [single parity check code](/ref/SingleParityCheckCode). Attributes: - n: The length $n$ of the code. Must be a positive integer. Examples: - >>> code = komm.RepetitionCode(5) >>> (code.length, code.dimension, code.redundancy) (5, 1, 4) diff --git a/src/komm/_error_control_block/SimplexCode.py b/src/komm/_error_control_block/SimplexCode.py index 69551583..750609c7 100644 --- a/src/komm/_error_control_block/SimplexCode.py +++ b/src/komm/_error_control_block/SimplexCode.py @@ -24,20 +24,17 @@ class SimplexCode(SystematicBlockCode): - Minimum distance: $d = 2^{\kappa - 1}$ Notes: - - For $\kappa = 2$ it reduces to the [single parity check code](/ref/SingleParityCheckCode) of length $3$. - Its dual is the [Hamming code](/ref/HammingCode). - Simplex codes are constant-weight codes. Attributes: - kappa: The parameter $\kappa$ of the code. Must satisfy $\kappa \geq 2$. extended: Whether to use the extended version of the Simplex code. Default is `False`. This function constructs the code in systematic form, with the information set on the left. Examples: - >>> code = komm.SimplexCode(3) >>> (code.length, code.dimension, code.redundancy) (7, 3, 4) diff --git a/src/komm/_error_control_block/SingleParityCheckCode.py b/src/komm/_error_control_block/SingleParityCheckCode.py index fd20ade3..cef83a81 100644 --- a/src/komm/_error_control_block/SingleParityCheckCode.py +++ b/src/komm/_error_control_block/SingleParityCheckCode.py @@ -18,15 +18,12 @@ class SingleParityCheckCode(BlockCode): - Minimum distance: $d = 2$. Notes: - - Its dual is the [repetition code](/ref/RepetitionCode). Attributes: - n (int): The length $n$ of the code. Must be a positive integer. Examples: - >>> code = komm.SingleParityCheckCode(5) >>> (code.length, code.dimension, code.redundancy) (5, 4, 1) diff --git a/src/komm/_error_control_block/SystematicBlockCode.py b/src/komm/_error_control_block/SystematicBlockCode.py index f180cb87..0a5b14bd 100644 --- a/src/komm/_error_control_block/SystematicBlockCode.py +++ b/src/komm/_error_control_block/SystematicBlockCode.py @@ -15,13 +15,11 @@ class SystematicBlockCode(BlockCode): The constructor expects the parity submatrix the information set. Parameters: - parity_submatrix (Array2D[int]): The parity submatrix $P$ the code, which is a $k \times m$ binary matrix. information_set (Optional[Array1D[int] | str]): Either an array containing the indices of the information positions, which must be a $k$-sublist of $[0 : n)$, or one of the strings `'left'` or `'right'`. The default value is `'left'`. Examples: - >>> code = komm.SystematicBlockCode(parity_submatrix=[[0, 1, 1], [1, 0, 1], [1, 1, 0]]) >>> (code.length, code.dimension, code.redundancy) (6, 3, 3) diff --git a/src/komm/_error_control_block/TerminatedConvolutionalCode.py b/src/komm/_error_control_block/TerminatedConvolutionalCode.py index b9fc7f8a..93f1c2a0 100644 --- a/src/komm/_error_control_block/TerminatedConvolutionalCode.py +++ b/src/komm/_error_control_block/TerminatedConvolutionalCode.py @@ -26,7 +26,6 @@ class TerminatedConvolutionalCode(BlockCode): For more details, see LC04, Sec. 12.7 and WBR01. Attributes: - convolutional_code: The convolutional code to be terminated. num_blocks: The number $h$ of information blocks. @@ -34,7 +33,6 @@ class TerminatedConvolutionalCode(BlockCode): mode: The termination mode. It must be one of `'direct-truncation'` | `'zero-termination'` | `'tail-biting'`. The default value is `'zero-termination'`. Examples: - >>> convolutional_code = komm.ConvolutionalCode([[0b1, 0b11]]) >>> code = komm.TerminatedConvolutionalCode(convolutional_code, num_blocks=3, mode='zero-termination') diff --git a/src/komm/_error_control_convolutional/ConvolutionalCode.py b/src/komm/_error_control_convolutional/ConvolutionalCode.py index 9b5ea191..79f4e69a 100644 --- a/src/komm/_error_control_convolutional/ConvolutionalCode.py +++ b/src/komm/_error_control_convolutional/ConvolutionalCode.py @@ -78,13 +78,11 @@ def __init__(self, feedforward_polynomials, feedback_polynomials=None): Constructor for the class. Parameters: - feedforward_polynomials (Array2D[BinaryPolynomial, int]): The matrix of feedforward polynomials $P(D)$, which is a $k \times n$ matrix whose entries are either [binary polynomials](/ref/BinaryPolynomial) or integers to be converted to the former. feedback_polynomials (Optional[Array1D[BinaryPolynomial, int]]): The vector of feedback polynomials $q(D)$, which is a $k$-vector whose entries are either [binary polynomials](/ref/BinaryPolynomial) or integers to be converted to the former. The default value corresponds to no feedback, that is, $q_i(D) = 1$ for all $i \in [0 : k)$. Examples: - The convolutional code with encoder depicted in the figure below has parameters $(n, k, \nu) = (2, 1, 6)$; its transfer function matrix is given by $$ G(D) = diff --git a/src/komm/_error_control_convolutional/ConvolutionalStreamDecoder.py b/src/komm/_error_control_convolutional/ConvolutionalStreamDecoder.py index 6f34b6bf..7241b692 100644 --- a/src/komm/_error_control_convolutional/ConvolutionalStreamDecoder.py +++ b/src/komm/_error_control_convolutional/ConvolutionalStreamDecoder.py @@ -15,22 +15,18 @@ class ConvolutionalStreamDecoder: Convolutional stream decoder using Viterbi algorithm. Decode a (hard or soft) bit stream given a [convolutional code](/ref/ConvolutionalCode), assuming a traceback length (path memory) of $\tau$. At time $t$, the decoder chooses the path survivor with best metric at time $t - \tau$ and outputs the corresponding information bits. The output stream has a delay equal to $k \tau$, where $k$ is the number of input bits of the convolutional code. As a rule of thumb, the traceback length is chosen as $\tau = 5\mu$, where $\mu$ is the memory order of the convolutional code. Attributes: - convolutional_code: The convolutional code. traceback_length: The traceback length (path memory) $\tau$ of the decoder. state: The current state of the decoder. The default value is `0`. input_type: The type of the input sequence, either `hard` or `soft`. The default value is `hard`. Parameters: Input: - in0 (Array1D[int] | Array1D[float]): The (hard or soft) bit sequence to be decoded. Parameters: Output: - out0 (Array1D[int]): The decoded bit sequence. Examples: - >>> convolutional_code = komm.ConvolutionalCode([[0o7, 0o5]]) >>> convolutional_decoder = komm.ConvolutionalStreamDecoder(convolutional_code, traceback_length=10) >>> convolutional_decoder([1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1]) diff --git a/src/komm/_error_control_convolutional/ConvolutionalStreamEncoder.py b/src/komm/_error_control_convolutional/ConvolutionalStreamEncoder.py index db2a1c4b..47df3299 100644 --- a/src/komm/_error_control_convolutional/ConvolutionalStreamEncoder.py +++ b/src/komm/_error_control_convolutional/ConvolutionalStreamEncoder.py @@ -12,20 +12,16 @@ class ConvolutionalStreamEncoder: Convolutional stream encoder. Encode a bit stream using a given [convolutional code](/ref/ConvolutionalCode). The internal state of the encoder is maintained across each call. Attributes: - convolutional_code: The convolutional code. state: The current state of the encoder. The default value is `0`. Parameters: Input: - in0 (Array1D[int]): The bit sequence to be encoded. Parameters: Output: - out0 (Array1D[int]): The encoded bit sequence. Examples: - >>> convolutional_code = komm.ConvolutionalCode([[0o7, 0o5]]) >>> convolutional_encoder = komm.ConvolutionalStreamEncoder(convolutional_code) >>> convolutional_encoder([1, 1, 1, 1]) diff --git a/src/komm/_finite_state_machine/FiniteStateMachine.py b/src/komm/_finite_state_machine/FiniteStateMachine.py index 665bf2fc..4e571958 100644 --- a/src/komm/_finite_state_machine/FiniteStateMachine.py +++ b/src/komm/_finite_state_machine/FiniteStateMachine.py @@ -31,13 +31,11 @@ def __init__(self, next_states, outputs): Constructor for the class. Parameters: - next_states (Array2D[int]): The matrix of next states of the machine, of shape $|\mathcal{S}| \times |\mathcal{X}|$. The element in row $s$ and column $x$ should be the next state of the machine (an element in $\mathcal{S}$), given that the current state is $s \in \mathcal{S}$ and the input is $x \in \mathcal{X}$. outputs (Array2D[int]): The matrix of outputs of the machine, of shape $|\mathcal{S}| \times |\mathcal{X}|$. The element in row $s$ and column $x$ should be the output of the machine (an element in $\mathcal{Y}$), given that the current state is $s \in \mathcal{S}$ and the input is $x \in \mathcal{X}$. Examples: - >>> fsm = komm.FiniteStateMachine(next_states=[[0,1], [2,3], [0,1], [2,3]], outputs=[[0,3], [1,2], [3,0], [2,1]]) """ self._next_states = np.array(next_states, dtype=int) @@ -101,7 +99,6 @@ def input_edges(self): The matrix of input edges of the machine. It has shape $|\mathcal{S}| \times |\mathcal{S}|$. If there is an edge from $s_0 \in \mathcal{S}$ to $s_1 \in \mathcal{S}$, then the element in row $s_0$ and column $s_1$ is the input associated with that edge (an element of $\mathcal{X}$); if there is no such edge, then the element is $-1$. Examples: - >>> fsm = komm.FiniteStateMachine(next_states=[[0,1], [2,3], [0,1], [2,3]], outputs=[[0,3], [1,2], [3,0], [2,1]]) >>> fsm.input_edges array([[ 0, 1, -1, -1], @@ -117,7 +114,6 @@ def output_edges(self): The matrix of output edges of the machine. It has shape $|\mathcal{S}| \times |\mathcal{S}|$. If there is an edge from $s_0 \in \mathcal{S}$ to $s_1 \in \mathcal{S}$, then the element in row $s_0$ and column $s_1$ is the output associated with that edge (an element of $\mathcal{Y}$); if there is no such edge, then the element is $-1$. Examples: - >>> fsm = komm.FiniteStateMachine(next_states=[[0,1], [2,3], [0,1], [2,3]], outputs=[[0,3], [1,2], [3,0], [2,1]]) >>> fsm.output_edges array([[ 0, 3, -1, -1], @@ -132,19 +128,16 @@ def process(self, input_sequence, initial_state): Returns the output sequence corresponding to a given input sequence. It assumes the machine starts at a given initial state $s_\mathrm{i}$. The input sequence and the output sequence are denoted by $\mathbf{x} = (x_0, x_1, \ldots, x_{L-1}) \in \mathcal{X}^L$ and $\mathbf{y} = (y_0, y_1, \ldots, y_{L-1}) \in \mathcal{Y}^L$, respectively. Parameters: - input_sequence (Array1D[int]): The input sequence $\mathbf{x} \in \mathcal{X}^L$. It should be a 1D-array with elements in $\mathcal{X}$. initial_state (int): The initial state $s_\mathrm{i}$ of the machine. Should be an integer in $\mathcal{S}$. Returns: - output_sequence (Array1D[int]): The output sequence $\mathbf{y} \in \mathcal{Y}^L$ corresponding to `input_sequence`, assuming the machine starts at the state given by `initial_state`. It is a 1D-array with elements in $\mathcal{Y}$. final_state (int): The final state $s_\mathrm{f}$ of the machine. It is an integer in $\mathcal{S}$. Examples: - >>> fsm = komm.FiniteStateMachine(next_states=[[0,1], [2,3], [0,1], [2,3]], outputs=[[0,3], [1,2], [3,0], [2,1]]) >>> input_sequence, initial_state = [1, 1, 0, 1, 0], 0 >>> output_sequence, final_state = fsm.process(input_sequence, initial_state) @@ -167,7 +160,6 @@ def viterbi(self, observed_sequence, metric_function, initial_metrics=None): Applies the Viterbi algorithm on a given observed sequence. The Viterbi algorithm finds the most probable input sequence $\hat{\mathbf{x}}(s) \in \mathcal{X}^L$ ending in state $s$, for all $s \in \mathcal{S}$, given an observed sequence $\mathbf{z} \in \mathcal{Z}^L$. It is assumed uniform input priors. See LC04, Sec. 12.1. Parameters: - observed_sequence (Array1D): The observed sequence $\mathbf{z} \in \mathcal{Z}^L$. metric_function (function): The metric function $\mathcal{Y} \times \mathcal{Z} \to \mathbb{R}$. @@ -175,7 +167,6 @@ def viterbi(self, observed_sequence, metric_function, initial_metrics=None): initial_metrics (Optional[Array1D[float]]): The initial metrics for each state. It must be a 1D-array of length $|\mathcal{S}|$. The default value is `0.0` for all states. Returns: - input_sequences_hat (Array2D[int]): The most probable input sequence $\hat{\mathbf{x}}(s) \in \mathcal{X}^L$ ending in state $s$, for all $s \in \mathcal{S}$. It is a 2D-array of shape $L \times |\mathcal{S}|$, in which column $s$ is equal to $\hat{\mathbf{x}}(s)$. final_metrics (Array1D[float]): The final metrics for each state. It is a 1D-array of length $|\mathcal{S}|$. @@ -211,7 +202,6 @@ def viterbi_streaming(self, observed_sequence, metric_function, memory): Applies the streaming version of the Viterbi algorithm on a given observed sequence. The path memory (or traceback length) is denoted by $\tau$. It chooses the survivor with best metric and selects the information block on this path. See LC04, Sec. 12.3. Parameters: - observed_sequence (Array1D): The observed sequence $\mathbf{z} \in \mathcal{Z}^L$. metric_function (function): The metric function $\mathcal{Y} \times \mathcal{Z} \to \mathbb{R}$. @@ -219,7 +209,6 @@ def viterbi_streaming(self, observed_sequence, metric_function, memory): memory (dict): The metrics for each state. It must be a dictionary containing two keys: `'paths'`, a 2D-array of integers of shape $|\mathcal{S}| \times (\tau + 1)$; and `'metrics'`, a 2D-array of floats of shape $|\mathcal{S}| \times (\tau + 1)$. This dictionary is updated in-place by this method. Returns: - input_sequence_hat (Array1D[int]): The most probable input sequence $\hat{\mathbf{x}} \in \mathcal{X}^L$ """ num_states = self._num_states @@ -261,7 +250,6 @@ def forward_backward( Applies the forward-backward algorithm on a given observed sequence. The forward-backward algorithm computes the posterior pmf of each input $x_0, x_1, \ldots, x_{L-1} \in \mathcal{X}$ given an observed sequence $\mathbf{z} = (z_0, z_1, \ldots, z_{L-1}) \in \mathcal{Z}^L$. The prior pmf of each input may also be provided. See LC04, 12.6. Parameters: - observed_sequence (Array1D): The observed sequence $\mathbf{z} \in \mathcal{Z}^L$. metric_function (function): The metric function $\mathcal{Y} \times \mathcal{Z} \to \mathbb{R}$. @@ -273,7 +261,6 @@ def forward_backward( final_state_distribution (Optional[Array1D[float]]): The pmf of the final state of the machine. It must be a 1D-array of length $|\mathcal{S}|$. The default value is uniform over all states. Returns: - input_posteriors (Array2D[float]): The posterior pmf of each input, given the observed sequence, of shape $L \times |\mathcal{X}|$. The element in row $t \in [0 : L)$ and column $x \in \mathcal{X}$ is $p(x_t = x \mid \mathbf{z})$. """ L, num_states, num_input_symbols = ( diff --git a/src/komm/_modulation/APSKModulation.py b/src/komm/_modulation/APSKModulation.py index 24b5dd6a..011ba943 100644 --- a/src/komm/_modulation/APSKModulation.py +++ b/src/komm/_modulation/APSKModulation.py @@ -36,7 +36,6 @@ def __init__(self, orders, amplitudes, phase_offsets=0.0, labeling="natural"): Constructor for the class. Parameters: - orders (Tuple[int, ...]): A $K$-tuple with the orders $M_k$ of each ring, for $k \in [0 : K)$. The sum $M_0 + M_1 + \cdots + M_{K-1}$ must be a power of $2$. amplitudes (Tuple[float, ...]): A $K$-tuple with the amplitudes $A_k$ of each ring, for $k \in [0 : K)$. @@ -46,7 +45,6 @@ def __init__(self, orders, amplitudes, phase_offsets=0.0, labeling="natural"): labeling (Optional[Array1D[int] | str]): The binary labeling of the modulation. Can be specified either as a 2D-array of integers (see [base class](/ref/Modulation) for details), or as a string. In the latter case, the string must be equal to `'natural'`. The default value is `'natural'`. Examples: - >>> apsk = komm.APSKModulation(orders=(8, 8), amplitudes=(1.0, 2.0), phase_offsets=(0.0, np.pi/8)) >>> np.around(apsk.constellation, decimals=4) array([ 1. +0.j , 0.7071+0.7071j, 0. +1.j , -0.7071+0.7071j, diff --git a/src/komm/_modulation/ASKModulation.py b/src/komm/_modulation/ASKModulation.py index a7cddaea..41cb8bbf 100644 --- a/src/komm/_modulation/ASKModulation.py +++ b/src/komm/_modulation/ASKModulation.py @@ -23,7 +23,6 @@ def __init__( Constructor for the class. Parameters: - order (int): The order $M$ of the modulation. It must be a power of $2$. base_amplitude (Optional[float]): The base amplitude $A$ of the constellation. The default value is `1.0`. @@ -33,7 +32,6 @@ def __init__( labeling (Optional[Array1D[int] | str]): The binary labeling of the modulation. Can be specified either as a 2D-array of integers (see [base class](/ref/Modulation) for details), or as a string. In the latter case, the string must be either `'natural'` or `'reflected'`. The default value is `'reflected'`, corresponding to the Gray labeling. Examples: - The ASK modulation with order $M = 4$, base amplitude $A = 1$, and Gray labeling is depicted below.
diff --git a/src/komm/_modulation/Modulation.py b/src/komm/_modulation/Modulation.py index f63966ce..5844fa13 100644 --- a/src/komm/_modulation/Modulation.py +++ b/src/komm/_modulation/Modulation.py @@ -17,13 +17,11 @@ def __init__(self, constellation, labeling): Constructor for the class. Parameters: - constellation (Array1D[float] | Array1D[complex]): The constellation $\mathbf{X}$ of the modulation. Must be a 1D-array containing $M$ real or complex numbers. labeling (Array2D[int]): The binary labeling $\mathbf{Q}$ of the modulation. Must be a 2D-array of shape $(M, m)$ where each row is a distinct binary $m$-tuple. Examples: - The real modulation scheme depicted in the figure below has $M = 4$ and $m = 2$.
@@ -117,7 +115,6 @@ def constellation(self): The constellation $\mathbf{X}$ of the modulation. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.constellation array([-0.5, 0. , 0.5, 2. ]) @@ -130,7 +127,6 @@ def labeling(self): The binary labeling $\mathbf{Q}$ of the modulation. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.labeling array([[1, 0], @@ -146,7 +142,6 @@ def order(self): The order $M$ of the modulation. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.order 4 @@ -159,7 +154,6 @@ def bits_per_symbol(self): The number $m$ of bits per symbol of the modulation. It is given by $m = \log_2 M$, where $M$ is the order of the modulation. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.bits_per_symbol 2 @@ -176,7 +170,6 @@ def energy_per_symbol(self): where $|x_i|^2$ is the energy of constellation symbol $x_i$, and $M$ is the order of the modulation. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.energy_per_symbol np.float64(1.125) @@ -196,7 +189,6 @@ def energy_per_bit(self): The average bit energy $E_\mathrm{b}$ of the constellation. It assumes equiprobable symbols. It is given by $E_\mathrm{b} = E_\mathrm{s} / m$, where $E_\mathrm{s}$ is the average symbol energy, and $m$ is the number of bits per symbol of the modulation. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.energy_per_bit np.float64(0.5625) @@ -216,7 +208,6 @@ def symbol_mean(self): $$ Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.symbol_mean np.float64(0.5) @@ -236,7 +227,6 @@ def minimum_distance(self): $$ Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.minimum_distance np.float64(0.5) @@ -257,15 +247,12 @@ def modulate(self, bits): Modulates a sequence of bits to its corresponding constellation symbols. Parameters: - bits (Array1D[int]): The bits to be modulated. It should be a 1D-array of integers in the set $\\{ 0, 1 \\}$. Its length must be a multiple of $m$. Returns: - symbols (Array1D[complex] | Array1D[float]): The constellation symbols corresponding to `bits`. It is a 1D-array of real or complex numbers. Its length is equal to the length of `bits` divided by $m$. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> mod.modulate([0, 0, 1, 1, 0, 0, 1, 0]) array([ 2. , 0. , 2. , -0.5]) @@ -322,7 +309,6 @@ def demodulate(self, received, decision_method="hard", **kwargs): Demodulates a sequence of received points to a sequence of bits. Parameters: - received (Array1D[complex] | Array1D[float]): The received points to be demodulated. It should be a 1D-array of real or complex numbers. It may be of any length. decision_method (str): The decision method to be used. It should be either `'hard'` (corresponding to *hard-decision decoding*) or `'soft'` (corresponding to *soft-decision decoding*). The default value is `'hard'`. @@ -330,11 +316,9 @@ def demodulate(self, received, decision_method="hard", **kwargs): kwargs (): Keyword arguments to be passed to the demodulator. Returns: - bits_or_soft_bits (Array1D[int] | Array1D[float]): The (hard or soft) bits corresponding to `received`. In the case of hard-decision decoding, it is a 1D-array of bits (integers in the set $\\{ 0, 1 \\}$); in the case of of soft-decision decoding, it is a 1D-array of L-values (real numbers, where positive values correspond to bit $0$ and negative values correspond to bit $1$). Its length is equal to the length of `received` multiplied by $m$. Examples: - >>> mod = komm.Modulation(constellation=[-0.5, 0.0, 0.5, 2.0], labeling=[[1, 0], [1, 1], [0, 1], [0, 0]]) >>> received = [2.17, -0.06, 1.94, -0.61] diff --git a/src/komm/_modulation/PAModulation.py b/src/komm/_modulation/PAModulation.py index 1f4b2140..48dd779c 100644 --- a/src/komm/_modulation/PAModulation.py +++ b/src/komm/_modulation/PAModulation.py @@ -23,7 +23,6 @@ def __init__(self, order, base_amplitude=1.0, labeling="reflected"): Constructor for the class. Parameters: - order (int): The order $M$ of the modulation. It must be a power of $2$. base_amplitude (Optional[float]): The base amplitude $A$ of the constellation. The default value is `1.0`. @@ -31,7 +30,6 @@ def __init__(self, order, base_amplitude=1.0, labeling="reflected"): labeling (Optional[Array1D[int] | str]): The binary labeling of the modulation. Can be specified either as a 2D-array of integers (see [base class](/ref/Modulation) for details), or as a string. In the latter case, the string must be either `'natural'` or `'reflected'`. The default value is `'reflected'`, corresponding to the Gray labeling. Examples: - The PAM modulation with order $M = 4$, base amplitude $A = 1$, and Gray labeling is depicted below.
diff --git a/src/komm/_modulation/PSKModulation.py b/src/komm/_modulation/PSKModulation.py index 194f5713..64b495cd 100644 --- a/src/komm/_modulation/PSKModulation.py +++ b/src/komm/_modulation/PSKModulation.py @@ -21,7 +21,6 @@ def __init__(self, order, amplitude=1.0, phase_offset=0.0, labeling="reflected") Constructor for the class. Parameters: - order (int): The order $M$ of the modulation. It must be a power of $2$. amplitude (Optional[float]): The amplitude $A$ of the constellation. The default value is `1.0`. @@ -37,7 +36,6 @@ def __init__(self, order, amplitude=1.0, phase_offset=0.0, labeling="reflected")
Examples: - >>> psk = komm.PSKModulation(4, phase_offset=np.pi/4.0) >>> psk.constellation #doctest: +NORMALIZE_WHITESPACE array([ 0.70710678+0.70710678j, -0.70710678+0.70710678j, -0.70710678-0.70710678j, 0.70710678-0.70710678j]) diff --git a/src/komm/_modulation/QAModulation.py b/src/komm/_modulation/QAModulation.py index 8e87d242..9b9a2c54 100644 --- a/src/komm/_modulation/QAModulation.py +++ b/src/komm/_modulation/QAModulation.py @@ -35,7 +35,6 @@ def __init__( Constructor for the class. Parameters: - orders (Tuple(int, int) | int): A tuple $(M_\mathrm{I}, M_\mathrm{Q})$ with the orders of the in-phase and quadrature constellations, respectively; both $M_\mathrm{I}$ and $M_\mathrm{Q}$ must be powers of $2$. If specified as a single integer $M$, then it is assumed that $M_\mathrm{I} = M_\mathrm{Q} = \sqrt{M}$; in this case, $M$ must be an square power of $2$. base_amplitudes (Optional[Tuple(float, float) | float]): A tuple $(A_\mathrm{I}, A_\mathrm{Q})$ with the base amplitudes of the in-phase and quadrature constellations, respectively. If specified as a single float $A$, then it is assumed that $A_\mathrm{I} = A_\mathrm{Q} = A$. The default value is $1.0$. @@ -45,7 +44,6 @@ def __init__( labeling (Optional[Array1D[int] | str]): The binary labeling of the modulation. Can be specified either as a 2D-array of integers (see [base class](/ref/Modulation) for details), or as a string. In the latter case, the string must be either `'natural_2d'` or `'reflected_2d'`. The default value is `'reflected_2d'`, corresponding to the Gray labeling. Examples: - The square $16$-QAM modulation with $(M_\mathrm{I}, M_\mathrm{Q}) = (4, 4)$ and $(A_\mathrm{I}, A_\mathrm{Q}) = (1, 1)$, and Gray labeling is depicted below.
diff --git a/src/komm/_pulses/FormattingPulse.py b/src/komm/_pulses/FormattingPulse.py index 6ecac238..684aa838 100644 --- a/src/komm/_pulses/FormattingPulse.py +++ b/src/komm/_pulses/FormattingPulse.py @@ -11,7 +11,6 @@ def __init__(self, impulse_response=None, frequency_response=None, interval=None Constructor for the class. Parameters: - impulse_response (function): The impulse response of the pulse. frequency_response (function): The frequency response of the pulse. diff --git a/src/komm/_pulses/GaussianPulse.py b/src/komm/_pulses/GaussianPulse.py index a5fd7d10..a4701b23 100644 --- a/src/komm/_pulses/GaussianPulse.py +++ b/src/komm/_pulses/GaussianPulse.py @@ -28,13 +28,11 @@ def __init__(self, half_power_bandwidth, length_in_symbols): Constructor for the class. Parameters: - half_power_bandwidth (float): The half-power bandwidth $B$ of the pulse. length_in_symbols (int): The length (span) of the truncated impulse response, in symbols. Examples: - >>> pulse = komm.GaussianPulse(half_power_bandwidth=0.5, length_in_symbols=4) >>> pulse = komm.GaussianPulse(half_power_bandwidth=1.0, length_in_symbols=2) diff --git a/src/komm/_pulses/ManchesterPulse.py b/src/komm/_pulses/ManchesterPulse.py index 237b62f8..aab3c5f5 100644 --- a/src/komm/_pulses/ManchesterPulse.py +++ b/src/komm/_pulses/ManchesterPulse.py @@ -24,7 +24,6 @@ def __init__(self): Constructor for the class. It expects no parameters. Examples: - >>> pulse = komm.ManchesterPulse() """ diff --git a/src/komm/_pulses/RaisedCosinePulse.py b/src/komm/_pulses/RaisedCosinePulse.py index 7cc1bd56..ca99d35c 100644 --- a/src/komm/_pulses/RaisedCosinePulse.py +++ b/src/komm/_pulses/RaisedCosinePulse.py @@ -28,13 +28,11 @@ def __init__(self, rolloff, length_in_symbols): Constructor for the class. Parameters: - rolloff (float): The roll-off factor $\alpha$ of the pulse. Must satisfy $0 \leq \alpha \leq 1$. length_in_symbols (int): The length (span) of the truncated impulse response, in symbols. Examples: - >>> pulse = komm.RaisedCosinePulse(rolloff=0.25, length_in_symbols=16) >>> pulse = komm.RaisedCosinePulse(rolloff=0.75, length_in_symbols=16) diff --git a/src/komm/_pulses/RectangularPulse.py b/src/komm/_pulses/RectangularPulse.py index 57a13a61..46e87916 100644 --- a/src/komm/_pulses/RectangularPulse.py +++ b/src/komm/_pulses/RectangularPulse.py @@ -28,11 +28,9 @@ def __init__(self, width=1.0): Constructor for the class. Parameters: - width (Optional[float]): The width $w$ of the pulse. Must satisfy $0 \leq w \leq 1$. The default value is `1.0`. Examples: - >>> pulse = komm.RectangularPulse(width=1.0) # NRZ pulse >>> pulse = komm.RectangularPulse(width=0.5) # Halfway RZ pulse diff --git a/src/komm/_pulses/RootRaisedCosinePulse.py b/src/komm/_pulses/RootRaisedCosinePulse.py index 611dc357..1a219258 100644 --- a/src/komm/_pulses/RootRaisedCosinePulse.py +++ b/src/komm/_pulses/RootRaisedCosinePulse.py @@ -26,13 +26,11 @@ def __init__(self, rolloff, length_in_symbols): Constructor for the class. Parameters: - rolloff (float): The roll-off factor $\alpha$ of the pulse. Must satisfy $0 \leq \alpha \leq 1$. length_in_symbols (int): The length (span) of the truncated impulse response, in symbols. Examples: - >>> pulse = komm.RootRaisedCosinePulse(rolloff=0.25, length_in_symbols=16) >>> pulse = komm.RootRaisedCosinePulse(rolloff=0.75, length_in_symbols=16) diff --git a/src/komm/_pulses/SincPulse.py b/src/komm/_pulses/SincPulse.py index 357542d2..8516ab5a 100644 --- a/src/komm/_pulses/SincPulse.py +++ b/src/komm/_pulses/SincPulse.py @@ -21,11 +21,9 @@ def __init__(self, length_in_symbols): Constructor for the class. Parameters: - length_in_symbols (int): The length (span) of the truncated impulse response, in symbols. Examples: - >>> pulse = komm.SincPulse(length_in_symbols=64) """ L = self._length_in_symbols = int(length_in_symbols) diff --git a/src/komm/_pulses/TransmitFilter.py b/src/komm/_pulses/TransmitFilter.py index b050ed48..58846914 100644 --- a/src/komm/_pulses/TransmitFilter.py +++ b/src/komm/_pulses/TransmitFilter.py @@ -11,7 +11,6 @@ def __init__(self, pulse, samples_per_symbol): Constructor for the class. Parameters: - pulse (FormattingPulse): The pulse filter. samples_per_symbol (int): The number of samples (of the output) per symbol (of the input). @@ -38,11 +37,9 @@ def __call__(self, inp): Formats a sequence of symbols. Parameters: - inp (Array1D[float] | Array1D[complex]): The input signal, containing symbols of a modulation. Returns: - outp (SameAsInput): The output signal, formatted. """ sps = self._samples_per_symbol diff --git a/src/komm/_quantization/ScalarQuantizer.py b/src/komm/_quantization/ScalarQuantizer.py index 30a1b4ea..a4eec834 100644 --- a/src/komm/_quantization/ScalarQuantizer.py +++ b/src/komm/_quantization/ScalarQuantizer.py @@ -17,13 +17,11 @@ def __init__(self, levels, thresholds): Constructor for the class. Parameters: - levels (Array1D[float]): The quantizer levels $v_0, v_1, \ldots, v_{L-1}$. It should be a list floats of length $L$. thresholds (Array1D[float]): The finite quantizer thresholds $t_1, t_2, \ldots, t_{L-1}$. It should be a list of floats of length $L - 1$. Moreover, they must satisfy $v_0 < t_1 < v_1 < \cdots < t_{L - 1} < v_{L - 1}$. Examples: - The following example considers the $5$-level scalar quantizer whose characteristic (input × output) curve is depicted in the figure below.
diff --git a/src/komm/_quantization/UniformQuantizer.py b/src/komm/_quantization/UniformQuantizer.py index f6ca4df3..246a4ad7 100644 --- a/src/komm/_quantization/UniformQuantizer.py +++ b/src/komm/_quantization/UniformQuantizer.py @@ -13,7 +13,6 @@ def __init__(self, num_levels, input_peak=1.0, choice="mid-riser"): Constructor for the class. Parameters: - num_levels (int): The number of quantization levels $L$. input_peak (Optional[float]): The peak of the input signal $x_\mathrm{p}$. The default value is `1.0`. @@ -21,7 +20,6 @@ def __init__(self, num_levels, input_peak=1.0, choice="mid-riser"): choice (Optional[str]): The choice for the uniform quantizer. Must be one of `'unsigned'` | `'mid-riser'` | `'mid-tread'`. The default value is `'mid-riser'`. Examples: - >>> quantizer = komm.UniformQuantizer(num_levels=8) >>> quantizer.levels array([-0.875, -0.625, -0.375, -0.125, 0.125, 0.375, 0.625, 0.875]) diff --git a/src/komm/_sequences/BarkerSequence.py b/src/komm/_sequences/BarkerSequence.py index 65b3b5ef..0b3ed5fc 100644 --- a/src/komm/_sequences/BarkerSequence.py +++ b/src/komm/_sequences/BarkerSequence.py @@ -16,7 +16,6 @@ class BarkerSequence(BinarySequence): | $13$ | $0000011001010$ | References: - 1. https://en.wikipedia.org/wiki/Barker_code """ @@ -25,11 +24,9 @@ def __init__(self, length): Constructor for the class. Parameters: - length (int): Length of the Barker sequence. Must be in the set $\\{ 2, 3, 4, 5, 7, 11, 13 \\}$. Examples: - >>> barker = komm.BarkerSequence(length=13) >>> barker.polar_sequence array([ 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1]) diff --git a/src/komm/_sequences/BinarySequence.py b/src/komm/_sequences/BinarySequence.py index 6f62e1b5..7f28335c 100644 --- a/src/komm/_sequences/BinarySequence.py +++ b/src/komm/_sequences/BinarySequence.py @@ -13,13 +13,11 @@ def __init__(self, bit_sequence=None, polar_sequence=None): Constructor for the class. It expects *exactly one* the following parameters: Parameters: - bit_sequence (Array1D[int]): The binary sequence in bit format. Must be a 1D-array with elements in $\\{ 0, 1 \\}$. polar_sequence (Array1D[int]): The binary sequence in polar format. Must be a 1D-array with elements in $\\{ \pm 1 \\}$. Examples: - >>> seq = komm.BinarySequence(bit_sequence=[0, 1, 1, 0]) >>> seq.bit_sequence array([0, 1, 1, 0]) @@ -74,17 +72,14 @@ def autocorrelation(self, shifts=None, normalized=False): Returns the autocorrelation $R[\ell]$ of the binary sequence in polar format. See [`komm.autocorrelation`](/ref/autocorrelation) for more details. Parameters: - shifts (Optional[Array1D[int]]): See [`komm.autocorrelation`](/ref/autocorrelation). The default value yields $[0 : L)$. normalized (Optional[bool]): See [`komm.autocorrelation`](/ref/autocorrelation). The default value is `False`. Returns: - autocorrelation (Array1D[complex]): The autocorrelation $R[\ell]$ of the complex sequence. Examples: - >>> seq = komm.BinarySequence(bit_sequence=[0, 1, 1, 0]) >>> seq.autocorrelation() array([ 4, -1, -2, 1]) @@ -96,17 +91,14 @@ def cyclic_autocorrelation(self, shifts=None, normalized=False): Returns the cyclic autocorrelation $\tilde{R}[\ell]$ of the binary sequence in polar format. See [`komm.cyclic_autocorrelation`](/ref/cyclic_autocorrelation) for more details. Parameters: - shifts (Optional[Array1D[int]]): See [`komm.cyclic_autocorrelation`](/ref/cyclic_autocorrelation). The default value yields $[0 : L)$. normalized (Optional[bool]): See [`komm.cyclic_autocorrelation`](/ref/cyclic_autocorrelation). The default value is `False`. Returns: - cyclic_autocorrelation (Array1D[complex]): The cyclic autocorrelation $\tilde{R}[\ell]$ of the complex sequence. Examples: - >>> seq = komm.BinarySequence(bit_sequence=[0, 1, 1, 0]) >>> seq.cyclic_autocorrelation() array([ 4, 0, -4, 0]) diff --git a/src/komm/_sequences/ComplexSequence.py b/src/komm/_sequences/ComplexSequence.py index 5293dea2..3e9d774d 100644 --- a/src/komm/_sequences/ComplexSequence.py +++ b/src/komm/_sequences/ComplexSequence.py @@ -13,11 +13,9 @@ def __init__(self, sequence): Constructor for the class. Parameters: - sequence (Array1D[complex]): The complex sequence. Must be a 1D-array of length $L$ with elements in $\\mathbb{C}$. Examples: - >>> seq = ComplexSequence([1, 1j, -1, -1j]) >>> seq.sequence array([ 1.+0.j, 0.+1.j, -1.+0.j, -0.-1.j]) @@ -48,17 +46,14 @@ def autocorrelation(self, shifts=None, normalized=False): Returns the autocorrelation $R[\ell]$ of the complex sequence. See [`komm.autocorrelation`](/ref/autocorrelation) for more details. Parameters: - shifts (Optional[Array1D[int]]): See [`komm.autocorrelation`](/ref/autocorrelation). The default value yields $[0 : L)$. normalized (Optional[bool]): See [`komm.autocorrelation`](/ref/autocorrelation). The default value is `False`. Returns: - autocorrelation (Array1D[complex]): The autocorrelation $R[\ell]$ of the complex sequence. Examples: - >>> seq = ComplexSequence([1, 1j, -1, -1j]) >>> seq.autocorrelation(shifts=[-2, -1, 0, 1, 2]) array([-2.+0.j, 0.-3.j, 4.+0.j, 0.+3.j, -2.+0.j]) @@ -70,17 +65,14 @@ def cyclic_autocorrelation(self, shifts=None, normalized=False): Returns the cyclic autocorrelation $\tilde{R}[\ell]$ of the complex sequence. See [`komm.cyclic_autocorrelation`](/ref/cyclic_autocorrelation) for more details. Parameters: - shifts (Optional[Array1D[int]]): See [`komm.cyclic_autocorrelation`](/ref/cyclic_autocorrelation). The default value yields $[0 : L)$. normalized (Optional[bool]): See [`komm.cyclic_autocorrelation`](/ref/cyclic_autocorrelation). The default value is `False`. Returns: - cyclic_autocorrelation (Array1D[complex]): The cyclic autocorrelation $\tilde{R}[\ell]$ of the complex sequence. Examples: - >>> seq = ComplexSequence([1, 1j, -1, -1j]) >>> seq.cyclic_autocorrelation(shifts=[-2, -1, 0, 1, 2]) array([-4.+0.j, 0.-4.j, 4.+0.j, 0.+4.j, -4.+0.j]) diff --git a/src/komm/_sequences/LFSRSequence.py b/src/komm/_sequences/LFSRSequence.py index f2f30db2..970c2b87 100644 --- a/src/komm/_sequences/LFSRSequence.py +++ b/src/komm/_sequences/LFSRSequence.py @@ -27,7 +27,6 @@ class LFSRSequence(BinarySequence): where $L$ is the length of the sequence. References: - 1. https://en.wikipedia.org/wiki/Linear-feedback_shift_register 2. https://en.wikipedia.org/wiki/Maximum_length_sequence """ @@ -37,13 +36,11 @@ def __init__(self, feedback_polynomial, start_state_polynomial=0b1): Default constructor for the class. Parameters: - feedback_polynomial (BinaryPolynomial | int): The feedback polynomial of the LFSR, specified either as a [binary polynomial](/ref/BinaryPolynomial) or as an integer to be converted to the former. start_state_polynomial (Optional[BinaryPolynomial | int]): The start state polynomial of the LFSR, specified either as a [binary polynomial](/ref/BinaryPolynomial) or as an integer to be converted to the former. The default value is `0b1`. Examples: - >>> lfsr = komm.LFSRSequence(feedback_polynomial=0b100101) >>> lfsr.bit_sequence #doctest: +NORMALIZE_WHITESPACE array([0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1]) @@ -77,13 +74,11 @@ def maximum_length_sequence(cls, degree, start_state_polynomial=0b1): | $8$ | `0b100011101` | $16$ | `0b10001000000001011` | Parameters: - degree (int): The degree $n$ of the MLS. Only degrees in the range $[1 : 16]$ are implemented. start_state_polynomial (Optional[BinaryPolynomial | int]): See the corresponding parameter of the default constructor. Examples: - >>> komm.LFSRSequence.maximum_length_sequence(degree=5) LFSRSequence(feedback_polynomial=0b100101) """ diff --git a/src/komm/_sequences/WalshHadamardSequence.py b/src/komm/_sequences/WalshHadamardSequence.py index 7adfaf3a..d50146ec 100644 --- a/src/komm/_sequences/WalshHadamardSequence.py +++ b/src/komm/_sequences/WalshHadamardSequence.py @@ -51,7 +51,6 @@ class WalshHadamardSequence(BinarySequence): The Walsh–Hadamard sequence of *length* $L$ and *index* $i \in [0 : L)$ is a [binary sequence](/ref/BinarySequence) whose polar format is the $i$-th row of $H_L$, if assuming natural ordering, or $H_L^{\mathrm{s}}$, if assuming sequency ordering. References: - 1. https://en.wikipedia.org/wiki/Hadamard_matrix 2. https://en.wikipedia.org/wiki/Walsh_matrix """ @@ -61,7 +60,6 @@ def __init__(self, length, ordering="natural", index=0): Constructor for the class. Parameters: - length (int): Length $L$ of the Walsh–Hadamard sequence. Must be a power of two. ordering (Optional[str]): Ordering to be assumed. Should be one of `'natural'`, `'sequency'`, or `'dyadic'`. The default value is `'natural'`. @@ -69,7 +67,6 @@ def __init__(self, length, ordering="natural", index=0): index (Optional[int]): Index of the Walsh–Hadamard sequence, with respect to the ordering assumed. Must be in the set $[0 : L)$. The default value is `0`. Examples: - >>> walsh_hadamard = komm.WalshHadamardSequence(length=64, ordering='sequency', index=60) >>> walsh_hadamard.polar_sequence[:16] array([ 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1]) diff --git a/src/komm/_sequences/ZadoffChuSequence.py b/src/komm/_sequences/ZadoffChuSequence.py index d1ee0ae6..a5da3672 100644 --- a/src/komm/_sequences/ZadoffChuSequence.py +++ b/src/komm/_sequences/ZadoffChuSequence.py @@ -31,7 +31,6 @@ class ZadoffChuSequence(ComplexSequence): For more details, see And22. Notes: - - Theses sequences are also called *Frank–Zadoff–Chu* sequences. """ @@ -40,13 +39,11 @@ def __init__(self, length, root_index=1): Constructor for the class. Parameters: - length (int): The length $L$ of the Zadoff–Chu sequence. Must be an odd integer. root_index (Optional[int]): The root index $q$ of the Zadoff–Chu sequence. Must be in $[1:L)$. The default value is $1$. Examples: - >>> zadoff_chu = ZadoffChuSequence(5, root_index=1) >>> np.around(zadoff_chu.sequence, decimals=6) #doctest: +NORMALIZE_WHITESPACE array([ 1. +0.j , 0.309017-0.951057j, -0.809017+0.587785j, 0.309017-0.951057j, 1. +0.j ]) diff --git a/src/komm/_source_coding/FixedToVariableCode.py b/src/komm/_source_coding/FixedToVariableCode.py index 8d8e4791..ddb452e4 100644 --- a/src/komm/_source_coding/FixedToVariableCode.py +++ b/src/komm/_source_coding/FixedToVariableCode.py @@ -13,7 +13,6 @@ class FixedToVariableCode: Fixed-to-variable length code. A *fixed-to-variable length code* with *source alphabet* $\mathcal{S}$, *target alphabet* $\mathcal{T}$, and *source block size* $k$ is defined by an injective *encoding mapping* $\Enc : \mathcal{S}^k \to \mathcal{T}^+$, where the domain is the set of all $k$-tuples with entries in $\mathcal{S}$, and the co-domain is the set of all finite-length, non-empty tuples with entries in $\mathcal{T}$. Here we assume that $\mathcal{S} = [0:S)$ and $\mathcal{T} = [0:T)$, for integers $S \geq 2$ and $T \geq 2$. The elements in the image of $\Enc$ are called *codewords*. Attributes: - source_cardinality: The source cardinality $S$. target_cardinality: The target cardinality $T$. @@ -50,11 +49,9 @@ def from_enc_mapping(cls, enc_mapping: dict[Word, Word]): Constructs a fixed-to-variable length code from the encoding mapping $\Enc$. Parameters: - enc_mapping: The encoding mapping $\Enc$. See the corresponding attribute for more details. Examples: - >>> code = komm.FixedToVariableCode.from_enc_mapping({(0,): (0,), (1,): (1,0), (2,): (1,1)}) >>> code.source_cardinality, code.target_cardinality, code.source_block_size (3, 2, 1) @@ -85,13 +82,11 @@ def from_codewords(cls, source_cardinality: int, codewords: list[Word]): Constructs a fixed-to-variable length code from the source cardinality $S$ and a list of codewords. Parameters: - source_cardinality: The source cardinality $S$. Must be an integer greater than or equal to $2$. codewords: The codewords of the code. See the [corresponding property](./#codewords) for more details. Examples: - >>> code = komm.FixedToVariableCode.from_codewords(3, [(0,), (1,0), (1,1)]) >>> code.source_cardinality, code.target_cardinality, code.source_block_size (3, 2, 1) @@ -121,7 +116,6 @@ def codewords(self) -> list[Word]: The codewords of the code. It is a list of length $S^k$ containing tuples of integers in $[0:T)$. The tuple in position $i$ of `codewords` is equal to $\Enc(u)$, where $u$ is the $i$-th element in the lexicographic ordering of $[0:S)^k$. Examples: - >>> code = komm.FixedToVariableCode.from_enc_mapping({(0,): (0,), (1,): (1,0), (2,): (1,1)}) >>> code.codewords [(0,), (1, 0), (1, 1)] @@ -134,7 +128,6 @@ def inv_enc_mapping(self) -> dict[Word, Word]: The inverse encoding mapping $\Enc^{-1}$ of the code. It is a dictionary of length $S^k$ whose keys are all the codewords of the code and whose values are the corresponding source words. Examples: - >>> code = komm.FixedToVariableCode.from_codewords(3, [(0,), (1,0), (1,1)]) >>> code.inv_enc_mapping # doctest: +NORMALIZE_WHITESPACE {(0,): (0,), @@ -151,7 +144,6 @@ def is_uniquely_decodable(self) -> bool: $$ Examples: - >>> code = komm.FixedToVariableCode.from_codewords(3, [(0,), (1,0), (1,1)]) >>> code.is_uniquely_decodable() True @@ -171,7 +163,6 @@ def is_prefix_free(self) -> bool: Returns whether the code is prefix-free or not. A code is *prefix-free* if no codeword is a prefix of any other codeword. Examples: - >>> code = komm.FixedToVariableCode.from_codewords(3, [(0,), (1,0), (1,1)]) >>> code.is_prefix_free() True @@ -196,15 +187,12 @@ def rate(self, pmf) -> float: where $\bar{n}$ is the expected codeword length, assuming iid source symbols drawn from $p_X$, and $k$ is the source block size. It is measured in $T$-ary digits per source symbol. Parameters: - pmf (Array1D[float]): The (first-order) probability mass function $p_X$ to be considered. Returns: - rate: The expected rate $R$ of the code. Examples: - >>> code = komm.FixedToVariableCode.from_codewords(3, [(0,), (1,0), (1,1)]) >>> code.rate([0.5, 0.25, 0.25]) np.float64(1.5) diff --git a/src/komm/_source_coding/FixedToVariableDecoder.py b/src/komm/_source_coding/FixedToVariableDecoder.py index 49de94b0..400cc72b 100644 --- a/src/komm/_source_coding/FixedToVariableDecoder.py +++ b/src/komm/_source_coding/FixedToVariableDecoder.py @@ -12,19 +12,15 @@ class FixedToVariableDecoder: Prefix-free decoder for [fixed-to-variable length code](/ref/FixedToVariableCode). Attributes: - code: The code to be considered, which must be a prefix-free code (that is, no codeword is a prefix of another codeword). Parameters: Input: - in0 (Array1D[int]): The sequence of symbols to be decoded. Must be a 1D-array with elements in $[0:T)$, where $T$ is the target cardinality of the code. Parameters: Output: - out0 (Array1D[int]): The sequence of decoded symbols. It is a 1D-array with elements in $[0:S)$, where $S$ is the source cardinality of the code. Examples: - >>> code = komm.FixedToVariableCode.from_codewords(3, [(0,), (1,0), (1,1)]) >>> decoder = komm.FixedToVariableDecoder(code) >>> decoder([1, 0, 0, 1, 0, 0, 1, 1, 0]) diff --git a/src/komm/_source_coding/FixedToVariableEncoder.py b/src/komm/_source_coding/FixedToVariableEncoder.py index 23b9792c..3e78d8e3 100644 --- a/src/komm/_source_coding/FixedToVariableEncoder.py +++ b/src/komm/_source_coding/FixedToVariableEncoder.py @@ -11,19 +11,15 @@ class FixedToVariableEncoder: Encoder for [fixed-to-variable length code](/ref/FixedToVariableCode). Attributes: - code: The code to be considered. Parameters: Input: - in0 (Array1D[int]): The sequence of symbols to be encoded. Must be a 1D-array with elements in $[0:S)$, where $S$ is the source cardinality of the code. Parameters: Output: - out0 (Array1D[int]): The sequence of encoded symbols. It is a 1D-array with elements in $[0:T)$, where $T$ is the target cardinality of the code. Examples: - >>> code = komm.FixedToVariableCode.from_codewords(3, [(0,), (1,0), (1,1)]) >>> encoder = komm.FixedToVariableEncoder(code) >>> encoder([1, 0, 1, 0, 2, 0]) diff --git a/src/komm/_source_coding/HuffmanCode.py b/src/komm/_source_coding/HuffmanCode.py index f0271322..54710771 100644 --- a/src/komm/_source_coding/HuffmanCode.py +++ b/src/komm/_source_coding/HuffmanCode.py @@ -18,7 +18,6 @@ def HuffmanCode(pmf, source_block_size=1, policy="high"): Binary Huffman code. It is an optimal (minimal expected rate) [fixed-to-variable length code](/ref/FixedToVariableCode) for a given probability mass function. Parameters: - pmf (Array1D[float]): The probability mass function of the source. source_block_size (Optional[int]): The source block size $k$. The default value is $k = 1$. @@ -26,7 +25,6 @@ def HuffmanCode(pmf, source_block_size=1, policy="high"): policy (Optional[str]): The policy to be used when constructing the code. It must be either `'high'` (move combined symbols as high as possible) or `'low'` (move combined symbols as low as possible). The default value is `'high'`. Examples: - >>> pmf = [0.7, 0.15, 0.15] >>> code = komm.HuffmanCode(pmf) diff --git a/src/komm/_source_coding/TunstallCode.py b/src/komm/_source_coding/TunstallCode.py index c802e2fd..2a3c8684 100644 --- a/src/komm/_source_coding/TunstallCode.py +++ b/src/komm/_source_coding/TunstallCode.py @@ -15,13 +15,11 @@ def TunstallCode(pmf, target_block_size=None): Binary Tunstall code. It is an optimal (minimal expected rate) [variable-to-fixed length code](/ref/VariableToFixedCode) for a given probability mass function. Parameters: - pmf (Array1D[float]): The probability mass function of the source. target_block_size (Optional[int]): The target block size $n$. Must satisfy $2^n \geq S$, where $S$ is the cardinality of the source alphabet, given by `len(pmf)`. The default value is $n = \lceil \log_2 S \rceil$. Examples: - >>> pmf = [0.7, 0.15, 0.15] >>> code = komm.TunstallCode(pmf) diff --git a/src/komm/_source_coding/VariableToFixedCode.py b/src/komm/_source_coding/VariableToFixedCode.py index 4aa01402..32e58990 100644 --- a/src/komm/_source_coding/VariableToFixedCode.py +++ b/src/komm/_source_coding/VariableToFixedCode.py @@ -13,7 +13,6 @@ class VariableToFixedCode: Variable-to-fixed length code. A *variable-to-fixed length code* with *target alphabet* $\mathcal{T}$, *source alphabet* $\mathcal{S}$, and *target block size* $n$ is defined by a (possibly partial) injective decoding mapping $\mathrm{Dec} : \mathcal{T}^n \to \mathcal{S}^+$, where the domain is the set of all $n$-tuples with entries in $\mathcal{T}$, and the co-domain is the set of all finite-length, non-empty tuples with entries in $\mathcal{S}$. Here, we assume that $\mathcal{T} = [0:T)$ and $\mathcal{S} = [0:S)$, for integers $T \geq 2$ and $S \geq 2$. The elements in the image of $\mathrm{Dec}$ are called *sourcewords*. Attributes: - target_cardinality: The target cardinality $T$. source_cardinality: The source cardinality $S$. @@ -50,11 +49,9 @@ def from_dec_mapping(cls, dec_mapping: dict[Word, Word]): Constructs a variable-to-fixed code from the decoding map $\Dec$. Parameters: - dec_mapping: The decoding map $\Dec$. See the corresponding attribute for more details. Examples: - >>> code = komm.VariableToFixedCode.from_dec_mapping({(0,0): (0,0,0), (0,1): (0,0,1), (1,0): (0,1), (1,1): (1,)}) >>> (code.target_cardinality, code.source_cardinality, code.target_block_size) (2, 2, 2) @@ -89,13 +86,11 @@ def from_sourcewords(cls, target_cardinality: int, sourcewords: list[Word]): Constructs a variable-to-fixed code from the target cardinality $T$ and a list of sourcewords. Parameters: - target_cardinality: The target cardinality $T$. Must be an integer greater than or equal to $2$. sourcewords: The sourcewords of the code. See the [corresponding property](./#sourcewords) for more details. Examples: - >>> code = komm.VariableToFixedCode.from_sourcewords(2, [(0,0,0), (0,0,1), (0,1), (1,)]) >>> (code.target_cardinality, code.source_cardinality, code.target_block_size) (2, 2, 2) @@ -117,7 +112,6 @@ def sourcewords(self) -> list[Word]: The sourcewords of the code. It is a list of length at most $T^n$ containing tuples of integers in $[0:S)$. The tuple in position $i$ of `sourcewords` is equal to $\mathrm{Dec}(v)$, where $v$ is the $i$-th element in the lexicographic ordering of $[0:T)^n$. Examples: - >>> code = komm.VariableToFixedCode.from_dec_mapping({(0,0): (0,0,0), (0,1): (0,0,1), (1,0): (0,1), (1,1): (1,)}) >>> code.sourcewords [(0, 0, 0), (0, 0, 1), (0, 1), (1,)] @@ -130,7 +124,6 @@ def inv_dec_mapping(self) -> dict[Word, Word]: The inverse decoding mapping $\mathrm{Dec}^{-1}$ of the code. It is a dictionary of length at most $T^n$ whose keys are all the sourcewords of the code, and whose values are the corresponding target words. Examples: - >>> code = komm.VariableToFixedCode.from_sourcewords(2, [(0,0,0), (0,0,1), (0,1), (1,)]) >>> code.inv_dec_mapping # doctest: +NORMALIZE_WHITESPACE {(0, 0, 0): (0, 0), @@ -151,7 +144,6 @@ def is_prefix_free(self) -> bool: Returns whether the code is prefix-free or not. A code is *prefix-free* if no sourceword is a prefix of any other sourceword. Examples: - >>> code = komm.VariableToFixedCode.from_sourcewords(2, [(0,0,0), (0,0,1), (0,1), (1,)]) >>> code.is_prefix_free() True @@ -172,15 +164,12 @@ def rate(self, pmf) -> float: where $n$ is the target block size, and $\bar{k}$ is the expected sourceword length, assuming iid source symbols drawn from $p_X$. It is measured in $T$-ary digits per source symbol. Parameters: - pmf (Array1D[float]): The (first-order) probability mass function $p_X$ to be considered. Returns: - rate: The expected rate $R$ of the code. Examples: - >>> code = komm.VariableToFixedCode.from_sourcewords(2, [(0,0,0), (0,0,1), (0,1), (1,)]) >>> code.rate([2/3, 1/3]) np.float64(0.9473684210526315) diff --git a/src/komm/_source_coding/VariableToFixedDecoder.py b/src/komm/_source_coding/VariableToFixedDecoder.py index 8fddb010..6ece995c 100644 --- a/src/komm/_source_coding/VariableToFixedDecoder.py +++ b/src/komm/_source_coding/VariableToFixedDecoder.py @@ -11,19 +11,15 @@ class VariableToFixedDecoder: Decoder for [variable-to-fixed length code](/ref/VariableToFixedCode). Attributes: - code: The code to be considered. Parameters: Input: - in0 (Array1D[int]): The sequence of symbols to be decoded. Must be a 1D-array with elements in $[0:T)$, where $T$ is the target cardinality of the code. Parameters: Output: - out0 (Array1D[int]): The sequence of decoded symbols. It is a 1D-array with elements in $[0:S)$, where $S$ is the source cardinality of the code. Examples: - >>> code = komm.VariableToFixedCode.from_sourcewords(2, [(0,0,0), (0,0,1), (0,1), (1,)]) >>> decoder = komm.VariableToFixedDecoder(code) >>> decoder([0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0]) diff --git a/src/komm/_source_coding/VariableToFixedEncoder.py b/src/komm/_source_coding/VariableToFixedEncoder.py index 9ba0c08f..2a2e01ce 100644 --- a/src/komm/_source_coding/VariableToFixedEncoder.py +++ b/src/komm/_source_coding/VariableToFixedEncoder.py @@ -12,19 +12,15 @@ class VariableToFixedEncoder: Prefix-free encoder for [variable-to-fixed length code](/ref/VariableToFixedCode). Attributes: - code: The code to be considered. Parameters: Input: - in0 (Array1D[int]): The sequence of symbols to be encoded. Must be a 1D-array with elements in $[0:S)$, where $S$ is the source cardinality of the code. Parameters: Output: - out0 (Array1D[int]): The sequence of encoded symbols. It is a 1D-array with elements in $[0:T)$, where $T$ is the target cardinality of the code. Examples: - >>> code = komm.VariableToFixedCode.from_sourcewords(2, [(0,0,0), (0,0,1), (0,1), (1,)]) >>> encoder = komm.VariableToFixedEncoder(code) >>> encoder([0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0]) diff --git a/src/komm/_sources/DiscreteMemorylessSource.py b/src/komm/_sources/DiscreteMemorylessSource.py index c8a35c52..698cab0c 100644 --- a/src/komm/_sources/DiscreteMemorylessSource.py +++ b/src/komm/_sources/DiscreteMemorylessSource.py @@ -13,11 +13,9 @@ class DiscreteMemorylessSource: To invoke the source, call the object giving the number of symbols to be emitted as parameter (see example in the constructor below). Attributes: - pmf: The source probability mass function $p_X$. The element in position $x \in \mathcal{X}$ must be equal to $p_X(x)$. Examples: - >>> np.random.seed(42) >>> dms = komm.DiscreteMemorylessSource([0.5, 0.4, 0.1]) >>> dms(10) @@ -39,11 +37,9 @@ def entropy(self, base=2.0): Returns the source entropy $\mathrm{H}(X)$. See [`komm.entropy`](/ref/entropy) for more details. Parameters: - base (Optional[float | str]): See [`komm.entropy`](/ref/entropy). The default value is $2.0$. Examples: - >>> dms = komm.DiscreteMemorylessSource([1/2, 1/4, 1/8, 1/8]) >>> dms.entropy() np.float64(1.75) diff --git a/src/komm/_util/bit_operations.py b/src/komm/_util/bit_operations.py index b5beb06d..1c8dfde6 100644 --- a/src/komm/_util/bit_operations.py +++ b/src/komm/_util/bit_operations.py @@ -10,15 +10,12 @@ def binlist2int(binlist): Converts a bit array to its integer representation. Parameters: - binlist (List[int] | Array1D[int]): A list or array of $0$'s and $1$'s whose $i$-th element stands for the coefficient of $2^i$ in the binary representation of the output integer. Returns: - integer (int): The integer representation of the input bit array. Examples: - >>> komm.binlist2int([0, 1, 0, 1, 1]) 26 @@ -39,17 +36,14 @@ def int2binlist(integer, width=None): Converts an integer to its bit array representation. Parameters: - integer (int): The input integer. May be any nonnegative integer. width (Optional[int]): If this parameter is specified, the output will be filled with zeros on the right so that its length will be the specified value. Returns: - binlist (Array1D[int]): An array of $0$'s and $1$'s whose $i$-th element stands for the coefficient of $2^i$ in the binary representation of the input integer. Examples: - >>> komm.int2binlist(26) array([0, 1, 0, 1, 1]) diff --git a/src/komm/_util/correlation.py b/src/komm/_util/correlation.py index 755bb7c8..0f805644 100644 --- a/src/komm/_util/correlation.py +++ b/src/komm/_util/correlation.py @@ -10,7 +10,6 @@ def acorr(seq, shifts=None, normalized=False): where $x^\*\_\ell[n] = x^\*[n - \ell]$ is the complex conjugate of $x[n]$ shifted by $\ell$ positions. The autocorrelation $R[\ell]$ is even symmetric and satisfies $R[\ell] = 0$ for $|\ell| \geq L$, where $L$ is the length of the sequence. Parameters: - seq (Array1D[float] | Array1D[complex]): A 1D-array containing the sequence $x[n]$, of length $L$. shifts (Optional[Array1D[int]]): A 1D-array containing the values of $\ell$ for which the autocorrelation will be computed. The default value is `range(len(seq))`, that is, $[0 : L)$. @@ -18,11 +17,9 @@ def acorr(seq, shifts=None, normalized=False): normalized (Optional[bool]): If `True`, returns the autocorrelation divided by the sequence energy, so that $R[0] = 1$. The default value is `False`. Returns: - acorr (SameAsInput): The autocorrelation $R[\ell]$ of the sequence. Examples: - >>> komm.acorr([1.0, 2.0, 3.0, 4.0], shifts=[-2, -1, 0, 1, 2]) array([11., 20., 30., 20., 11.]) """ @@ -50,7 +47,6 @@ def cyclic_acorr(seq, shifts=None, normalized=False): where $\tilde{x}^\*\_\ell[n]$ is the complex conjugate of $x[n]$ cyclic-shifted by $\ell$ positions, and $L$ is the period of the sequence. The cyclic autocorrelation $\tilde{R}[\ell]$ is even symmetric and periodic with period $L$. Parameters: - seq (Array1D[float] | Array1D[complex]): A 1D-array containing the sequence $x[n]$, of length $L$. shifts (Optional[Array1D[int]]): A 1D-array containing the values of $\ell$ for which the cyclic autocorrelation will be computed. The default value is `range(len(seq))`, that is, $[0 : L)$. @@ -58,11 +54,9 @@ def cyclic_acorr(seq, shifts=None, normalized=False): normalized (Optional[bool]): If `True`, returns the cyclic autocorrelation divided by the sequence energy, so that $R[0] = 1$. The default value is `False`. Returns: - cyclic_acorr (SameAsInput): The cyclic autocorrelation $\tilde{R}[\ell]$ of the sequence. Examples: - >>> komm.cyclic_acorr([1.0, 2.0, 3.0, 4.0], shifts=[-2, -1, 0, 1, 2]) array([22., 24., 30., 24., 22.]) """ diff --git a/src/komm/_util/information_theory.py b/src/komm/_util/information_theory.py index d0269fdd..bfd553ba 100644 --- a/src/komm/_util/information_theory.py +++ b/src/komm/_util/information_theory.py @@ -31,17 +31,14 @@ def entropy(pmf, base: float | str = 2.0): By default, the base of the logarithm is $2$, in which case the entropy is measured in bits. For more details, see CT06, Ch. 2. Parameters: - pmf (Array1D[float]): The probability mass function $p_X$ of the random variable. It must be a valid pmf, that is, all of its values must be non-negative and sum up to $1$. base (Optional[float | str]): The base of the logarithm to be used. It must be a positive float or the string `'e'`. The default value is `2.0`. Returns: - entropy (float): The entropy $\mathrm{H}(X)$ of the random variable. Examples: - >>> komm.entropy([1/4, 1/4, 1/4, 1/4]) # doctest: +NUMBER np.float64(2.0) diff --git a/src/komm/_util/special_functions.py b/src/komm/_util/special_functions.py index 7f7b58f2..02a69246 100644 --- a/src/komm/_util/special_functions.py +++ b/src/komm/_util/special_functions.py @@ -11,16 +11,14 @@ def qfunc(x): $$ \mathrm{Q}(x) = \frac{1}{\sqrt{2\pi}} \int_x^\infty \mathrm{e}^{-u^2/2} \, \mathrm{d}u. $$ - Parameters: + Parameters: x (float | ArrayND[float]): The input to the function. May be any float or array of floats. Returns: - y (SameAsInput): The value $y = \mathrm{Q}(x)$. Examples: - >>> komm.qfunc(0.0) np.float64(0.5) @@ -35,15 +33,12 @@ def qfuncinv(y): Computes the inverse Gaussian Q-function. Parameters: - y (float | ArrayND[float]): The input to the function. Should be a float or array of floats in the real interval $[0, 1]$. Returns: - x (SameAsInput): The value $x = \mathrm{Q^{-1}}(y)$. Examples: - >>> komm.qfuncinv(0.5) np.float64(0.0)