| #include <stdint.h>
|
| #include <stddef.h>
|
| #include "jso.h"
|
|
|
| |
| |
|
|
|
|
| static inline cf32_t cf_add(cf32_t a, cf32_t b) {
|
| return (cf32_t){ a.re + b.re, a.im + b.im };
|
| }
|
| static inline cf32_t cf_scale(cf32_t a, float s) {
|
| return (cf32_t){ a.re * s, a.im * s };
|
| }
|
| static inline cf32_t cf_mul(cf32_t a, cf32_t b) {
|
| return (cf32_t){ a.re*b.re - a.im*b.im,
|
| a.re*b.im + a.im*b.re };
|
| }
|
| static inline cf32_t cf_conj(cf32_t a) {
|
| return (cf32_t){ a.re, -a.im };
|
| }
|
| static inline float cf_abs2(cf32_t a) {
|
| return a.re*a.re + a.im*a.im;
|
| }
|
|
|
| |
| |
|
|
| static void cgemm(const cf32_t* A, const cf32_t* B, cf32_t* C, int n) {
|
| for (int i = 0; i < n; i++) {
|
| for (int j = 0; j < n; j++) {
|
| cf32_t acc = {0.0f, 0.0f};
|
| for (int p = 0; p < n; p++)
|
| acc = cf_add(acc, cf_mul(A[i*n+p], B[p*n+j]));
|
| C[i*n+j] = acc;
|
| }
|
| }
|
| }
|
|
|
|
|
| static void ctranspose(const cf32_t* A, cf32_t* AH, int n) {
|
| for (int i = 0; i < n; i++)
|
| for (int j = 0; j < n; j++)
|
| AH[j*n+i] = cf_conj(A[i*n+j]);
|
| }
|
|
|
|
|
| static float fsqrt(float x) {
|
| if (x <= 0.0f) return 0.0f;
|
|
|
| float r = x;
|
| for (int i = 0; i < 8; i++) r = 0.5f*(r + x/r);
|
| return r;
|
| }
|
|
|
| |
| |
| |
| |
| |
|
|
|
|
|
|
| static cf32_t s_scratch[2 * JSO_MAX_N * JSO_MAX_N];
|
|
|
| int sov_jso_f32(const cf32_t* U, const cf32_t* rho,
|
| cf32_t* S_out, cf32_t* scratch, int n) {
|
| if (!U || !rho || !S_out || n <= 0) return -1;
|
|
|
| cf32_t* tmp1;
|
| cf32_t* tmp2;
|
| if (scratch) {
|
| tmp1 = scratch;
|
| tmp2 = scratch + n*n;
|
| } else {
|
| if (n > JSO_MAX_N) return -1;
|
| tmp1 = s_scratch;
|
| tmp2 = s_scratch + n*n;
|
| }
|
|
|
|
|
| cgemm(U, rho, tmp1, n);
|
|
|
|
|
| ctranspose(U, tmp2, n);
|
|
|
| |
| |
| |
| |
|
|
| cgemm(tmp1, tmp2, S_out, n);
|
|
|
|
|
| for (int i = 0; i < n*n; i++) {
|
| S_out[i].re = JSO_PHI_INV * S_out[i].re + JSO_PHI_INV2 * rho[i].re;
|
| S_out[i].im = JSO_PHI_INV * S_out[i].im + JSO_PHI_INV2 * rho[i].im;
|
| }
|
| return 0;
|
| }
|
|
|
| float sov_jso_residual_f32(const cf32_t* U, const cf32_t* rho,
|
| cf32_t* scratch, int n) {
|
| if (!U || !rho || !scratch || n <= 0) return -1.0f;
|
|
|
|
|
| cf32_t* S_out = scratch;
|
| cf32_t* jso_scr = scratch + n*n;
|
| if (sov_jso_f32(U, rho, S_out, jso_scr, n) != 0) return -1.0f;
|
|
|
| float s = 0.0f;
|
| for (int i = 0; i < n*n; i++) {
|
| float dr = S_out[i].re - rho[i].re;
|
| float di = S_out[i].im - rho[i].im;
|
| s += dr*dr + di*di;
|
| }
|
| return s;
|
| }
|
|
|
| |
| |
| |
|
|
|
|
| int sov_density_project_f32(const cf32_t* X, const cf32_t* W,
|
| cf32_t* rho_out, cf32_t* scratch, int n, int k) {
|
| if (!X || !W || !rho_out || !scratch || n <= 0 || k <= 0) return -1;
|
|
|
|
|
| |
|
|
| cf32_t* A = scratch;
|
| for (int i = 0; i < n; i++) {
|
| cf32_t acc = {0.0f, 0.0f};
|
| for (int p = 0; p < k; p++)
|
| acc = cf_add(acc, cf_mul(W[i*k+p], X[p]));
|
| A[i] = acc;
|
| }
|
|
|
|
|
| for (int i = 0; i < n; i++)
|
| for (int j = 0; j < n; j++)
|
| rho_out[i*n+j] = cf_mul(A[i], cf_conj(A[j]));
|
|
|
|
|
| float tr = 0.0f;
|
| for (int i = 0; i < n; i++) tr += cf_abs2(A[i]);
|
| if (tr < 1e-12f) return -1;
|
|
|
| float inv_tr = 1.0f / tr;
|
| for (int i = 0; i < n*n; i++) {
|
| rho_out[i].re *= inv_tr;
|
| rho_out[i].im *= inv_tr;
|
| }
|
| return 0;
|
| }
|
|
|
| |
| |
| |
| |
|
|
|
|
| static float cf_norm(const cf32_t* v, int n) {
|
| float s = 0.0f;
|
| for (int i = 0; i < n; i++) s += cf_abs2(v[i]);
|
| return fsqrt(s);
|
| }
|
|
|
| int sov_unitary_project_f32(const cf32_t* X, const cf32_t* W,
|
| cf32_t* U_out, cf32_t* scratch, int n, int k) {
|
| if (!X || !W || !U_out || !scratch || n <= 0 || k <= 0) return -1;
|
|
|
|
|
|
|
| cf32_t* cols = scratch;
|
|
|
|
|
|
|
|
|
| for (int j = 0; j < n; j++) {
|
| cf32_t dot = {0.0f, 0.0f};
|
| for (int p = 0; p < k; p++)
|
| dot = cf_add(dot, cf_mul(W[j*k+p], X[p]));
|
|
|
| for (int i = 0; i < n; i++)
|
| cols[i*n+j] = (i == j) ? dot : (cf32_t){0.0f, 0.0f};
|
| }
|
|
|
|
|
| for (int j = 0; j < n; j++) {
|
|
|
| for (int i = 0; i < n; i++) U_out[i*n+j] = cols[i*n+j];
|
|
|
|
|
| for (int p = 0; p < j; p++) {
|
|
|
| cf32_t proj = {0.0f, 0.0f};
|
| for (int i = 0; i < n; i++)
|
| proj = cf_add(proj, cf_mul(cf_conj(U_out[i*n+p]), U_out[i*n+j]));
|
| for (int i = 0; i < n; i++)
|
| U_out[i*n+j] = (cf32_t){
|
| U_out[i*n+j].re - (proj.re*U_out[i*n+p].re - proj.im*U_out[i*n+p].im),
|
| U_out[i*n+j].im - (proj.re*U_out[i*n+p].im + proj.im*U_out[i*n+p].re)
|
| };
|
| }
|
|
|
|
|
| float nrm = cf_norm(&U_out[0*n+j], 0);
|
|
|
| float s2 = 0.0f;
|
| for (int i = 0; i < n; i++) s2 += cf_abs2(U_out[i*n+j]);
|
| nrm = fsqrt(s2);
|
| if (nrm < 1e-12f) {
|
|
|
| for (int i = 0; i < n; i++)
|
| U_out[i*n+j] = (i == j) ? (cf32_t){1.0f,0.0f} : (cf32_t){0.0f,0.0f};
|
| } else {
|
| float inv = 1.0f / nrm;
|
| for (int i = 0; i < n; i++) {
|
| U_out[i*n+j].re *= inv;
|
| U_out[i*n+j].im *= inv;
|
| }
|
| }
|
| }
|
| return 0;
|
| }
|
|
|
| |
| |
|
|
| static void rmsnorm(cf32_t* x, int len) {
|
| float ss = 0.0f;
|
| for (int i = 0; i < len; i++) ss += cf_abs2(x[i]);
|
| float scale = 1.0f / fsqrt(ss / (float)len + 1e-6f);
|
| for (int i = 0; i < len; i++) {
|
| x[i].re *= scale;
|
| x[i].im *= scale;
|
| }
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
|
|
| static inline cf32_t cf_relu(cf32_t a) {
|
| return (cf32_t){ a.re > 0.0f ? a.re : 0.0f,
|
| a.im > 0.0f ? a.im : 0.0f };
|
| }
|
|
|
| int sov_agent_block_f32(const cf32_t* in, cf32_t* out,
|
| const sov_agent_params_t* params,
|
| cf32_t* scratch, int B, int T) {
|
| if (!in || !out || !params || !scratch) return -1;
|
|
|
| const int D = params->D;
|
| const int n = params->n;
|
| const int k = params->k;
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| cf32_t* x_work = scratch;
|
| cf32_t* rho = scratch + D;
|
| cf32_t* U = scratch + D + n*n;
|
| cf32_t* S = scratch + D + 2*n*n;
|
| cf32_t* jso_scr = scratch + D + 3*n*n;
|
| cf32_t* proj_scr = scratch + D + 5*n*n;
|
| cf32_t* ffn_mid = scratch + D + 5*n*n + n;
|
|
|
| for (int b = 0; b < B; b++) {
|
| for (int t = 0; t < T; t++) {
|
| const cf32_t* x_in = in + (b*T + t)*D;
|
| cf32_t* x_out = out + (b*T + t)*D;
|
|
|
|
|
| for (int i = 0; i < D; i++) x_work[i] = x_in[i];
|
|
|
|
|
| for (int i = 0; i < D; i++) {
|
| cf32_t h = {0.0f, 0.0f};
|
| for (int j = 0; j < D; j++)
|
| h = cf_add(h, cf_mul(params->ssm_A[i*D+j], x_work[j]));
|
| x_work[i] = cf_add(x_work[i], h);
|
| }
|
|
|
|
|
| rmsnorm(x_work, D);
|
|
|
|
|
| if (sov_density_project_f32(x_work, params->W_rho, rho, proj_scr, n, k) != 0) return -2;
|
| if (sov_unitary_project_f32(x_work, params->W_u, U, proj_scr, n, k) != 0) return -3;
|
|
|
|
|
| if (sov_jso_f32(U, rho, S, jso_scr, n) != 0) return -4;
|
|
|
| |
|
|
| for (int i = 0; i < D; i++) {
|
| cf32_t s_val = (i < n*n) ? S[i] : (cf32_t){0.0f, 0.0f};
|
| x_work[i] = cf_add(x_work[i], s_val);
|
| }
|
|
|
|
|
| rmsnorm(x_work, D);
|
|
|
|
|
| int D4 = 4 * D;
|
| for (int i = 0; i < D4; i++) {
|
| cf32_t acc = {0.0f, 0.0f};
|
| for (int j = 0; j < D; j++)
|
| acc = cf_add(acc, cf_mul(params->ffn_W1[i*D+j], x_work[j]));
|
| ffn_mid[i] = cf_relu(acc);
|
| }
|
| for (int i = 0; i < D; i++) {
|
| cf32_t acc = {0.0f, 0.0f};
|
| for (int j = 0; j < D4; j++)
|
| acc = cf_add(acc, cf_mul(params->ffn_W2[i*D4+j], ffn_mid[j]));
|
| x_out[i] = cf_add(x_work[i], acc);
|
| }
|
| }
|
| }
|
| return 0;
|
| }
|
|
|