From cb8dcd0ffb17781ded2dd294402334386b6f6889 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 15 Feb 2026 08:05:24 +0100 Subject: [PATCH 1/8] only need m=6 bits with 1011011 --- pac_encoder.hh | 2 +- pac_list_decoder.hh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pac_encoder.hh b/pac_encoder.hh index 6b642d1..8e141c5 100644 --- a/pac_encoder.hh +++ b/pac_encoder.hh @@ -22,7 +22,7 @@ class PACEncoder bool b4 = (*state >> 4) & 1; bool b6 = (*state >> 6) & 1; bool output = input ^ b1 ^ b3 ^ b4 ^ b6; - *state = ((*state & 126) << 1) | (input ? 2 : 0) | (output ? 1 : 0); + *state = ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); return output; } public: diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index ec8eb60..e1f0361 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -46,7 +46,7 @@ struct PACListTree bool b4 = (*state >> 4) & 1; bool b6 = (*state >> 6) & 1; bool output = input ^ b1 ^ b3 ^ b4 ^ b6; - *state = ((*state & 126) << 1) | (input ? 2 : 0) | (output ? 1 : 0); + *state = ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); return output; } static MAP rate0(PATH *metric, int *state, TYPE *hard, TYPE *soft) From 67355dbdb350aa4be6903ea8f3456ac70a4d1a9e Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 15 Feb 2026 09:08:17 +0100 Subject: [PATCH 2/8] init conv state with last 6 bits --- pac_encoder.hh | 9 ++++++++- pac_list_decoder.hh | 10 +++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pac_encoder.hh b/pac_encoder.hh index 8e141c5..98f73eb 100644 --- a/pac_encoder.hh +++ b/pac_encoder.hh @@ -22,7 +22,7 @@ class PACEncoder bool b4 = (*state >> 4) & 1; bool b6 = (*state >> 6) & 1; bool output = input ^ b1 ^ b3 ^ b4 ^ b6; - *state = ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); + *state = (*state & 8064) | ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); return output; } public: @@ -31,6 +31,13 @@ public: int length = 1 << level; int state = 0; int frozen = length - mesg_bits; + for (int i = 0, j = 0; i < length; i += 2) { + TYPE msg0 = rank_map[i] < frozen ? PH::one() : message[j++]; + TYPE msg1 = rank_map[i+1] < frozen ? PH::one() : message[j++]; + conv(&state, msg0 < 0); + conv(&state, msg1 < 0); + } + state |= (state & 126) << 7; for (int i = 0; i < length; i += 2) { TYPE msg0 = rank_map[i] < frozen ? PH::one() : *message++; TYPE msg1 = rank_map[i+1] < frozen ? PH::one() : *message++; diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index e1f0361..fcaa3c1 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -46,7 +46,7 @@ struct PACListTree bool b4 = (*state >> 4) & 1; bool b6 = (*state >> 6) & 1; bool output = input ^ b1 ^ b3 ^ b4 ^ b6; - *state = ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); + *state = (*state & 8064) | ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); return output; } static MAP rate0(PATH *metric, int *state, TYPE *hard, TYPE *soft) @@ -119,6 +119,7 @@ template class PACListDecoder { static_assert(MAX_M >= 5 && MAX_M <= 8); + static_assert(TYPE::SIZE == 64); typedef PolarHelper PH; typedef typename TYPE::value_type VALUE; typedef typename PH::PATH PATH; @@ -133,15 +134,14 @@ public: assert(level <= MAX_M); PATH metric[TYPE::SIZE]; int count = 0; - metric[0] = 0; - for (int k = 1; k < TYPE::SIZE; ++k) - metric[k] = 1000000; + for (int k = 0; k < TYPE::SIZE; ++k) + metric[k] = 0; int length = 1 << level; for (int i = 0; i < length; ++i) soft[length+i] = vdup(codeword[i]); int state[TYPE::SIZE]; for (int i = 0; i < TYPE::SIZE; ++i) - state[i] = 0; + state[i] = (i << 7) | (i << 1); int frozen = length - mesg_bits; switch (level) { From da6f94b7ad2a7b1ddfd340dcd2db18ffa6c9a8f4 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 15 Feb 2026 09:56:25 +0100 Subject: [PATCH 3/8] prune paths that don't match initial conv state --- pac_list_decoder.hh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index fcaa3c1..2624b0c 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -152,12 +152,21 @@ public: default: assert(false); } + for (int i = 0; i < TYPE::SIZE; ++i) + if (((state[i] & 8064) >> 7) != ((state[i] & 126) >> 1)) + metric[i] += 1000000; + int perm[TYPE::SIZE]; + CODE::insertion_sort(perm, metric, TYPE::SIZE); for (int i = 0, r = 0; rank != nullptr && i < TYPE::SIZE; ++i) { if (i > 0 && metric[i-1] != metric[i]) ++r; rank[i] = r; } - MAP acc = maps[count-1]; + MAP acc; + for (int k = 0; k < TYPE::SIZE; ++k) + acc.v[k] = perm[k]; + message[count-1] = vshuf(message[count-1], acc); + acc = vshuf(maps[count-1], acc); for (int i = count-2; i >= 0; --i) { message[i] = vshuf(message[i], acc); acc = vshuf(maps[i], acc); From 9525aa8a6abeda252367c6821d657f9f8174d383 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 15 Feb 2026 10:36:35 +0100 Subject: [PATCH 4/8] give pruned paths the same rank --- pac_list_decoder.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index 2624b0c..f567344 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -154,7 +154,7 @@ public: for (int i = 0; i < TYPE::SIZE; ++i) if (((state[i] & 8064) >> 7) != ((state[i] & 126) >> 1)) - metric[i] += 1000000; + metric[i] = 1000000; int perm[TYPE::SIZE]; CODE::insertion_sort(perm, metric, TYPE::SIZE); for (int i = 0, r = 0; rank != nullptr && i < TYPE::SIZE; ++i) { From 98959b8d9eb2dd9bdc19289a1c523221c9a83d72 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 15 Feb 2026 11:29:19 +0100 Subject: [PATCH 5/8] only start conv with the first info bit --- pac_encoder.hh | 18 +++++++++++------- pac_list_decoder.hh | 27 +++++++++++++++++---------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/pac_encoder.hh b/pac_encoder.hh index 98f73eb..573d986 100644 --- a/pac_encoder.hh +++ b/pac_encoder.hh @@ -33,16 +33,20 @@ public: int frozen = length - mesg_bits; for (int i = 0, j = 0; i < length; i += 2) { TYPE msg0 = rank_map[i] < frozen ? PH::one() : message[j++]; + if (j) + conv(&state, msg0 < 0); TYPE msg1 = rank_map[i+1] < frozen ? PH::one() : message[j++]; - conv(&state, msg0 < 0); - conv(&state, msg1 < 0); + if (j) + conv(&state, msg1 < 0); } state |= (state & 126) << 7; - for (int i = 0; i < length; i += 2) { - TYPE msg0 = rank_map[i] < frozen ? PH::one() : *message++; - TYPE msg1 = rank_map[i+1] < frozen ? PH::one() : *message++; - msg0 = 1 - 2 * conv(&state, msg0 < 0); - msg1 = 1 - 2 * conv(&state, msg1 < 0); + for (int i = 0, j = 0; i < length; i += 2) { + TYPE msg0 = rank_map[i] < frozen ? PH::one() : message[j++]; + if (j) + msg0 = 1 - 2 * conv(&state, msg0 < 0); + TYPE msg1 = rank_map[i+1] < frozen ? PH::one() : message[j++]; + if (j) + msg1 = 1 - 2 * conv(&state, msg1 < 0); codeword[i] = PH::qmul(msg0, msg1); codeword[i+1] = msg1; } diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index f567344..7544d7f 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -49,16 +49,23 @@ struct PACListTree *state = (*state & 8064) | ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); return output; } - static MAP rate0(PATH *metric, int *state, TYPE *hard, TYPE *soft) + static MAP rate0(PATH *metric, int *count, int *state, TYPE *hard, TYPE *soft) { TYPE sft = soft[1]; - for (int k = 0; k < TYPE::SIZE; ++k) - if (conv(state+k, 0) != (sft.v[k] < 0)) - metric[k] += std::abs(sft.v[k]); - TYPE hrd; - for (int k = 0; k < TYPE::SIZE; ++k) - hrd.v[k] = 1 - 2 * (state[k] & 1); - *hard = hrd; + if (*count) { + for (int k = 0; k < TYPE::SIZE; ++k) + if (conv(state+k, 0) != (sft.v[k] < 0)) + metric[k] += std::abs(sft.v[k]); + TYPE hrd; + for (int k = 0; k < TYPE::SIZE; ++k) + hrd.v[k] = 1 - 2 * (state[k] & 1); + *hard = hrd; + } else { + for (int k = 0; k < TYPE::SIZE; ++k) + if (sft.v[k] < 0) + metric[k] -= sft.v[k]; + *hard = PH::one(); + } MAP map; for (int k = 0; k < TYPE::SIZE; ++k) map.v[k] = k; @@ -102,12 +109,12 @@ struct PACListTree soft[1] = PH::prod(soft[2], soft[3]); MAP lmap, rmap; if (rank[0] < frozen) - lmap = rate0(metric, state, hard, soft); + lmap = rate0(metric, count, state, hard, soft); else lmap = rate1(metric, message, maps, count, state, hard, soft); soft[1] = PH::madd(hard[0], vshuf(soft[2], lmap), vshuf(soft[3], lmap)); if (rank[1] < frozen) - rmap = rate0(metric, state, hard+1, soft); + rmap = rate0(metric, count, state, hard+1, soft); else rmap = rate1(metric, message, maps, count, state, hard+1, soft); hard[0] = PH::qmul(vshuf(hard[0], rmap), hard[1]); From f5f1fc76b3c4ea8381e9ef2f5e9df18cadad78e9 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 15 Feb 2026 12:55:34 +0100 Subject: [PATCH 6/8] only updating metric after the first info bit --- pac_list_decoder.hh | 3 --- 1 file changed, 3 deletions(-) diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index 7544d7f..53fb8d3 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -61,9 +61,6 @@ struct PACListTree hrd.v[k] = 1 - 2 * (state[k] & 1); *hard = hrd; } else { - for (int k = 0; k < TYPE::SIZE; ++k) - if (sft.v[k] < 0) - metric[k] -= sft.v[k]; *hard = PH::one(); } MAP map; From 43508ce94e1205ca1cafe5404e8c5537f3fd5530 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Sun, 15 Feb 2026 22:49:45 +0100 Subject: [PATCH 7/8] allow larger list size for testing --- pac_list_decoder.hh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index 53fb8d3..53fc52d 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -123,7 +123,7 @@ template class PACListDecoder { static_assert(MAX_M >= 5 && MAX_M <= 8); - static_assert(TYPE::SIZE == 64); + static_assert(TYPE::SIZE >= 64); typedef PolarHelper PH; typedef typename TYPE::value_type VALUE; typedef typename PH::PATH PATH; @@ -138,14 +138,18 @@ public: assert(level <= MAX_M); PATH metric[TYPE::SIZE]; int count = 0; - for (int k = 0; k < TYPE::SIZE; ++k) + for (int k = 0; k < 64; ++k) metric[k] = 0; + for (int k = 64; k < TYPE::SIZE; ++k) + metric[k] = 1000000; int length = 1 << level; for (int i = 0; i < length; ++i) soft[length+i] = vdup(codeword[i]); int state[TYPE::SIZE]; - for (int i = 0; i < TYPE::SIZE; ++i) + for (int i = 0; i < 64; ++i) state[i] = (i << 7) | (i << 1); + for (int i = 64; i < TYPE::SIZE; ++i) + state[i] = 0; int frozen = length - mesg_bits; switch (level) { From 0c3b9111f1b9a474946547dd065dff4054855167 Mon Sep 17 00:00:00 2001 From: Ahmet Inan Date: Mon, 16 Feb 2026 09:07:02 +0100 Subject: [PATCH 8/8] do multi-round using a smaller list size --- pac_encoder.hh | 2 +- pac_list_decoder.hh | 55 +++++++++++++++++++++++-------- tests/pac_list_regression_test.cc | 4 +-- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/pac_encoder.hh b/pac_encoder.hh index 573d986..f4fdc56 100644 --- a/pac_encoder.hh +++ b/pac_encoder.hh @@ -22,7 +22,7 @@ class PACEncoder bool b4 = (*state >> 4) & 1; bool b6 = (*state >> 6) & 1; bool output = input ^ b1 ^ b3 ^ b4 ^ b6; - *state = (*state & 8064) | ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); + *state = ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); return output; } public: diff --git a/pac_list_decoder.hh b/pac_list_decoder.hh index 53fc52d..9129ea2 100644 --- a/pac_list_decoder.hh +++ b/pac_list_decoder.hh @@ -46,7 +46,7 @@ struct PACListTree bool b4 = (*state >> 4) & 1; bool b6 = (*state >> 6) & 1; bool output = input ^ b1 ^ b3 ^ b4 ^ b6; - *state = (*state & 8064) | ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); + *state = ((*state & 62) << 1) | (input ? 2 : 0) | (output ? 1 : 0); return output; } static MAP rate0(PATH *metric, int *count, int *state, TYPE *hard, TYPE *soft) @@ -123,7 +123,6 @@ template class PACListDecoder { static_assert(MAX_M >= 5 && MAX_M <= 8); - static_assert(TYPE::SIZE >= 64); typedef PolarHelper PH; typedef typename TYPE::value_type VALUE; typedef typename PH::PATH PATH; @@ -137,20 +136,49 @@ public: { assert(level <= MAX_M); PATH metric[TYPE::SIZE]; - int count = 0; - for (int k = 0; k < 64; ++k) - metric[k] = 0; - for (int k = 64; k < TYPE::SIZE; ++k) - metric[k] = 1000000; + int state[TYPE::SIZE]; + int count; int length = 1 << level; + int frozen = length - mesg_bits; + int best_metric = 1000000; + int best_round = 0; + + for (int round = 0; round < 64; ++round) { + count = 0; + metric[0] = 0; + for (int k = 1; k < TYPE::SIZE; ++k) + metric[k] = 1000000; + for (int i = 0; i < length; ++i) + soft[length+i] = vdup(codeword[i]); + state[0] = round << 1; + for (int i = 1; i < TYPE::SIZE; ++i) + state[i] = 0; + + switch (level) { + case 5: PACListTree::decode(metric, message, maps, &count, state, hard, soft, rank_map, frozen); break; + case 6: PACListTree::decode(metric, message, maps, &count, state, hard, soft, rank_map, frozen); break; + case 7: PACListTree::decode(metric, message, maps, &count, state, hard, soft, rank_map, frozen); break; + case 8: PACListTree::decode(metric, message, maps, &count, state, hard, soft, rank_map, frozen); break; + default: assert(false); + } + + for (int i = 0; i < TYPE::SIZE; ++i) { + if (round == ((state[i] & 126) >> 1) && metric[i] < best_metric) { + best_metric = metric[i]; + best_round = round; + } + } + } + + count = 0; + metric[0] = 0; + for (int k = 1; k < TYPE::SIZE; ++k) + metric[k] = 1000000; for (int i = 0; i < length; ++i) soft[length+i] = vdup(codeword[i]); - int state[TYPE::SIZE]; - for (int i = 0; i < 64; ++i) - state[i] = (i << 7) | (i << 1); - for (int i = 64; i < TYPE::SIZE; ++i) + state[0] = best_round << 1; + for (int i = 1; i < TYPE::SIZE; ++i) state[i] = 0; - int frozen = length - mesg_bits; switch (level) { case 5: PACListTree::decode(metric, message, maps, &count, state, hard, soft, rank_map, frozen); break; @@ -159,9 +187,8 @@ public: case 8: PACListTree::decode(metric, message, maps, &count, state, hard, soft, rank_map, frozen); break; default: assert(false); } - for (int i = 0; i < TYPE::SIZE; ++i) - if (((state[i] & 8064) >> 7) != ((state[i] & 126) >> 1)) + if (best_round != ((state[i] & 126) >> 1)) metric[i] = 1000000; int perm[TYPE::SIZE]; CODE::insertion_sort(perm, metric, TYPE::SIZE); diff --git a/tests/pac_list_regression_test.cc b/tests/pac_list_regression_test.cc index 5f6fac0..f831156 100644 --- a/tests/pac_list_regression_test.cc +++ b/tests/pac_list_regression_test.cc @@ -30,10 +30,10 @@ int main() const int C = 16; int K = R * N + crc_aided * C; #if 1 - const int L = 64; + const int L = 16; typedef int8_t code_type; #else - const int L = 16; + const int L = 4; typedef float code_type; #endif