Skip to content

Commit b83b700

Browse files
author
grigory
committed
Merge branch 'feature/extended-g-fast-ssc-codec'
2 parents 1cc0125 + 6b8cf22 commit b83b700

File tree

23 files changed

+483
-56
lines changed

23 files changed

+483
-56
lines changed

e_g_fast_ssc_analisys.ipynb

Lines changed: 118 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from .codec import BaseCRCPolarCodec, BasePolarCodec
2+
from .constants import *
23
from .decoder import BaseDecoder
34
from .decoding_path import DecodingPathMixin
5+
from .encoder import *
46
from .functions import *
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# LLR = 1000 is high enough to be considered as +∞ for SCAN decoding
2+
INFINITY = 1000

python_polar_coding/polar_codes/base/functions.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,21 @@ def compute_alpha(a, b):
3232
def make_hard_decision(soft_input):
3333
"""Makes hard decision based on soft input values (LLR)."""
3434
return np.array([s < 0 for s in soft_input], dtype=np.int8)
35+
36+
37+
@numba.njit
38+
def compute_left_alpha(llr):
39+
"""Compute Alpha for left node during SC-based decoding."""
40+
N = llr.size // 2
41+
left = llr[:N]
42+
right = llr[N:]
43+
return compute_alpha(left, right)
44+
45+
46+
@numba.njit
47+
def compute_right_alpha(llr, left_beta):
48+
"""Compute Alpha for right node during SC-based decoding."""
49+
N = llr.size // 2
50+
left = llr[:N]
51+
right = llr[N:]
52+
return right - (2 * left_beta - 1) * left
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .codec import EGFastSSCPolarCodec
2+
from .decoder import EGFastSSCDecoder
3+
from .functions import *
4+
from .node import EGFastSSCNode
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from python_polar_coding.polar_codes.g_fast_ssc import (
2+
GeneralizedFastSSCPolarCodec,
3+
)
4+
5+
from .decoder import EGFastSSCDecoder
6+
7+
8+
class EGFastSSCPolarCodec(GeneralizedFastSSCPolarCodec):
9+
"""Extended Generalized Fast SSC codec."""
10+
decoder_class = EGFastSSCDecoder
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from python_polar_coding.polar_codes.g_fast_ssc import (
2+
GeneralizedFastSSCDecoder,
3+
)
4+
5+
from .node import EGFastSSCNode
6+
7+
8+
class EGFastSSCDecoder(GeneralizedFastSSCDecoder):
9+
""""""
10+
node_class = EGFastSSCNode
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import numba
2+
import numpy as np
3+
4+
from ..base import compute_left_alpha
5+
6+
7+
@numba.njit
8+
def compute_left_alpha_sign(alpha: np.array) -> np.array:
9+
""""""
10+
left_alpha = compute_left_alpha(alpha)
11+
return np.sign(np.sum(left_alpha))
12+
13+
14+
@numba.njit
15+
def compute_right_alpha(alpha: np.array, left_sign: int = 1) -> np.array:
16+
"""`left_sign` is 1 or -1"""
17+
N = alpha.size // 2
18+
left_alpha = alpha[:N]
19+
right_alpha = alpha[N:]
20+
return right_alpha + left_alpha * left_sign
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import numpy as np
2+
3+
from python_polar_coding.polar_codes.g_fast_ssc import GeneralizedFastSSCNode
4+
5+
from .functions import compute_left_alpha_sign, compute_right_alpha
6+
7+
8+
class EGFastSSCNode(GeneralizedFastSSCNode):
9+
"""Decoder for Generalized Fast SSC code.
10+
11+
Based on: https://arxiv.org/pdf/1804.09508.pdf
12+
13+
"""
14+
ZERO_ANY = 'ZERO-ANY'
15+
REP_ANY = 'REP-ANY'
16+
17+
def __init__(self, *args, **kwargs):
18+
# Contains `ANY` node for ZERO_ANY or REP_ANY
19+
self.inner_node = None
20+
super().__init__(*args, **kwargs)
21+
22+
@property
23+
def is_any(self):
24+
return (
25+
self.is_zero or
26+
self.is_one or
27+
self.is_repetition or
28+
self.is_parity or
29+
self.is_g_repetition or
30+
self.is_rg_parity
31+
)
32+
33+
@property
34+
def is_zero_any(self):
35+
return self._node_type == self.ZERO_ANY
36+
37+
@property
38+
def is_rep_any(self):
39+
return self._node_type == self.REP_ANY
40+
41+
def get_node_type(self):
42+
ntype = super().get_node_type()
43+
if ntype != self.OTHER:
44+
return ntype
45+
if self._check_is_zero_any(self._mask):
46+
return self.ZERO_ANY
47+
if self._check_is_rep_any(self._mask):
48+
return self.REP_ANY
49+
return self.OTHER
50+
51+
def _check_is_zero_any(self, mask):
52+
""""""
53+
left, right = np.split(mask, 2)
54+
if not self._check_is_zero(left):
55+
return False
56+
inner_node = self.__class__(
57+
mask=right,
58+
name=self.ROOT,
59+
N_min=self.N_min,
60+
AF=self.AF
61+
)
62+
if not inner_node.is_any:
63+
return False
64+
65+
self.inner_node = inner_node
66+
return True
67+
68+
def _check_is_rep_any(self, mask):
69+
""""""
70+
left, right = np.split(mask, 2)
71+
if not self._check_is_rep(left):
72+
return False
73+
right_node = self.__class__(
74+
mask=right,
75+
name=self.ROOT,
76+
N_min=self.N_min,
77+
AF=self.AF
78+
)
79+
if not right_node.is_any:
80+
return False
81+
82+
self.inner_node = right_node
83+
return True
84+
85+
def compute_leaf_beta(self):
86+
super().compute_leaf_beta()
87+
klass = self.__class__
88+
89+
if self._node_type == klass.ZERO_ANY:
90+
self._beta = self.compute_zero_any()
91+
if self._node_type == klass.REP_ANY:
92+
self._beta = self.compute_rep_any()
93+
94+
def compute_zero_any(self):
95+
""""""
96+
right_alpha = compute_right_alpha(self.alpha, left_sign=1)
97+
98+
self.inner_node.alpha = right_alpha
99+
self.inner_node.compute_leaf_beta()
100+
101+
beta = np.zeros(self.N, dtype=np.int8)
102+
beta[:self.inner_node.N] = self.inner_node.beta
103+
beta[self.inner_node.N:] = self.inner_node.beta
104+
return beta
105+
106+
def compute_rep_any(self):
107+
""""""
108+
left_sign = compute_left_alpha_sign(self.alpha)
109+
right_alpha = compute_right_alpha(self.alpha, left_sign)
110+
111+
self.inner_node.alpha = right_alpha
112+
self.inner_node.compute_leaf_beta()
113+
114+
beta = np.zeros(self.N, dtype=np.int8)
115+
beta[:self.inner_node.N] = self.inner_node.beta
116+
beta[self.inner_node.N:] = self.inner_node.beta
117+
return beta

python_polar_coding/polar_codes/fast_ssc/decoder.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import numpy as np
22
from anytree import PreOrderIter
33

4+
from python_polar_coding.polar_codes.base.functions import (
5+
compute_left_alpha,
6+
compute_right_alpha,
7+
)
48
from python_polar_coding.polar_codes.sc import SCDecoder
59

610
from .node import FastSSCNode
@@ -18,12 +22,13 @@ def __init__(
1822
code_min_size: int = 0,
1923
):
2024
super().__init__(n=n, mask=mask, is_systematic=is_systematic)
21-
self._decoding_tree = self.node_class(
22-
mask=self.mask,
23-
N_min=code_min_size,
24-
)
25+
self._decoding_tree = self.setup_decoding_tree(code_min_size)
2526
self._position = 0
2627

28+
def setup_decoding_tree(self, N_min, **kwargs):
29+
"""Setup decoding tree."""
30+
return self.node_class(mask=self.mask, N_min=N_min)
31+
2732
def _set_initial_state(self, received_llr):
2833
"""Initialize decoder with received message."""
2934
self.current_state = np.zeros(self.n, dtype=np.int8)
@@ -70,15 +75,19 @@ def compute_intermediate_alpha(self, leaf):
7075
if node.is_computed:
7176
continue
7277

78+
# No need to compute zero node because output is vector of zeros
79+
if node.is_zero:
80+
continue
81+
7382
parent_alpha = node.parent.alpha
7483

7584
if node.is_left:
76-
node.alpha = self._compute_left_alpha(parent_alpha)
85+
node.alpha = compute_left_alpha(parent_alpha)
7786
continue
7887

7988
left_node = node.siblings[0]
8089
left_beta = left_node.beta
81-
node.alpha = self._compute_right_alpha(parent_alpha, left_beta)
90+
node.alpha = compute_right_alpha(parent_alpha, left_beta)
8291
node.is_computed = True
8392

8493
def compute_intermediate_beta(self, node):

0 commit comments

Comments
 (0)