use crate::math::common::half::f16_bits_to_f32;
use crate::math::common::kahan_add;
#[inline]
pub unsafe fn dot_product_4x_interleaved_fallback(weights: &[[u16; 4]], state: &[f32]) -> [f32; 4] {
let len = core::cmp::min(weights.len(), state.len());
let mut sum = [0.0f32; 4];
let mut comp = [0.0f32; 4];
for i in 0..len {
unsafe {
let s = *state.get_unchecked(i);
let w = weights.get_unchecked(i);
let w0 = f16_bits_to_f32(w[0]);
let w1 = f16_bits_to_f32(w[1]);
let w2 = f16_bits_to_f32(w[2]);
let w3 = f16_bits_to_f32(w[3]);
let (s0, c0) = kahan_add(sum[0], comp[0], w0 * s);
sum[0] = s0;
comp[0] = c0;
let (s1, c1) = kahan_add(sum[1], comp[1], w1 * s);
sum[1] = s1;
comp[1] = c1;
let (s2, c2) = kahan_add(sum[2], comp[2], w2 * s);
sum[2] = s2;
comp[2] = c2;
let (s3, c3) = kahan_add(sum[3], comp[3], w3 * s);
sum[3] = s3;
comp[3] = c3;
}
}
sum
}
#[inline]
pub unsafe fn dot_product_4x_f32_scalar(weights: &[[f32; 4]], state: &[f32]) -> [f32; 4] {
let len = core::cmp::min(weights.len(), state.len());
let mut r = [0.0f32; 4];
for i in 0..len {
let w = weights.get_unchecked(i);
let s = state.get_unchecked(i);
r[0] = (*w.get_unchecked(0)).mul_add(*s, r[0]);
r[1] = (*w.get_unchecked(1)).mul_add(*s, r[1]);
r[2] = (*w.get_unchecked(2)).mul_add(*s, r[2]);
r[3] = (*w.get_unchecked(3)).mul_add(*s, r[3]);
}
r
}
#[inline]
pub unsafe fn dot_product_4x_f32_dual_scalar(
weights: &[[f32; 4]],
state_f0: &[f32],
state_f1: &[f32],
) -> ([f32; 4], [f32; 4]) {
let len = core::cmp::min(
weights.len(),
core::cmp::min(state_f0.len(), state_f1.len()),
);
let mut r0 = [0.0f32; 4];
let mut r1 = [0.0f32; 4];
for i in 0..len {
let w = weights.get_unchecked(i);
let s0 = state_f0.get_unchecked(i);
let s1 = state_f1.get_unchecked(i);
r0[0] = (*w.get_unchecked(0)).mul_add(*s0, r0[0]);
r0[1] = (*w.get_unchecked(1)).mul_add(*s0, r0[1]);
r0[2] = (*w.get_unchecked(2)).mul_add(*s0, r0[2]);
r0[3] = (*w.get_unchecked(3)).mul_add(*s0, r0[3]);
r1[0] = (*w.get_unchecked(0)).mul_add(*s1, r1[0]);
r1[1] = (*w.get_unchecked(1)).mul_add(*s1, r1[1]);
r1[2] = (*w.get_unchecked(2)).mul_add(*s1, r1[2]);
r1[3] = (*w.get_unchecked(3)).mul_add(*s1, r1[3]);
}
(r0, r1)
}
#[inline]
pub unsafe fn dot_product_4x_interleaved_dual_frame_fallback(
weights: &[[u16; 4]],
state_f0: &[f32], state_f1: &[f32], ) -> ([f32; 4], [f32; 4]) {
let len = core::cmp::min(
weights.len(),
core::cmp::min(state_f0.len(), state_f1.len()),
);
let mut sum_f0 = [0.0f32; 4];
let mut sum_f1 = [0.0f32; 4];
let mut comp_f0 = [0.0f32; 4];
let mut comp_f1 = [0.0f32; 4];
for i in 0..len {
unsafe {
let s0 = *state_f0.get_unchecked(i);
let s1 = *state_f1.get_unchecked(i);
let w = weights.get_unchecked(i);
let w0 = f16_bits_to_f32(w[0]);
let w1 = f16_bits_to_f32(w[1]);
let w2 = f16_bits_to_f32(w[2]);
let w3 = f16_bits_to_f32(w[3]);
let (s, c) = kahan_add(sum_f0[0], comp_f0[0], w0 * s0);
sum_f0[0] = s;
comp_f0[0] = c;
let (s, c) = kahan_add(sum_f0[1], comp_f0[1], w1 * s0);
sum_f0[1] = s;
comp_f0[1] = c;
let (s, c) = kahan_add(sum_f0[2], comp_f0[2], w2 * s0);
sum_f0[2] = s;
comp_f0[2] = c;
let (s, c) = kahan_add(sum_f0[3], comp_f0[3], w3 * s0);
sum_f0[3] = s;
comp_f0[3] = c;
let (s, c) = kahan_add(sum_f1[0], comp_f1[0], w0 * s1);
sum_f1[0] = s;
comp_f1[0] = c;
let (s, c) = kahan_add(sum_f1[1], comp_f1[1], w1 * s1);
sum_f1[1] = s;
comp_f1[1] = c;
let (s, c) = kahan_add(sum_f1[2], comp_f1[2], w2 * s1);
sum_f1[2] = s;
comp_f1[2] = c;
let (s, c) = kahan_add(sum_f1[3], comp_f1[3], w3 * s1);
sum_f1[3] = s;
comp_f1[3] = c;
}
}
(sum_f0, sum_f1)
}
#[inline]
pub unsafe fn dot_product_4x_f32_accumulate_scalar(
weights: &[[f32; 4]],
state: &[f32],
init: &[f32; 4],
) -> [f32; 4] {
let r = dot_product_4x_f32_scalar(weights, state);
[
init[0] + r[0],
init[1] + r[1],
init[2] + r[2],
init[3] + r[3],
]
}
#[inline]
pub unsafe fn dot_product_4x_f32_dual_accumulate_scalar(
weights: &[[f32; 4]],
state_f0: &[f32],
state_f1: &[f32],
init_f0: &[f32; 4],
init_f1: &[f32; 4],
) -> ([f32; 4], [f32; 4]) {
let (r0, r1) = dot_product_4x_f32_dual_scalar(weights, state_f0, state_f1);
(
[
init_f0[0] + r0[0],
init_f0[1] + r0[1],
init_f0[2] + r0[2],
init_f0[3] + r0[3],
],
[
init_f1[0] + r1[0],
init_f1[1] + r1[1],
init_f1[2] + r1[2],
init_f1[3] + r1[3],
],
)
}