1use super::{Message, SentMessage};
31use std::convert::identity;
32
33pub trait DecoderArithmetic: std::fmt::Debug + Send {
45 type Llr: std::fmt::Debug + Copy + Default + Send;
49 type CheckMessage: std::fmt::Debug + Copy + Default + Send;
53 type VarMessage: std::fmt::Debug + Copy + Default + Send;
57 type VarLlr: std::fmt::Debug + Copy + Default + Send;
62
63 fn input_llr_quantize(&self, llr: f64) -> Self::Llr;
68
69 fn llr_hard_decision(&self, llr: Self::Llr) -> bool;
73
74 fn llr_to_var_message(&self, llr: Self::Llr) -> Self::VarMessage;
80
81 fn llr_to_var_llr(&self, llr: Self::Llr) -> Self::VarLlr;
85
86 fn var_llr_to_llr(&self, var_llr: Self::VarLlr) -> Self::Llr;
90
91 fn send_check_messages<F>(&mut self, var_messages: &[Message<Self::VarMessage>], send: F)
101 where
102 F: FnMut(SentMessage<Self::CheckMessage>);
103
104 fn send_var_messages<F>(
117 &mut self,
118 input_llr: Self::Llr,
119 check_messages: &[Message<Self::CheckMessage>],
120 send: F,
121 ) -> Self::Llr
122 where
123 F: FnMut(SentMessage<Self::VarMessage>);
124
125 fn update_check_messages_and_vars(
133 &mut self,
134 check_messages: &mut [SentMessage<Self::CheckMessage>],
135 vars: &mut [Self::VarLlr],
136 );
137}
138
139fn send_var_messages_no_clip<T, F>(input_llr: T, check_messages: &[Message<T>], mut send: F) -> T
141where
142 T: std::iter::Sum + std::ops::Add<Output = T> + std::ops::Sub<Output = T> + Copy,
143 F: FnMut(SentMessage<T>),
144{
145 let llr: T = input_llr + check_messages.iter().map(|m| m.value).sum::<T>();
147 for msg in check_messages.iter() {
150 send(SentMessage {
151 dest: msg.source,
152 value: llr - msg.value,
153 });
154 }
155 llr
156}
157
158macro_rules! impl_phif {
159 ($ty:ident, $f:ty, $min_x:expr) => {
160 #[derive(Debug, Clone, Default)]
168 pub struct $ty {
169 phis: Vec<$f>,
170 }
171
172 impl $ty {
173 pub fn new() -> $ty {
175 <$ty>::default()
176 }
177 }
178
179 impl $ty {
180 fn phi(x: $f) -> $f {
181 let x = x.max($min_x);
184 -((0.5 * x).tanh().ln())
185 }
186 }
187
188 impl DecoderArithmetic for $ty {
189 type Llr = $f;
190 type CheckMessage = $f;
191 type VarMessage = $f;
192 type VarLlr = $f;
193
194 fn input_llr_quantize(&self, llr: f64) -> $f {
195 llr as $f
196 }
197
198 fn llr_hard_decision(&self, llr: $f) -> bool {
199 llr <= 0.0
200 }
201
202 fn llr_to_var_message(&self, llr: $f) -> $f {
203 llr
204 }
205
206 fn llr_to_var_llr(&self, llr: $f) -> $f {
207 llr
208 }
209
210 fn var_llr_to_llr(&self, var_llr: $f) -> $f {
211 var_llr
212 }
213
214 fn send_check_messages<F>(&mut self, var_messages: &[Message<$f>], mut send: F)
215 where
216 F: FnMut(SentMessage<$f>),
217 {
218 let mut sign: u32 = 0;
220 let mut sum = 0.0;
221 if self.phis.len() < var_messages.len() {
222 self.phis.resize(var_messages.len(), 0.0);
223 }
224 for (msg, phi) in var_messages.iter().zip(self.phis.iter_mut()) {
225 let x = msg.value;
226 let phi_x = Self::phi(x.abs());
227 *phi = phi_x;
228 sum += phi_x;
229 if x < 0.0 {
230 sign ^= 1;
231 }
232 }
233
234 for (msg, phi) in var_messages.iter().zip(self.phis.iter()) {
237 let x = msg.value;
238 let y = Self::phi(sum - phi);
239 let s = if x < 0.0 { sign ^ 1 } else { sign };
240 let val = if s == 0 { y } else { -y };
241 send(SentMessage {
242 dest: msg.source,
243 value: val,
244 });
245 }
246 }
247
248 fn send_var_messages<F>(
249 &mut self,
250 input_llr: $f,
251 check_messages: &[Message<$f>],
252 send: F,
253 ) -> $f
254 where
255 F: FnMut(SentMessage<$f>),
256 {
257 send_var_messages_no_clip(input_llr, check_messages, send)
258 }
259
260 fn update_check_messages_and_vars(
261 &mut self,
262 check_messages: &mut [SentMessage<$f>],
263 vars: &mut [$f],
264 ) {
265 let mut sign: u32 = 0;
267 let mut sum = 0.0;
268 if self.phis.len() < check_messages.len() {
269 self.phis.resize(check_messages.len(), 0.0);
270 }
271 for (msg, phi) in check_messages.iter().zip(self.phis.iter_mut()) {
272 let x = vars[msg.dest] - msg.value;
274 let phi_x = Self::phi(x.abs());
275 *phi = phi_x;
276 sum += phi_x;
277 if x < 0.0 {
278 sign ^= 1;
279 }
280 }
281
282 for (msg, phi) in check_messages.iter_mut().zip(self.phis.iter()) {
285 let x = vars[msg.dest] - msg.value;
286 let rcv = Self::phi(sum - phi);
287 let s = if x < 0.0 { sign ^ 1 } else { sign };
288 let rcv = if s == 0 { rcv } else { -rcv };
289 msg.value = rcv;
290 vars[msg.dest] = x + rcv;
291 }
292 }
293 }
294 };
295}
296
297impl_phif!(Phif64, f64, 1e-30);
298impl_phif!(Phif32, f32, 1e-30);
299
300macro_rules! impl_tanhf {
301 ($ty:ident, $f:ty, $tanh_clamp:expr) => {
302 #[derive(Debug, Clone, Default)]
310 pub struct $ty {
311 tanhs: Vec<$f>,
312 }
313
314 impl $ty {
315 pub fn new() -> $ty {
317 <$ty>::default()
318 }
319 }
320
321 impl DecoderArithmetic for $ty {
322 type Llr = $f;
323 type CheckMessage = $f;
324 type VarMessage = $f;
325 type VarLlr = $f;
326
327 fn input_llr_quantize(&self, llr: f64) -> $f {
328 llr as $f
329 }
330
331 fn llr_hard_decision(&self, llr: $f) -> bool {
332 llr <= 0.0
333 }
334
335 fn llr_to_var_message(&self, llr: $f) -> $f {
336 llr
337 }
338
339 fn llr_to_var_llr(&self, llr: $f) -> $f {
340 llr
341 }
342
343 fn var_llr_to_llr(&self, var_llr: $f) -> $f {
344 var_llr
345 }
346
347 fn send_check_messages<F>(&mut self, var_messages: &[Message<$f>], mut send: F)
348 where
349 F: FnMut(SentMessage<$f>),
350 {
351 if self.tanhs.len() < var_messages.len() {
353 self.tanhs.resize(var_messages.len(), 0.0);
354 }
355 for (msg, tanh) in var_messages.iter().zip(self.tanhs.iter_mut()) {
356 let x = msg.value;
357 let t = (0.5 * x).clamp(-$tanh_clamp, $tanh_clamp).tanh();
358 *tanh = t;
359 }
360
361 for exclude_msg in var_messages.iter() {
362 let product = var_messages
364 .iter()
365 .zip(self.tanhs.iter())
366 .filter_map(|(msg, tanh)| {
367 if msg.source != exclude_msg.source {
368 Some(tanh)
369 } else {
370 None
371 }
372 })
373 .product::<$f>();
374 send(SentMessage {
375 dest: exclude_msg.source,
376 value: 2.0 * product.atanh(),
377 })
378 }
379 }
380
381 fn send_var_messages<F>(
382 &mut self,
383 input_llr: $f,
384 check_messages: &[Message<$f>],
385 send: F,
386 ) -> $f
387 where
388 F: FnMut(SentMessage<$f>),
389 {
390 send_var_messages_no_clip(input_llr, check_messages, send)
391 }
392
393 fn update_check_messages_and_vars(
394 &mut self,
395 check_messages: &mut [SentMessage<$f>],
396 vars: &mut [$f],
397 ) {
398 if self.tanhs.len() < check_messages.len() {
400 self.tanhs.resize(check_messages.len(), 0.0);
401 }
402 for (msg, tanh) in check_messages.iter().zip(self.tanhs.iter_mut()) {
403 let x = vars[msg.dest] - msg.value;
404 let t = (0.5 * x).clamp(-$tanh_clamp, $tanh_clamp).tanh();
405 *tanh = t;
406 }
407
408 for j in 0..check_messages.len() {
409 let exclude_msg = &check_messages[j];
411 let product = check_messages
412 .iter()
413 .zip(self.tanhs.iter())
414 .filter_map(|(msg, tanh)| {
415 if msg.dest != exclude_msg.dest {
416 Some(tanh)
417 } else {
418 None
419 }
420 })
421 .product::<$f>();
422 let rcv = 2.0 * product.atanh();
423 vars[exclude_msg.dest] += rcv - exclude_msg.value;
424 check_messages[j].value = rcv;
425 }
426 }
427 }
428 };
429}
430
431impl_tanhf!(Tanhf64, f64, 18.0);
434impl_tanhf!(Tanhf32, f32, 9.0);
436
437macro_rules! impl_minstarapproxf {
438 ($ty:ident, $f:ty) => {
439 #[derive(Debug, Clone, Default)]
450 pub struct $ty {
451 minstars: Vec<$f>,
452 }
453
454 impl $ty {
455 pub fn new() -> $ty {
457 <$ty>::default()
458 }
459 }
460
461 impl DecoderArithmetic for $ty {
462 type Llr = $f;
463 type CheckMessage = $f;
464 type VarMessage = $f;
465 type VarLlr = $f;
466
467 fn input_llr_quantize(&self, llr: f64) -> $f {
468 llr as $f
469 }
470
471 fn llr_hard_decision(&self, llr: $f) -> bool {
472 llr <= 0.0
473 }
474
475 fn llr_to_var_message(&self, llr: $f) -> $f {
476 llr
477 }
478
479 fn llr_to_var_llr(&self, llr: $f) -> $f {
480 llr
481 }
482
483 fn var_llr_to_llr(&self, var_llr: $f) -> $f {
484 var_llr
485 }
486
487 fn send_check_messages<F>(&mut self, var_messages: &[Message<$f>], mut send: F)
488 where
489 F: FnMut(SentMessage<$f>),
490 {
491 for exclude_msg in var_messages.iter() {
492 let mut sign: u32 = 0;
493 let mut minstar = None;
494 for msg in var_messages
495 .iter()
496 .filter(|msg| msg.source != exclude_msg.source)
497 {
498 let x = msg.value;
499 if x < 0.0 {
500 sign ^= 1;
501 }
502 let x = x.abs();
503 minstar = Some(match minstar {
504 None => x,
505 Some(y) => (x.min(y) - (-(x - y).abs()).exp().ln_1p()).max(0.0),
511 });
512 }
513 let minstar =
514 minstar.expect("only one variable message connected to check node");
515 let minstar = if sign == 0 { minstar } else { -minstar };
516 send(SentMessage {
517 dest: exclude_msg.source,
518 value: minstar,
519 })
520 }
521 }
522
523 fn send_var_messages<F>(
524 &mut self,
525 input_llr: $f,
526 check_messages: &[Message<$f>],
527 send: F,
528 ) -> $f
529 where
530 F: FnMut(SentMessage<$f>),
531 {
532 send_var_messages_no_clip(input_llr, check_messages, send)
533 }
534
535 fn update_check_messages_and_vars(
536 &mut self,
537 check_messages: &mut [SentMessage<$f>],
538 vars: &mut [$f],
539 ) {
540 if self.minstars.len() < check_messages.len() {
542 self.minstars.resize(check_messages.len(), 0.0);
543 }
544 for (exclude_msg, minstar) in check_messages.iter().zip(self.minstars.iter_mut()) {
545 let mut sign: u32 = 0;
546 let mut mstar = None;
547 for msg in check_messages
548 .iter()
549 .filter(|msg| msg.dest != exclude_msg.dest)
550 {
551 let x = vars[msg.dest] - msg.value;
552 if x < 0.0 {
553 sign ^= 1;
554 }
555 let x = x.abs();
556 mstar = Some(match mstar {
557 None => x,
558 Some(y) => (x.min(y) - (-(x - y).abs()).exp().ln_1p()).max(0.0),
564 });
565 }
566 let mstar = mstar.expect("only one variable message connected to check node");
567 *minstar = if sign == 0 { mstar } else { -mstar };
568 }
569 for (msg, &minstar) in check_messages.iter_mut().zip(self.minstars.iter()) {
571 vars[msg.dest] += minstar - msg.value;
572 msg.value = minstar;
573 }
574 }
575 }
576 };
577}
578
579impl_minstarapproxf!(Minstarapproxf64, f64);
580impl_minstarapproxf!(Minstarapproxf32, f32);
581
582macro_rules! impl_8bitquant {
583 ($ty:ident) => {
584 impl $ty {
585 const QUANTIZER_C: f64 = 8.0;
586
587 pub fn new() -> $ty {
589 let table = (0..=127)
590 .map_while(|t| {
591 let x = (Self::QUANTIZER_C
592 * (-(t as f64 / Self::QUANTIZER_C)).exp().ln_1p())
593 .round() as i8;
594 if x > 0 { Some(x) } else { None }
595 })
596 .collect::<Vec<_>>()
597 .into_boxed_slice();
598 $ty {
599 table,
600 _minstars: Vec::new(),
601 }
602 }
603
604 fn lookup(table: &[i8], x: i8) -> i8 {
605 assert!(x >= 0);
606 table.get(x as usize).copied().unwrap_or(0)
607 }
608
609 fn clip(x: i16) -> i8 {
610 if x >= 127 {
611 127
612 } else if x <= -127 {
613 -127
614 } else {
615 x as i8
616 }
617 }
618 }
619 };
620}
621
622macro_rules! impl_send_var_messages_i8 {
623 ($degree_one_clip:expr, $jones_clip:expr) => {
624 #[allow(clippy::redundant_closure_call)]
625 fn send_var_messages<F>(
626 &mut self,
627 input_llr: i8,
628 check_messages: &[Message<i8>],
629 mut send: F,
630 ) -> i8
631 where
632 F: FnMut(SentMessage<i8>),
633 {
634 let degree_one = check_messages.len() == 1;
635 let llr = i16::from($degree_one_clip(input_llr, degree_one))
637 + check_messages
638 .iter()
639 .map(|m| i16::from(m.value))
640 .sum::<i16>();
641 let llr = $jones_clip(llr);
643 for msg in check_messages.iter() {
646 send(SentMessage {
647 dest: msg.source,
648 value: Self::clip(llr - i16::from(msg.value)),
649 });
650 }
651 Self::clip(llr)
652 }
653 };
654}
655
656macro_rules! impl_minstarapproxi8 {
657 ($ty:ident, $jones_clip:expr, $check_hardlimit:expr, $degree_one_clip:expr) => {
658 #[derive(Debug, Clone)]
667 pub struct $ty {
668 table: Box<[i8]>,
669 _minstars: Vec<i8>,
670 }
671
672 impl_8bitquant!($ty);
673
674 impl Default for $ty {
675 fn default() -> $ty {
676 <$ty>::new()
677 }
678 }
679
680 impl DecoderArithmetic for $ty {
681 type Llr = i8;
682 type CheckMessage = i8;
683 type VarMessage = i8;
684 type VarLlr = i16;
689
690 fn input_llr_quantize(&self, llr: f64) -> i8 {
691 let x = Self::QUANTIZER_C * llr;
692 if x >= 127.0 {
693 127
694 } else if x <= -127.0 {
695 -127
696 } else {
697 x.round() as i8
698 }
699 }
700
701 fn llr_hard_decision(&self, llr: i8) -> bool {
702 llr <= 0
703 }
704
705 fn llr_to_var_message(&self, llr: i8) -> i8 {
706 llr
707 }
708
709 fn llr_to_var_llr(&self, llr: i8) -> i16 {
710 i16::from(llr)
711 }
712
713 fn var_llr_to_llr(&self, var_llr: i16) -> i8 {
714 Self::clip(var_llr)
715 }
716
717 #[allow(clippy::redundant_closure_call)]
718 fn send_check_messages<F>(&mut self, var_messages: &[Message<i8>], mut send: F)
719 where
720 F: FnMut(SentMessage<i8>),
721 {
722 for exclude_msg in var_messages.iter() {
723 let mut sign: u32 = 0;
724 let mut minstar = None;
725 for msg in var_messages
726 .iter()
727 .filter(|msg| msg.source != exclude_msg.source)
728 {
729 let x = msg.value;
730 if x < 0 {
731 sign ^= 1;
732 }
733 let x = x.abs();
734 minstar = Some(match minstar {
735 None => x,
736 Some(y) => (x.min(y) - Self::lookup(&self.table, (x - y).abs())).max(0),
742 });
743 }
744 let minstar =
745 minstar.expect("only one variable message connected to check node");
746 let minstar = if sign == 0 { minstar } else { -minstar };
747 let minstar = $check_hardlimit(minstar);
749 send(SentMessage {
750 dest: exclude_msg.source,
751 value: minstar,
752 })
753 }
754 }
755
756 impl_send_var_messages_i8!($degree_one_clip, $jones_clip);
757
758 #[allow(clippy::redundant_closure_call)]
759 fn update_check_messages_and_vars(
760 &mut self,
761 check_messages: &mut [SentMessage<i8>],
762 vars: &mut [i16],
763 ) {
764 if self._minstars.len() < check_messages.len() {
766 self._minstars.resize(check_messages.len(), 0);
767 }
768 for (exclude_msg, minstar) in check_messages.iter().zip(self._minstars.iter_mut()) {
769 let mut sign: u32 = 0;
770 let mut mstar = None;
771 for msg in check_messages
772 .iter()
773 .filter(|msg| msg.dest != exclude_msg.dest)
774 {
775 let x = Self::clip(vars[msg.dest] - i16::from(msg.value));
776 if x < 0 {
777 sign ^= 1;
778 }
779 let x = x.abs();
780 mstar = Some(match mstar {
781 None => x,
782 Some(y) => (x.min(y) - Self::lookup(&self.table, (x - y).abs())).max(0),
788 });
789 }
790 let mstar = mstar.expect("only one variable message connected to check node");
791 let mstar = if sign == 0 { mstar } else { -mstar };
792 let mstar = $check_hardlimit(mstar);
794 *minstar = mstar;
795 }
796 for (msg, &minstar) in check_messages.iter_mut().zip(self._minstars.iter()) {
798 vars[msg.dest] += i16::from(minstar) - i16::from(msg.value);
799 msg.value = minstar;
800 }
801 }
802 }
803 };
804}
805
806macro_rules! jones_clip {
807 () => {
808 |x| i16::from(Self::clip(x))
809 };
810}
811
812macro_rules! partial_hard_limit {
813 () => {
814 |x| {
815 if x <= -100 {
816 -127
817 } else if x >= 100 {
818 127
819 } else {
820 x
821 }
822 }
823 };
824}
825
826macro_rules! degree_one_clipping {
827 () => {
828 |x, degree_one| {
829 if degree_one {
830 if x <= -116 {
831 -116
832 } else if x >= 116 {
833 116
834 } else {
835 x
836 }
837 } else {
838 x
839 }
840 }
841 };
842}
843
844macro_rules! degree_one_no_clipping {
845 () => {
846 |x, _| x
847 };
848}
849
850impl_minstarapproxi8!(
851 Minstarapproxi8,
852 identity,
853 identity,
854 degree_one_no_clipping!()
855);
856impl_minstarapproxi8!(
857 Minstarapproxi8Jones,
858 jones_clip!(),
859 identity,
860 degree_one_no_clipping!()
861);
862impl_minstarapproxi8!(
863 Minstarapproxi8PartialHardLimit,
864 identity,
865 partial_hard_limit!(),
866 degree_one_no_clipping!()
867);
868impl_minstarapproxi8!(
869 Minstarapproxi8JonesPartialHardLimit,
870 jones_clip!(),
871 partial_hard_limit!(),
872 degree_one_no_clipping!()
873);
874impl_minstarapproxi8!(
875 Minstarapproxi8Deg1Clip,
876 identity,
877 identity,
878 degree_one_clipping!()
879);
880impl_minstarapproxi8!(
881 Minstarapproxi8JonesDeg1Clip,
882 jones_clip!(),
883 identity,
884 degree_one_clipping!()
885);
886impl_minstarapproxi8!(
887 Minstarapproxi8PartialHardLimitDeg1Clip,
888 identity,
889 partial_hard_limit!(),
890 degree_one_clipping!()
891);
892impl_minstarapproxi8!(
893 Minstarapproxi8JonesPartialHardLimitDeg1Clip,
894 jones_clip!(),
895 partial_hard_limit!(),
896 degree_one_clipping!()
897);
898
899macro_rules! impl_aminstarf {
900 ($ty:ident, $f:ty) => {
901 #[derive(Debug, Clone, Default)]
907 pub struct $ty {}
908
909 impl $ty {
910 pub fn new() -> $ty {
912 <$ty>::default()
913 }
914 }
915
916 impl DecoderArithmetic for $ty {
917 type Llr = $f;
918 type CheckMessage = $f;
919 type VarMessage = $f;
920 type VarLlr = $f;
921
922 fn input_llr_quantize(&self, llr: f64) -> $f {
923 llr as $f
924 }
925
926 fn llr_hard_decision(&self, llr: $f) -> bool {
927 llr <= 0.0
928 }
929
930 fn llr_to_var_message(&self, llr: $f) -> $f {
931 llr
932 }
933
934 fn llr_to_var_llr(&self, llr: $f) -> $f {
935 llr
936 }
937
938 fn var_llr_to_llr(&self, var_llr: $f) -> $f {
939 var_llr
940 }
941
942 fn send_check_messages<F>(&mut self, var_messages: &[Message<$f>], mut send: F)
943 where
944 F: FnMut(SentMessage<$f>),
945 {
946 let (argmin, msgmin) = var_messages
947 .iter()
948 .enumerate()
949 .min_by(|(_, msg1), (_, msg2)| {
950 msg1.value.abs().partial_cmp(&msg2.value.abs()).unwrap()
951 })
952 .expect("var_messages is empty");
953 let mut sign: u32 = 0;
954 let mut delta = None;
955 for (j, msg) in var_messages.iter().enumerate() {
956 let x = msg.value;
957 if x < 0.0 {
958 sign ^= 1;
959 }
960 if j != argmin {
961 let x = x.abs();
962 delta = Some(match delta {
963 None => x,
964 Some(y) => {
965 (x.min(y) - (-(x - y).abs()).exp().ln_1p()
966 + (-(x + y)).exp().ln_1p())
967 }
968 });
969 }
970 }
971 let delta = delta.expect("var_messages_empty");
972
973 send(SentMessage {
974 dest: msgmin.source,
975 value: if (sign != 0) ^ (msgmin.value < 0.0) {
976 -delta
977 } else {
978 delta
979 },
980 });
981
982 let vmin = msgmin.value.abs();
983 let delta = delta.min(vmin) - (-(delta - vmin).abs()).exp().ln_1p()
984 + (-(delta + vmin)).exp().ln_1p();
985 for msg in var_messages
986 .iter()
987 .enumerate()
988 .filter_map(|(j, msg)| if j != argmin { Some(msg) } else { None })
989 {
990 send(SentMessage {
991 dest: msg.source,
992 value: if (sign != 0) ^ (msg.value < 0.0) {
993 -delta
994 } else {
995 delta
996 },
997 });
998 }
999 }
1000
1001 fn send_var_messages<F>(
1002 &mut self,
1003 input_llr: $f,
1004 check_messages: &[Message<$f>],
1005 send: F,
1006 ) -> $f
1007 where
1008 F: FnMut(SentMessage<$f>),
1009 {
1010 send_var_messages_no_clip(input_llr, check_messages, send)
1011 }
1012
1013 fn update_check_messages_and_vars(
1014 &mut self,
1015 check_messages: &mut [SentMessage<$f>],
1016 vars: &mut [$f],
1017 ) {
1018 let (argmin, msgmin) = check_messages
1019 .iter()
1020 .map(|msg| vars[msg.dest] - msg.value)
1021 .enumerate()
1022 .min_by(|(_, msg1), (_, msg2)| msg1.abs().partial_cmp(&msg2.abs()).unwrap())
1023 .expect("var_messages is empty");
1024 let mut sign: u32 = 0;
1025 let mut delta = None;
1026 for (j, msg) in check_messages.iter().enumerate() {
1027 let x = vars[msg.dest] - msg.value;
1028 if x < 0.0 {
1029 sign ^= 1;
1030 }
1031 if j != argmin {
1032 let x = x.abs();
1033 delta = Some(match delta {
1034 None => x,
1035 Some(y) => {
1036 (x.min(y) - (-(x - y).abs()).exp().ln_1p()
1037 + (-(x + y)).exp().ln_1p())
1038 }
1039 });
1040 }
1041 }
1042 let delta = delta.expect("var_messages_empty");
1043 let msgmin_rcv = if (sign != 0) ^ (msgmin < 0.0) {
1044 -delta
1045 } else {
1046 delta
1047 };
1048
1049 let vmin = msgmin.abs();
1050 let delta = delta.min(vmin) - (-(delta - vmin).abs()).exp().ln_1p()
1051 + (-(delta + vmin)).exp().ln_1p();
1052 for (j, msg) in check_messages.iter_mut().enumerate() {
1053 let x = vars[msg.dest] - msg.value;
1054 let rcv = if j == argmin {
1055 msgmin_rcv
1056 } else {
1057 if (sign != 0) ^ (x < 0.0) {
1058 -delta
1059 } else {
1060 delta
1061 }
1062 };
1063 msg.value = rcv;
1064 vars[msg.dest] = x + rcv;
1065 }
1066 }
1067 }
1068 };
1069}
1070
1071impl_aminstarf!(Aminstarf64, f64);
1072impl_aminstarf!(Aminstarf32, f32);
1073
1074macro_rules! impl_aminstari8 {
1075 ($ty:ident, $jones_clip:expr, $check_hardlimit:expr, $degree_one_clip:expr) => {
1076 #[derive(Debug, Clone)]
1083 pub struct $ty {
1084 table: Box<[i8]>,
1085 _minstars: Vec<i8>,
1086 }
1087
1088 impl_8bitquant!($ty);
1089
1090 impl Default for $ty {
1091 fn default() -> $ty {
1092 <$ty>::new()
1093 }
1094 }
1095
1096 impl DecoderArithmetic for $ty {
1097 type Llr = i8;
1098 type CheckMessage = i8;
1099 type VarMessage = i8;
1100 type VarLlr = i16;
1101
1102 fn input_llr_quantize(&self, llr: f64) -> i8 {
1103 let x = Self::QUANTIZER_C * llr;
1104 if x >= 127.0 {
1105 127
1106 } else if x <= -127.0 {
1107 -127
1108 } else {
1109 x.round() as i8
1110 }
1111 }
1112
1113 fn llr_hard_decision(&self, llr: i8) -> bool {
1114 llr <= 0
1115 }
1116
1117 fn llr_to_var_message(&self, llr: i8) -> i8 {
1118 llr
1119 }
1120
1121 fn llr_to_var_llr(&self, llr: i8) -> i16 {
1122 i16::from(llr)
1123 }
1124
1125 fn var_llr_to_llr(&self, var_llr: i16) -> i8 {
1126 Self::clip(var_llr)
1127 }
1128
1129 #[allow(clippy::redundant_closure_call)]
1130 fn send_check_messages<F>(&mut self, var_messages: &[Message<i8>], mut send: F)
1131 where
1132 F: FnMut(SentMessage<i8>),
1133 {
1134 let (argmin, msgmin) = var_messages
1135 .iter()
1136 .enumerate()
1137 .min_by_key(|(_, msg)| msg.value.abs())
1138 .expect("var_messages is empty");
1139 let mut sign: u32 = 0;
1140 let mut delta = None;
1141 for (j, msg) in var_messages.iter().enumerate() {
1142 let x = msg.value;
1143 if x < 0 {
1144 sign ^= 1;
1145 }
1146 if j != argmin {
1147 let x = x.abs();
1148 delta = Some(match delta {
1149 None => x,
1150 Some(y) => (x.min(y) - Self::lookup(&self.table, (x - y).abs())
1156 + Self::lookup(&self.table, x.saturating_add(y)))
1157 .max(0),
1158 });
1159 }
1160 }
1161 let delta = delta.expect("var_messages_empty");
1162 let delta_hl = $check_hardlimit(delta);
1163
1164 send(SentMessage {
1165 dest: msgmin.source,
1166 value: if (sign != 0) ^ (msgmin.value < 0) {
1167 -delta_hl
1168 } else {
1169 delta_hl
1170 },
1171 });
1172
1173 let vmin = msgmin.value.abs();
1174 let delta = (delta.min(vmin) - Self::lookup(&self.table, (delta - vmin).abs())
1175 + Self::lookup(&self.table, delta.saturating_add(vmin)))
1176 .max(0);
1177 let delta_hl = $check_hardlimit(delta);
1178 for msg in var_messages
1179 .iter()
1180 .enumerate()
1181 .filter_map(|(j, msg)| if j != argmin { Some(msg) } else { None })
1182 {
1183 send(SentMessage {
1184 dest: msg.source,
1185 value: if (sign != 0) ^ (msg.value < 0) {
1186 -delta_hl
1187 } else {
1188 delta_hl
1189 },
1190 });
1191 }
1192 }
1193
1194 impl_send_var_messages_i8!($degree_one_clip, $jones_clip);
1195
1196 #[allow(clippy::redundant_closure_call)]
1197 fn update_check_messages_and_vars(
1198 &mut self,
1199 check_messages: &mut [SentMessage<i8>],
1200 vars: &mut [i16],
1201 ) {
1202 let (argmin, msgmin) = check_messages
1203 .iter()
1204 .map(|msg| Self::clip(vars[msg.dest] - i16::from(msg.value)))
1205 .enumerate()
1206 .min_by_key(|(_, msg)| msg.abs())
1207 .expect("var_messages is empty");
1208 let mut sign: u32 = 0;
1209 let mut delta = None;
1210 for (j, msg) in check_messages.iter().enumerate() {
1211 let x = Self::clip(vars[msg.dest] - i16::from(msg.value));
1212 if x < 0 {
1213 sign ^= 1;
1214 }
1215 if j != argmin {
1216 let x = x.abs();
1217 delta = Some(match delta {
1218 None => x,
1219 Some(y) => (x.min(y) - Self::lookup(&self.table, (x - y).abs())
1225 + Self::lookup(&self.table, x.saturating_add(y)))
1226 .max(0),
1227 });
1228 }
1229 }
1230 let delta = delta.expect("var_messages_empty");
1231 let delta_hl = $check_hardlimit(delta);
1232 let msgmin_rcv = if (sign != 0) ^ (msgmin < 0) {
1233 -delta_hl
1234 } else {
1235 delta_hl
1236 };
1237
1238 let vmin = msgmin.abs();
1239 let delta = (delta.min(vmin) - Self::lookup(&self.table, (delta - vmin).abs())
1240 + Self::lookup(&self.table, delta.saturating_add(vmin)))
1241 .max(0);
1242 let delta_hl = $check_hardlimit(delta);
1243 for (j, msg) in check_messages.iter_mut().enumerate() {
1244 let x = vars[msg.dest] - i16::from(msg.value);
1245 let rcv = if j == argmin {
1246 msgmin_rcv
1247 } else {
1248 if (sign != 0) ^ (x < 0) {
1249 -delta_hl
1250 } else {
1251 delta_hl
1252 }
1253 };
1254 vars[msg.dest] = x + i16::from(rcv);
1255 msg.value = rcv;
1256 }
1257 }
1258 }
1259 };
1260}
1261
1262impl_aminstari8!(Aminstari8, identity, identity, degree_one_no_clipping!());
1263impl_aminstari8!(
1264 Aminstari8Jones,
1265 jones_clip!(),
1266 identity,
1267 degree_one_no_clipping!()
1268);
1269impl_aminstari8!(
1270 Aminstari8PartialHardLimit,
1271 identity,
1272 partial_hard_limit!(),
1273 degree_one_no_clipping!()
1274);
1275impl_aminstari8!(
1276 Aminstari8JonesPartialHardLimit,
1277 jones_clip!(),
1278 partial_hard_limit!(),
1279 degree_one_no_clipping!()
1280);
1281impl_aminstari8!(
1282 Aminstari8Deg1Clip,
1283 identity,
1284 identity,
1285 degree_one_clipping!()
1286);
1287impl_aminstari8!(
1288 Aminstari8JonesDeg1Clip,
1289 jones_clip!(),
1290 identity,
1291 degree_one_clipping!()
1292);
1293impl_aminstari8!(
1294 Aminstari8PartialHardLimitDeg1Clip,
1295 identity,
1296 partial_hard_limit!(),
1297 degree_one_clipping!()
1298);
1299impl_aminstari8!(
1300 Aminstari8JonesPartialHardLimitDeg1Clip,
1301 jones_clip!(),
1302 partial_hard_limit!(),
1303 degree_one_clipping!()
1304);