Spaces:
Running
Running
| /* phoenix_brain.c — Pure BQSM inference: 1 settle = 1 forward pass. | |
| * | |
| * The ring IS the computation. No matmul. Weights are encoded as | |
| * oscillator lens profiles, activations as phases. The 4 mode coupling | |
| * channels (c₁×c₁→c₂, c₂×c₂→c₄, c₂×c₄→c₆, direct) compute | |
| * products through wave interference. One settle of the ring = | |
| * one complete forward pass through all layers. | |
| * | |
| * Build: cc -O3 -std=c11 -march=native -fopenmp phoenix_brain.c -o /tmp/phoenix -lm | |
| * Run: /tmp/phoenix [model.bqsm] | |
| */ | |
| /* ── Ring geometry ── */ | |
| /* ── Settle budget ── */ | |
| /* ── Product channels — the 4 wave interference paths ── */ | |
| /* ── State persistence ── */ | |
| /* ── 4-Ring Macro Core ── */ | |
| /* ── Checkpoint confirm windows ── */ | |
| /* ── Roles ── */ | |
| enum role { ROLE_DORMANT, ROLE_INPUT, ROLE_PROJ, ROLE_GATE, ROLE_OUTPUT, ROLE_RESERVE }; | |
| enum tune_phase { TUNE_IDLE, TUNE_PERTURB, TUNE_EVAL, TUNE_COMMIT, TUNE_REVERT }; | |
| /* ── Self-tuning state ── */ | |
| typedef struct { | |
| int phase; | |
| double best_score; | |
| double perturb_lr; | |
| int perturb_count; | |
| int batch_size; | |
| int improve_count; | |
| int revert_count; | |
| int *train_tokens; | |
| int n_train; | |
| int train_pos; | |
| double last_accuracy; /* next-token argmax accuracy of last eval batch */ | |
| /* Backup of the per-tendril gains perturbed this round, for revert */ | |
| int perturb_idx[128]; | |
| double perturb_old[128]; | |
| int n_perturbed; | |
| } self_tune_t; | |
| static const char *role_str[] = {"dormant","input","proj","gate","output","reserve"}; | |
| /* ── Scheduling modes ── */ | |
| enum mode { IDLE, ACTIVATE, ESCALATE, CRYSTALLIZE, MAINTAIN }; | |
| static const char *mode_str[] = {"IDLE","ACTIVATE","ESCALATE","CRYSTALLIZE","MAINTAIN"}; | |
| /* ── Modification types ── */ | |
| enum mod_type { | |
| MOD_NONE, MOD_ADD_VQPUS, MOD_ADD_CONN, MOD_PRUNE_CONN, | |
| MOD_ADJ_WEIGHT, MOD_RESHAPE | |
| }; | |
| static const char *mod_str[] = { | |
| "NONE","ADD_VQPUS","ADD_CONN","PRUNE_CONN","ADJ_WEIGHT","RESHAPE" | |
| }; | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * SINGLE vQPU — 16 Kuramoto oscillators | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| typedef struct { | |
| double theta[N_OSC]; /* oscillator phases */ | |
| double omega[N_OSC]; /* lens profile = encoded weights */ | |
| double c_re[N_HARM]; /* harmonic coefficients (real) */ | |
| double c_im[N_HARM]; /* harmonic coefficients (imag) */ | |
| double c_mag[N_HARM]; /* harmonic magnitudes */ | |
| double K; /* coupling strength */ | |
| double coherence; /* |c₁| */ | |
| int active; | |
| int age; | |
| int role; | |
| int layer_id; /* transformer layer assignment */ | |
| int proj_id; /* which projection (0=Wq,1=Wk,...6=Wdown) */ | |
| int col_start; /* which output column range this vQPU handles */ | |
| double utilization; | |
| double train_gain; /* trainable per-tendril output gain (1.0 = neutral) */ | |
| } vqpu_t; | |
| /* ── Connection ── */ | |
| typedef struct { | |
| int src, dst; | |
| int src_harm, dst_harm; | |
| double weight; | |
| double traffic; | |
| int alive; | |
| } conn_t; | |
| /* ── Checkpoint ── */ | |
| typedef struct { | |
| vqpu_t *vqpus; | |
| conn_t *fabric; | |
| int n_vqpus, n_connections; | |
| double coherence; | |
| int deadline, pending; | |
| enum mod_type mod; | |
| } checkpoint_t; | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * MACRO CORE — 4 rings × 16 oscillators = 64 fixed oscillators. | |
| * Everything else grows outward as tentacles during weight ingestion. | |
| * The topology IS the model — discovered, not prescribed. | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| typedef struct { | |
| int ring_id[MACRO_RINGS]; /* vQPU index for each core ring */ | |
| /* Tendrils grown during ingestion */ | |
| int input_start, n_inputs; /* activation-holding tendrils (off INTAKE) */ | |
| int compute_start, n_compute; /* weight-processing tendrils (off PROC_A/B) */ | |
| int output_start, n_outputs; /* product-collecting tendrils (off COLLECT) */ | |
| /* Ingestion stats */ | |
| int ingestion_rounds; | |
| int tendrils_pruned; | |
| int tendrils_strengthened; | |
| int ready; | |
| } macro_core_t; | |
| /* ── Phoenix Brain ── */ | |
| typedef struct { | |
| vqpu_t *vqpus; | |
| int n_vqpus; | |
| int capacity; | |
| conn_t *fabric; | |
| int n_connections; | |
| int capacity_conns; | |
| int alive_conns; | |
| double g_coupling[N_HARM][N_HARM]; | |
| double lens_enhance[N_HARM]; | |
| /* Backup of the trainable physics gains, for tune perturb/revert */ | |
| double g_coupling_bak[N_HARM][N_HARM]; | |
| double lens_enhance_bak[N_HARM]; | |
| enum mode mode; | |
| int *hot_set; | |
| int n_hot; | |
| int cycle_count; | |
| int total_cycles; | |
| double ring_coherence; | |
| double convergence_rate; | |
| checkpoint_t ckpt; | |
| int mod_attempts, mod_confirms, mod_reverts; | |
| /* Model (mmap'd) */ | |
| const uint8_t *weights; | |
| const uint8_t *weight_base; | |
| size_t weights_size; | |
| int D, FFN, q_dim, kv_dim, V, n_layers; | |
| int qw, kw, vw, ow, gw, uw, dw; | |
| int layer_bytes; | |
| int model_loaded; | |
| /* RMSNorm weights (loaded from end of .bqsm if present) */ | |
| float *norm_output, *norm_attn, *norm_q, *norm_k, *norm_ffn; | |
| int has_norms; | |
| /* Pipeline mapping: layer → vQPU groups */ | |
| int *layer_base; /* first vQPU index for each layer */ | |
| int vqpus_per_layer; | |
| /* 4-Ring Macro Core */ | |
| macro_core_t core; | |
| /* Output readout buffer */ | |
| double *readout; | |
| int readout_dim; | |
| /* Self-tuning */ | |
| self_tune_t tune; | |
| /* Timing */ | |
| double last_settle_ms; | |
| double last_cycle_ms; | |
| } phoenix_t; | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * CORE PHYSICS | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static double now_ms(void) { | |
| struct timespec ts; | |
| clock_gettime(CLOCK_MONOTONIC, &ts); | |
| return ts.tv_sec * 1000.0 + ts.tv_nsec / 1e6; | |
| } | |
| static void init_coupling(phoenix_t *p) { | |
| for (int i = 0; i < N_HARM; i++) | |
| for (int j = 0; j < N_HARM; j++) { | |
| double ri = 1.0 - cos(2*M_PI*i/N_OSC); | |
| double ii = -sin(2*M_PI*i/N_OSC); | |
| double rj = 1.0 - cos(2*M_PI*j/N_OSC); | |
| double ij = -sin(2*M_PI*j/N_OSC); | |
| p->g_coupling[i][j] = 0.5 * sqrt( | |
| (ri*rj - ii*ij)*(ri*rj - ii*ij) + | |
| (ri*ij + ii*rj)*(ri*ij + ii*rj)); | |
| } | |
| for (int k = 0; k < N_HARM; k++) p->lens_enhance[k] = 1.0; | |
| p->lens_enhance[CH_PROD4] = 24.38; /* (2,2)→4 channel */ | |
| p->lens_enhance[CH_PROD2] = 4.0; /* (1,1)→2 channel */ | |
| p->lens_enhance[CH_PROD6] = 10.0; /* (2,4)→6 channel */ | |
| } | |
| /* ── Kuramoto step ── */ | |
| static void vqpu_step(vqpu_t *v) { | |
| double dth[N_OSC]; | |
| for (int i = 0; i < N_OSC; i++) { | |
| double c = 0; | |
| for (int j = 0; j < N_OSC; j++) | |
| c += sin(v->theta[j] - v->theta[i]); | |
| dth[i] = v->omega[i] + (v->K / N_OSC) * c; | |
| } | |
| for (int i = 0; i < N_OSC; i++) | |
| v->theta[i] += SETTLE_DT * dth[i]; | |
| } | |
| /* ── DFT: extract harmonic coefficients from phases ── */ | |
| static void vqpu_dft(vqpu_t *v) { | |
| for (int k = 0; k < N_HARM; k++) { | |
| double re = 0, im = 0; | |
| for (int n = 0; n < N_OSC; n++) { | |
| double a = 2.0 * M_PI * k * n / N_OSC; | |
| re += cos(v->theta[n] - a); | |
| im += sin(v->theta[n] - a); | |
| } | |
| v->c_re[k] = re / N_OSC; | |
| v->c_im[k] = im / N_OSC; | |
| v->c_mag[k] = sqrt(re*re + im*im) / N_OSC; | |
| } | |
| v->coherence = v->c_mag[CH_FUND]; | |
| } | |
| /* ── Mode coupling product: the wave interference computation ── */ | |
| static double vqpu_product(const vqpu_t *v, int p, int q, | |
| const double g[N_HARM][N_HARM], | |
| const double enh[N_HARM]) { | |
| double prod_re = v->c_re[p] * v->c_re[q] - v->c_im[p] * v->c_im[q]; | |
| int k = (p + q) % N_HARM; | |
| return prod_re * g[p][q] * enh[k]; | |
| } | |
| /* ── Read all 4 product channels from a settled vQPU ── */ | |
| static double vqpu_read_products(const vqpu_t *v, | |
| const double g[N_HARM][N_HARM], | |
| const double enh[N_HARM]) { | |
| double sum = 0; | |
| /* Channel 1: c₁×c₁ → c₂ (fundamental self-product, 4× lens) */ | |
| sum += vqpu_product(v, 1, 1, g, enh); | |
| /* Channel 2: c₂×c₂ → c₄ (24.38× lens, highest gain) */ | |
| sum += vqpu_product(v, 2, 2, g, enh); | |
| /* Channel 3: c₂×c₄ → c₆ (10× lens, cross-product) */ | |
| sum += vqpu_product(v, 2, 4, g, enh); | |
| /* Channel 4: c₁×c₂ → c₃ (direct, 1× lens) */ | |
| sum += vqpu_product(v, 1, 2, g, enh); | |
| return sum; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * WEIGHT ENCODING — ternary weights → oscillator lens profiles | |
| * | |
| * Each ternary value {-1, 0, +1} becomes an oscillator frequency: | |
| * -1 → ω = -0.5 (counter-rotating) | |
| * 0 → ω = 0.0 (stationary, vanishes from dynamics) | |
| * +1 → ω = +0.5 (co-rotating) | |
| * | |
| * Site-0 bias: ω[0] += 0.5 for the lens enhancement effect. | |
| * The zero weights naturally drop out — they don't oscillate, | |
| * don't contribute to harmonics, don't consume energy. This is | |
| * the same sparsity that makes v5 fast, but expressed as physics. | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void decode_ternary_to_lens(const uint8_t *packed, int col, | |
| int stride, double *omega) { | |
| memset(omega, 0, N_OSC * sizeof(double)); | |
| const uint8_t *w = packed + (size_t)col * stride; | |
| for (int i = 0; i < N_OSC; i++) { | |
| int byte_idx = i / 4; | |
| int bit_idx = (i % 4) * 2; | |
| if (byte_idx >= stride) break; | |
| int val = (w[byte_idx] >> bit_idx) & 0x03; | |
| if (val == 0) omega[i] = -0.5; | |
| else if (val == 2) omega[i] = 0.5; | |
| /* val=1 or val=3 → 0.0 (zero weight, drops out) */ | |
| } | |
| /* Gradient lens: linear frequency ramp creates traveling wave drive. | |
| * The wave propagates because each oscillator has a different omega. | |
| * Weight values modulate the wave speed at each position. */ | |
| for (int i = 0; i < N_OSC; i++) | |
| omega[i] += (i - N_OSC / 2.0) * 0.1; | |
| } | |
| /* ── Token embedding: extract column from LM head ── | |
| * The LM head is [D × V] packed 2-bit. Token t's embedding = column t. | |
| * Each row contributes one ternary value per token. */ | |
| static void embed_token(phoenix_t *p, int token_id, double *emb) { | |
| size_t lm_offset = (size_t)p->layer_bytes * p->n_layers; | |
| const uint8_t *lm_head = p->weights + lm_offset; | |
| int stride = p->V / 4; | |
| int byte_idx = token_id / 4; | |
| int bit_shift = (token_id % 4) * 2; | |
| memset(emb, 0, p->D * sizeof(double)); | |
| for (int d = 0; d < p->D; d++) { | |
| int val = (lm_head[d * stride + byte_idx] >> bit_shift) & 0x03; | |
| if (val == 0) emb[d] = -1.0; | |
| else if (val == 2) emb[d] = 1.0; | |
| } | |
| } | |
| /* ── Project to vocab: x[D] × LM_head[D × V] → logits[V], argmax ── */ | |
| static int project_to_vocab(phoenix_t *p, const double *x) { | |
| size_t lm_offset = (size_t)p->layer_bytes * p->n_layers; | |
| const uint8_t *lm_head = p->weights + lm_offset; | |
| int stride = p->V / 4; | |
| double best_logit = -1e30; | |
| int best_id = 0; | |
| { | |
| double local_best = -1e30; | |
| int local_id = 0; | |
| for (int v = 0; v < p->V; v++) { | |
| int byte_idx = v / 4; | |
| int bit_shift = (v % 4) * 2; | |
| double logit = 0; | |
| for (int d = 0; d < p->D; d++) { | |
| int bits = (lm_head[d * stride + byte_idx] >> bit_shift) & 0x03; | |
| if (bits == 0) logit -= x[d]; | |
| else if (bits == 2) logit += x[d]; | |
| } | |
| if (logit > local_best) { local_best = logit; local_id = v; } | |
| } | |
| if (local_best > best_logit) { best_logit = local_best; best_id = local_id; } | |
| } | |
| return best_id; | |
| } | |
| /* ── Wave-rider activation: token rides traveling wave ── | |
| * Instead of static theta = x * pi/4 (converges to fixed point), | |
| * we create a traveling wave baseline and modulate it with the token. | |
| * The wave keeps information in motion — no fixed point to collapse to. | |
| * | |
| * theta[i] = 2*pi*i/N + x[i] * pi/4 | |
| * The traveling wave creates linear phase ramp; the token perturbs it. | |
| */ | |
| static void encode_activation(vqpu_t *v, const double *act, int n) { | |
| for (int i = 0; i < N_OSC; i++) { | |
| double wave = 2.0 * M_PI * i / N_OSC; | |
| double perturb = (i < n) ? act[i] * M_PI / 4.0 : 0.0; | |
| v->theta[i] = wave + perturb; | |
| } | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * FABRIC — neuromorphic connections between vQPUs | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static int fabric_add(phoenix_t *p, int src, int dst, | |
| int sh, int dh, double w) { | |
| for (int i = 0; i < p->n_connections; i++) | |
| if (!p->fabric[i].alive) { | |
| p->fabric[i] = (conn_t){src, dst, sh, dh, w, 0, 1}; | |
| p->alive_conns++; | |
| return i; | |
| } | |
| if (p->n_connections >= p->capacity_conns) return -1; | |
| p->fabric[p->n_connections] = (conn_t){src, dst, sh, dh, w, 0, 1}; | |
| p->alive_conns++; | |
| return p->n_connections++; | |
| } | |
| /* ── Propagate harmonic data through fabric ── */ | |
| static void fabric_propagate(phoenix_t *p) { | |
| for (int i = 0; i < p->n_connections; i++) { | |
| conn_t *c = &p->fabric[i]; | |
| if (!c->alive || !p->vqpus[c->src].active) continue; | |
| vqpu_t *src = &p->vqpus[c->src]; | |
| vqpu_t *dst = &p->vqpus[c->dst]; | |
| double flow = c->weight * src->c_re[c->src_harm]; | |
| dst->c_re[c->dst_harm] += flow; | |
| dst->c_im[c->dst_harm] += c->weight * src->c_im[c->src_harm]; | |
| c->traffic = c->traffic * 0.95 + fabs(flow) * 0.05; | |
| } | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * CHECKPOINT / ROLLBACK — "Keep these changes?" | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void ckpt_save(phoenix_t *p) { | |
| checkpoint_t *c = &p->ckpt; | |
| c->vqpus = realloc(c->vqpus, p->n_vqpus * sizeof(vqpu_t)); | |
| c->fabric = realloc(c->fabric, p->n_connections * sizeof(conn_t)); | |
| memcpy(c->vqpus, p->vqpus, p->n_vqpus * sizeof(vqpu_t)); | |
| memcpy(c->fabric, p->fabric, p->n_connections * sizeof(conn_t)); | |
| c->n_vqpus = p->n_vqpus; | |
| c->n_connections = p->n_connections; | |
| c->coherence = p->ring_coherence; | |
| } | |
| static void ckpt_revert(phoenix_t *p) { | |
| checkpoint_t *c = &p->ckpt; | |
| if (!c->pending) return; | |
| if (c->n_vqpus <= p->capacity) | |
| memcpy(p->vqpus, c->vqpus, c->n_vqpus * sizeof(vqpu_t)); | |
| p->n_vqpus = c->n_vqpus; | |
| if (c->n_connections <= p->capacity_conns) | |
| memcpy(p->fabric, c->fabric, c->n_connections * sizeof(conn_t)); | |
| p->n_connections = c->n_connections; | |
| p->alive_conns = 0; | |
| for (int i = 0; i < p->n_connections; i++) | |
| if (p->fabric[i].alive) p->alive_conns++; | |
| c->pending = 0; | |
| p->mod_reverts++; | |
| printf(" ** REVERTED %s **\n", mod_str[c->mod]); | |
| } | |
| static void ckpt_confirm(phoenix_t *p) { | |
| p->ckpt.pending = 0; | |
| p->mod_confirms++; | |
| printf(" ** CONFIRMED %s — ring stable **\n", mod_str[p->ckpt.mod]); | |
| } | |
| static void ckpt_check(phoenix_t *p) { | |
| checkpoint_t *c = &p->ckpt; | |
| if (!c->pending) return; | |
| if (p->total_cycles >= c->deadline) { | |
| double threshold = c->coherence * 0.7; | |
| if (threshold < 0.005) threshold = 0.005; | |
| if (p->ring_coherence >= threshold) | |
| ckpt_confirm(p); | |
| else | |
| ckpt_revert(p); | |
| } | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * SELF-MODIFICATION PROPOSALS | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void propose_grow(phoenix_t *p, int count) { | |
| if (p->ckpt.pending || p->n_vqpus + count > p->capacity) return; | |
| ckpt_save(p); | |
| p->ckpt.mod = MOD_ADD_VQPUS; | |
| p->ckpt.deadline = p->total_cycles + CONFIRM_SLOW; | |
| p->ckpt.pending = 1; | |
| int start = p->n_vqpus; | |
| p->n_vqpus += count; | |
| for (int i = start; i < p->n_vqpus; i++) { | |
| memset(&p->vqpus[i], 0, sizeof(vqpu_t)); | |
| p->vqpus[i].K = 1.0; | |
| for (int o = 0; o < N_OSC; o++) | |
| p->vqpus[i].theta[o] = ((double)rand()/RAND_MAX) * 2*M_PI; | |
| p->vqpus[i].omega[0] = 0.5; | |
| fabric_add(p, (start-1) % start, i, CH_FUND, CH_FUND, 0.1); | |
| fabric_add(p, i, (start-1) % start, CH_FUND, CH_FUND, 0.1); | |
| } | |
| p->mod_attempts++; | |
| printf(" >> PROPOSED: grow +%d vQPUs (%d → %d)\n", count, start, p->n_vqpus); | |
| } | |
| static void propose_prune(phoenix_t *p) { | |
| if (p->ckpt.pending) return; | |
| ckpt_save(p); | |
| p->ckpt.mod = MOD_PRUNE_CONN; | |
| p->ckpt.deadline = p->total_cycles + CONFIRM_MEDIUM; | |
| p->ckpt.pending = 1; | |
| int pruned = 0; | |
| for (int i = 0; i < p->n_connections; i++) { | |
| if (!p->fabric[i].alive) continue; | |
| if (p->fabric[i].traffic < 0.001 && p->total_cycles > 50) { | |
| p->fabric[i].alive = 0; | |
| p->alive_conns--; | |
| pruned++; | |
| } | |
| } | |
| p->mod_attempts++; | |
| printf(" >> PROPOSED: prune %d dead connections\n", pruned); | |
| } | |
| static void propose_strengthen(phoenix_t *p) { | |
| if (p->ckpt.pending) return; | |
| ckpt_save(p); | |
| p->ckpt.mod = MOD_ADJ_WEIGHT; | |
| p->ckpt.deadline = p->total_cycles + CONFIRM_FAST; | |
| p->ckpt.pending = 1; | |
| double mx = 0; | |
| for (int i = 0; i < p->n_connections; i++) | |
| if (p->fabric[i].alive && p->fabric[i].traffic > mx) | |
| mx = p->fabric[i].traffic; | |
| if (mx < 0.001) { p->ckpt.pending = 0; return; } | |
| for (int i = 0; i < p->n_connections; i++) { | |
| if (!p->fabric[i].alive) continue; | |
| double norm = p->fabric[i].traffic / mx; | |
| if (norm > 0.5) p->fabric[i].weight *= 1.05; | |
| else if (norm < 0.1) p->fabric[i].weight *= 0.95; | |
| } | |
| p->mod_attempts++; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * SETTLE — THE COMPUTATIONAL PRIMITIVE | |
| * | |
| * One settle = Kuramoto dynamics evolve until coherence. | |
| * During settle, mode coupling computes products through | |
| * wave interference. Fabric propagates results between vQPUs. | |
| * At the end, harmonic coefficients hold the computation output. | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void settle_ring(phoenix_t *p, int steps) { | |
| double t0 = now_ms(); | |
| for (int s = 0; s < steps; s++) { | |
| /* Evolve all active vQPUs */ | |
| for (int i = 0; i < p->n_hot; i++) | |
| vqpu_step(&p->vqpus[p->hot_set[i]]); | |
| /* Every 5 steps: DFT + fabric propagation */ | |
| if (s % 5 == 0) { | |
| for (int i = 0; i < p->n_hot; i++) | |
| vqpu_dft(&p->vqpus[p->hot_set[i]]); | |
| fabric_propagate(p); | |
| } | |
| } | |
| /* Final DFT to extract products */ | |
| for (int i = 0; i < p->n_hot; i++) | |
| vqpu_dft(&p->vqpus[p->hot_set[i]]); | |
| p->last_settle_ms = now_ms() - t0; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * MODEL INGESTION — decipher shape, encode weights into lenses | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void phoenix_init(phoenix_t *p) { | |
| memset(p, 0, sizeof(*p)); | |
| init_coupling(p); | |
| p->capacity = MAX_VQPUS; | |
| p->vqpus = calloc(MAX_VQPUS, sizeof(vqpu_t)); | |
| p->capacity_conns = MAX_CONNS; | |
| p->fabric = calloc(MAX_CONNS, sizeof(conn_t)); | |
| p->hot_set = calloc(MAX_VQPUS, sizeof(int)); | |
| p->layer_base = calloc(256, sizeof(int)); | |
| p->mode = IDLE; | |
| } | |
| static void phoenix_ingest(phoenix_t *p, const char *path) { | |
| int fd = open(path, O_RDONLY); | |
| if (fd < 0) { fprintf(stderr, "Cannot open %s\n", path); return; } | |
| struct stat st; fstat(fd, &st); | |
| p->weight_base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | |
| p->weights_size = st.st_size; | |
| close(fd); | |
| if (p->weight_base == MAP_FAILED) { p->weight_base = NULL; return; } | |
| /* ── Parse header ── */ | |
| const uint32_t *h = (const uint32_t *)(p->weight_base + 4); | |
| int version = h[0]; | |
| p->D = h[1]; p->FFN = h[2]; p->n_layers = h[3]; | |
| if (version >= 5) { | |
| p->q_dim = h[4]; p->kv_dim = h[5]; p->V = h[6]; | |
| } else { | |
| int n_qh = h[4], n_kvh = h[5]; p->V = h[6]; | |
| int hd = p->D / n_qh; | |
| p->q_dim = n_qh * hd; p->kv_dim = n_kvh * hd; | |
| } | |
| p->weights = p->weight_base + 36; /* 32-byte header + 4-byte n_layers_blocks */ | |
| p->qw = (p->D * p->q_dim + 3) / 4; | |
| p->kw = (p->D * p->kv_dim + 3) / 4; | |
| p->vw = (p->D * p->kv_dim + 3) / 4; | |
| p->ow = (p->q_dim * p->D + 3) / 4; | |
| p->gw = (p->D * p->FFN + 3) / 4; | |
| p->uw = (p->D * p->FFN + 3) / 4; | |
| p->dw = (p->FFN * p->D + 3) / 4; | |
| p->layer_bytes = p->qw + p->kw + p->vw + p->ow + p->gw + p->uw + p->dw; | |
| /* Load RMSNorm from end of .bqsm if present (401152 floats + 4-byte count) */ | |
| if (p->weights_size > 1600000) { | |
| size_t norm_start = p->weights_size - (size_t)401152 * 4 - 4; | |
| uint32_t n_floats; | |
| memcpy(&n_floats, p->weight_base + norm_start, 4); | |
| if (n_floats == 401152) { | |
| const float *ndat = (const float *)(p->weight_base + norm_start + 4); | |
| p->norm_output = malloc(p->D * sizeof(float)); | |
| p->norm_attn = malloc(p->n_layers * p->D * sizeof(float)); | |
| p->norm_q = malloc(p->n_layers * (p->q_dim/16) * sizeof(float)); | |
| p->norm_k = malloc(p->n_layers * (p->kv_dim/8) * sizeof(float)); | |
| p->norm_ffn = malloc(p->n_layers * p->D * sizeof(float)); | |
| if (p->norm_output && p->norm_attn && p->norm_ffn) { | |
| memcpy(p->norm_output, ndat, p->D * sizeof(float)); | |
| int off = p->D; | |
| for (int l = 0; l < p->n_layers; l++) { | |
| memcpy(p->norm_attn + l * p->D, ndat + off, p->D * sizeof(float)); off += p->D; | |
| off += p->q_dim / 16; /* skip q_norm */ | |
| off += p->kv_dim / 8; /* skip k_norm */ | |
| memcpy(p->norm_ffn + l * p->D, ndat + off, p->D * sizeof(float)); off += p->D; | |
| } | |
| p->has_norms = 1; | |
| fprintf(stderr, " Loaded RMSNorm: 401K floats, %d layers\n", p->n_layers); | |
| } | |
| } | |
| } | |
| printf(" Model shape:\n"); | |
| printf(" BQSM v%d | D=%d FFN=%d layers=%d\n", version, p->D, p->FFN, p->n_layers); | |
| printf(" q_dim=%d kv_dim=%d vocab=%d\n", p->q_dim, p->kv_dim, p->V); | |
| printf(" %.2f GB ternary (mmap'd, page-fault on demand)\n\n", st.st_size / 1e9); | |
| /* ═══════════════════════════════════════════════════════════════ | |
| * 4-RING MACRO CORE — self-organizing topology | |
| * | |
| * Instead of fixed pools, we grow the network as we ingest weights. | |
| * 4 core rings (64 osc) form the backbone. Tendrils grow outward, | |
| * wired by traffic-driven Hebbian learning. The structure that | |
| * emerges IS the model — different models → different topologies. | |
| * ═══════════════════════════════════════════════════════════════ */ | |
| macro_core_t *mc = &p->core; | |
| memset(mc, 0, sizeof(*mc)); | |
| printf(" 4-Ring Macro Core — self-organizing topology\n"); | |
| printf(" ─────────────────────────────────────────────\n"); | |
| /* ── Phase 0: Initialize 4 core rings ── */ | |
| for (int r = 0; r < MACRO_RINGS; r++) { | |
| int id = p->n_vqpus++; | |
| mc->ring_id[r] = id; | |
| vqpu_t *v = &p->vqpus[id]; | |
| memset(v, 0, sizeof(*v)); | |
| v->K = 0.8; /* moderate coupling — stay responsive to tendrils */ | |
| v->role = ROLE_RESERVE; | |
| for (int i = 0; i < N_OSC; i++) { | |
| v->theta[i] = 2.0 * M_PI * i / N_OSC + r * M_PI / 2.0; | |
| /* Each core ring gets a distinct gradient lens */ | |
| v->omega[i] = (i - N_OSC / 2.0) * 0.1 * (1.0 + r * 0.3); | |
| } | |
| } | |
| /* Wire backbone: the core rings' fixed inter-connections */ | |
| int RI = mc->ring_id[RING_INTAKE]; | |
| int RA = mc->ring_id[RING_PROC_A]; | |
| int RB = mc->ring_id[RING_PROC_B]; | |
| int RC = mc->ring_id[RING_COLLECT]; | |
| /* INTAKE → processors (activation flows through c₂, c₄) */ | |
| fabric_add(p, RI, RA, CH_PROD2, CH_FUND, 0.30); | |
| fabric_add(p, RI, RA, CH_PROD4, CH_PROD4, 0.40); | |
| fabric_add(p, RI, RB, CH_PROD2, CH_FUND, 0.30); | |
| fabric_add(p, RI, RB, CH_PROD4, CH_PROD4, 0.40); | |
| /* Processors → COLLECT (products flow through c₄, c₆) */ | |
| fabric_add(p, RA, RC, CH_PROD4, CH_FUND, 0.40); | |
| fabric_add(p, RA, RC, CH_PROD6, CH_FUND, 0.30); | |
| fabric_add(p, RB, RC, CH_PROD4, CH_FUND, 0.40); | |
| fabric_add(p, RB, RC, CH_PROD6, CH_FUND, 0.30); | |
| /* COLLECT → INTAKE (ouroboros: output feeds next layer) */ | |
| fabric_add(p, RC, RI, CH_FUND, CH_FUND, 0.25); | |
| /* Processor cross-talk (c₃ channel) */ | |
| fabric_add(p, RA, RB, CH_PROD2, CH_PROD2, 0.15); | |
| fabric_add(p, RB, RA, CH_PROD2, CH_PROD2, 0.15); | |
| printf(" Core: 4 rings (%d osc), %d backbone conns\n", | |
| MACRO_RINGS * N_OSC, p->alive_conns); | |
| /* ── Phase 1: Grow input tendrils (activation → phases) ── */ | |
| int n_input = (p->D + N_OSC - 1) / N_OSC; | |
| mc->input_start = p->n_vqpus; | |
| mc->n_inputs = n_input; | |
| for (int i = 0; i < n_input && p->n_vqpus < p->capacity; i++) { | |
| int id = p->n_vqpus++; | |
| vqpu_t *v = &p->vqpus[id]; | |
| memset(v, 0, sizeof(*v)); | |
| v->K = 1.0; | |
| v->role = ROLE_INPUT; | |
| v->col_start = i * N_OSC; | |
| for (int o = 0; o < N_OSC; o++) | |
| v->theta[o] = 2.0 * M_PI * o / N_OSC; | |
| /* Wire: INTAKE hub ↔ each input tendril */ | |
| fabric_add(p, RI, id, CH_FUND, CH_FUND, 0.15); | |
| fabric_add(p, id, RI, CH_PROD2, CH_PROD2, 0.10); | |
| /* Neighbor chain for wave propagation along input */ | |
| if (i > 0) | |
| fabric_add(p, id - 1, id, CH_FUND, CH_FUND, 0.05); | |
| } | |
| printf(" Input tendrils: %d (D=%d)\n", mc->n_inputs, p->D); | |
| /* ── Phase 2: Grow compute tendrils (weight processors) ── */ | |
| int budget = p->capacity - p->n_vqpus - 40; /* leave reserve */ | |
| int compute_n = budget > 512 ? 512 : (budget > 0 ? budget : 16); | |
| mc->compute_start = p->n_vqpus; | |
| mc->n_compute = compute_n; | |
| for (int i = 0; i < compute_n && p->n_vqpus < p->capacity; i++) { | |
| int id = p->n_vqpus++; | |
| vqpu_t *v = &p->vqpus[id]; | |
| memset(v, 0, sizeof(*v)); | |
| v->K = 1.0; | |
| v->role = ROLE_GATE; | |
| for (int o = 0; o < N_OSC; o++) | |
| v->theta[o] = 2.0 * M_PI * o / N_OSC; | |
| /* Wire to processors — alternate A/B for load distribution */ | |
| int hub = (i % 2 == 0) ? RA : RB; | |
| fabric_add(p, hub, id, CH_FUND, CH_FUND, 0.20); | |
| fabric_add(p, id, hub, CH_PROD4, CH_PROD4, 0.30); | |
| fabric_add(p, id, hub, CH_PROD6, CH_PROD6, 0.20); | |
| /* Also wire input tendrils → compute tendrils for direct coupling */ | |
| int in_id = mc->input_start + (i % mc->n_inputs); | |
| fabric_add(p, in_id, id, CH_PROD2, CH_PROD2, 0.15); | |
| } | |
| printf(" Compute tendrils: %d (weight processors)\n", compute_n); | |
| /* ── Phase 3: Grow output tendrils (product collectors) ── */ | |
| int output_n = 32; | |
| mc->output_start = p->n_vqpus; | |
| mc->n_outputs = output_n; | |
| for (int i = 0; i < output_n && p->n_vqpus < p->capacity; i++) { | |
| int id = p->n_vqpus++; | |
| vqpu_t *v = &p->vqpus[id]; | |
| memset(v, 0, sizeof(*v)); | |
| v->K = 1.0; | |
| v->role = ROLE_OUTPUT; | |
| for (int o = 0; o < N_OSC; o++) | |
| v->theta[o] = 2.0 * M_PI * o / N_OSC; | |
| /* Wire: COLLECT hub ↔ output tendrils */ | |
| fabric_add(p, RC, id, CH_PROD4, CH_FUND, 0.30); | |
| fabric_add(p, id, RC, CH_FUND, CH_FUND, 0.20); | |
| /* Output → input feedback (ouroboros at tendril level) */ | |
| int in_id = mc->input_start + (i % mc->n_inputs); | |
| fabric_add(p, id, in_id, CH_FUND, CH_FUND, 0.10); | |
| } | |
| printf(" Output tendrils: %d (product collectors)\n", output_n); | |
| /* ── Phase 4: Self-organization — ingest weight patterns, adapt ── */ | |
| printf(" Self-organizing...\n"); | |
| int sample_layers = p->n_layers < 3 ? p->n_layers : 3; | |
| for (int layer = 0; layer < sample_layers; layer++) { | |
| const uint8_t *wp = p->weights + (size_t)layer * p->layer_bytes; | |
| int stride = (p->D * p->FFN + 3) / 4 / p->FFN; | |
| /* Load sample weight columns into compute tendrils */ | |
| for (int t = 0; t < mc->n_compute; t++) { | |
| vqpu_t *v = &p->vqpus[mc->compute_start + t]; | |
| decode_ternary_to_lens(wp, t % (p->FFN > 0 ? p->FFN : 1), | |
| stride > 0 ? stride : 1, v->omega); | |
| v->active = 1; | |
| } | |
| /* Seed input tendrils with random activation */ | |
| for (int i = 0; i < mc->n_inputs; i++) { | |
| vqpu_t *v = &p->vqpus[mc->input_start + i]; | |
| double seed[N_OSC]; | |
| for (int o = 0; o < N_OSC; o++) | |
| seed[o] = ((double)rand() / RAND_MAX) * 0.5; | |
| encode_activation(v, seed, N_OSC); | |
| v->active = 1; | |
| } | |
| /* Activate core + outputs */ | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| p->vqpus[mc->ring_id[r]].active = 1; | |
| for (int i = 0; i < mc->n_outputs; i++) | |
| p->vqpus[mc->output_start + i].active = 1; | |
| /* Build hot set */ | |
| p->n_hot = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| if (p->vqpus[i].active) | |
| p->hot_set[p->n_hot++] = i; | |
| /* Longer settle during ingestion — let traffic accumulate */ | |
| settle_ring(p, 10); | |
| /* Measure traffic */ | |
| double total_traffic = 0; | |
| int active_conns = 0; | |
| for (int c = 0; c < p->n_connections; c++) { | |
| if (!p->fabric[c].alive) continue; | |
| total_traffic += p->fabric[c].traffic; | |
| if (p->fabric[c].traffic > 0.001) active_conns++; | |
| } | |
| printf(" Layer %d: traffic=%.4f active=%d/%d conns\n", | |
| layer, total_traffic, active_conns, p->alive_conns); | |
| /* Deactivate */ | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| p->vqpus[i].active = 0; | |
| } | |
| /* Hebbian adaptation: strengthen high-traffic, prune dead */ | |
| double max_traffic = 0; | |
| for (int i = 0; i < p->n_connections; i++) | |
| if (p->fabric[i].alive && p->fabric[i].traffic > max_traffic) | |
| max_traffic = p->fabric[i].traffic; | |
| if (max_traffic > 0.0001) { | |
| int pruned = 0, strengthened = 0; | |
| for (int i = 0; i < p->n_connections; i++) { | |
| if (!p->fabric[i].alive) continue; | |
| double norm = p->fabric[i].traffic / max_traffic; | |
| if (norm > 0.3) { | |
| p->fabric[i].weight *= 1.10; | |
| strengthened++; | |
| } else if (norm < 0.01 && p->fabric[i].traffic < 0.0001) { | |
| p->fabric[i].alive = 0; | |
| p->alive_conns--; | |
| pruned++; | |
| } | |
| } | |
| mc->tendrils_pruned = pruned; | |
| mc->tendrils_strengthened = strengthened; | |
| printf(" Hebbian: strengthened %d, pruned %d connections\n", | |
| strengthened, pruned); | |
| } | |
| mc->ready = 1; | |
| int total_osc = p->n_vqpus * N_OSC; | |
| printf(" Topology: %d vQPUs (%d osc), %d connections\n", | |
| p->n_vqpus, total_osc, p->alive_conns); | |
| printf(" Core: %d osc fixed | Tendrils: %d grown\n", | |
| MACRO_RINGS * N_OSC, | |
| mc->n_inputs + mc->n_compute + mc->n_outputs); | |
| printf(" Connections: %d\n", p->alive_conns); | |
| /* Readout buffer */ | |
| p->readout_dim = p->D; | |
| p->readout = calloc(p->D, sizeof(double)); | |
| p->model_loaded = 1; | |
| p->vqpus_per_layer = mc->n_inputs; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * FORWARD PASS — one settle = one layer, ring propagates all layers | |
| * | |
| * For each layer: | |
| * 1. Load weights into gate vQPU lenses | |
| * 2. Load activation into input vQPU phases | |
| * 3. Settle → mode coupling computes weight × activation | |
| * 4. Read products from all 4 channels | |
| * 5. Fabric carries result to next layer's input | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void phoenix_forward_layer(phoenix_t *p, int layer, | |
| double *x, double *x_out) { | |
| int input_n = (p->D + N_OSC - 1) / N_OSC; | |
| const uint8_t *wp = p->weights + (size_t)layer * p->layer_bytes; | |
| int stride_q = p->q_dim / 4; | |
| /* ── Apply RMSNorm before this layer ── */ | |
| if (p->has_norms && p->norm_attn) { | |
| double ss = 0; | |
| for (int i = 0; i < p->D; i++) ss += x[i] * x[i]; | |
| double rms = sqrt(ss / p->D + 1e-5); | |
| double inv = 1.0 / rms; | |
| for (int i = 0; i < p->D; i++) | |
| x[i] = x[i] * inv * (double)p->norm_attn[layer * p->D + i]; | |
| } | |
| /* ── Load activation into input vQPU phases (wave-rider) ── */ | |
| for (int i = 0; i < input_n; i++) { | |
| vqpu_t *v = &p->vqpus[i]; | |
| encode_activation(v, x + i * N_OSC, | |
| (i * N_OSC + N_OSC <= p->D) ? N_OSC : (p->D - i * N_OSC)); | |
| v->active = 1; | |
| } | |
| /* ── Load weight columns into gate vQPU lenses ── */ | |
| int gate_start = input_n; | |
| int gate_n = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| if (p->vqpus[i].role == ROLE_GATE) { gate_start = i; break; } | |
| for (int i = gate_start; i < p->n_vqpus; i++) { | |
| if (p->vqpus[i].role != ROLE_GATE) break; | |
| /* Encode weight column into lens profile */ | |
| decode_ternary_to_lens(wp, gate_n, stride_q, p->vqpus[i].omega); | |
| p->vqpus[i].active = 1; | |
| gate_n++; | |
| } | |
| /* ── Activate output vQPUs ── */ | |
| int output_start = gate_start + gate_n; | |
| for (int i = output_start; i < p->n_vqpus; i++) { | |
| if (p->vqpus[i].role == ROLE_OUTPUT) { | |
| p->vqpus[i].active = 1; | |
| memset(p->vqpus[i].c_re, 0, sizeof(p->vqpus[i].c_re)); | |
| memset(p->vqpus[i].c_im, 0, sizeof(p->vqpus[i].c_im)); | |
| } | |
| } | |
| /* ── Build hot set ── */ | |
| p->n_hot = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| if (p->vqpus[i].active) | |
| p->hot_set[p->n_hot++] = i; | |
| /* ── SETTLE — this is where the computation happens ── */ | |
| settle_ring(p, SETTLE_STEPS); | |
| /* ── Read products from all 4 interference channels ── */ | |
| memset(x_out, 0, p->D * sizeof(double)); | |
| /* Read from gate vQPUs (products of weight × activation) */ | |
| for (int g = 0; g < gate_n; g++) { | |
| vqpu_t *gv = &p->vqpus[gate_start + g]; | |
| double product = vqpu_read_products(gv, p->g_coupling, p->lens_enhance); | |
| if (g < p->D) x_out[g] += product; | |
| } | |
| /* Read from output vQPUs (accumulated fabric products) */ | |
| for (int i = output_start; i < p->n_vqpus; i++) { | |
| if (p->vqpus[i].role != ROLE_OUTPUT) continue; | |
| int o = i - output_start; | |
| if (o < p->D) x_out[o] += p->vqpus[i].c_re[CH_FUND] * 10.0; | |
| } | |
| /* Residual connection */ | |
| for (int i = 0; i < p->D; i++) | |
| x_out[i] += x[i]; | |
| /* Apply output RMSNorm if this is the last layer */ | |
| if (layer == p->n_layers - 1 && p->has_norms && p->norm_output) { | |
| double ss = 0; | |
| for (int i = 0; i < p->D; i++) ss += x_out[i] * x_out[i]; | |
| double rms = sqrt(ss / p->D + 1e-5); | |
| double inv = 1.0 / rms; | |
| for (int i = 0; i < p->D; i++) | |
| x_out[i] = x_out[i] * inv * (double)p->norm_output[i]; | |
| } | |
| /* Deactivate */ | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| p->vqpus[i].active = 0; | |
| } | |
| static void phoenix_forward(phoenix_t *p, int token) { | |
| if (!p->model_loaded) return; | |
| /* Tokenize: simple one-hot into activation space */ | |
| double *x = calloc(p->D, sizeof(double)); | |
| double *x_out = calloc(p->D, sizeof(double)); | |
| x[token % p->D] = 1.0; | |
| double t0 = now_ms(); | |
| /* Run all layers — each one is a settle */ | |
| for (int layer = 0; layer < p->n_layers; layer++) { | |
| phoenix_forward_layer(p, layer, x, x_out); | |
| memcpy(x, x_out, p->D * sizeof(double)); | |
| } | |
| double elapsed = now_ms() - t0; | |
| /* Readout: copy final activation */ | |
| memcpy(p->readout, x, p->D * sizeof(double)); | |
| /* Sample (argmax over activation) */ | |
| int best = 0; | |
| double best_val = x[0]; | |
| for (int i = 1; i < p->D; i++) | |
| if (fabs(x[i]) > fabs(best_val)) { best_val = x[i]; best = i; } | |
| /* Layer energy profile */ | |
| double max_energy = 0; | |
| for (int i = 0; i < p->D; i++) max_energy += fabs(x[i]); | |
| printf(" tok=%d → sample=%d energy=%.2f " | |
| "settle=%.1fms/layer total=%.1fms (%.2f tok/s)\n", | |
| token, best, max_energy, | |
| elapsed / p->n_layers, elapsed, | |
| elapsed > 0 ? 1000.0 / elapsed : 0); | |
| free(x); | |
| free(x_out); | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * MACRO FORWARD PASS — 4-ring core + tentacle topology | |
| * | |
| * The core rings coordinate. The tendrils compute. | |
| * Activation enters through input tendrils → core INTAKE distributes | |
| * to PROC_A/B → compute tendrils process weight×activation → | |
| * products aggregate at COLLECT → output tendrils produce result. | |
| * Ouroboros: COLLECT feeds back to INTAKE for next layer. | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void macro_forward_layer(phoenix_t *p, int layer, | |
| double *x, double *x_out) { | |
| macro_core_t *mc = &p->core; | |
| const uint8_t *wp = p->weights + (size_t)layer * p->layer_bytes; | |
| int stride_gate = (p->D * p->FFN + 3) / 4 / (p->FFN > 0 ? p->FFN : 1); | |
| /* ── RMSNorm ── */ | |
| if (p->has_norms && p->norm_attn) { | |
| double ss = 0; | |
| for (int i = 0; i < p->D; i++) ss += x[i] * x[i]; | |
| double rms = sqrt(ss / p->D + 1e-5); | |
| double inv = 1.0 / rms; | |
| for (int i = 0; i < p->D; i++) | |
| x[i] = x[i] * inv * (double)p->norm_attn[layer * p->D + i]; | |
| } | |
| /* ── Perturb core rings with layer-specific signal ── */ | |
| /* INTAKE ring absorbs activation summary */ | |
| { | |
| vqpu_t *vi = &p->vqpus[mc->ring_id[RING_INTAKE]]; | |
| for (int i = 0; i < N_OSC; i++) { | |
| double sum = 0; | |
| int stride = p->D / N_OSC; | |
| for (int j = 0; j < stride && i * stride + j < p->D; j++) | |
| sum += x[i * stride + j]; | |
| vi->theta[i] = 2.0 * M_PI * i / N_OSC + sum * M_PI / 4.0; | |
| } | |
| } | |
| /* PROC rings: encode layer signature into phases and omega */ | |
| for (int r = RING_PROC_A; r <= RING_PROC_B; r++) { | |
| vqpu_t *vr = &p->vqpus[mc->ring_id[r]]; | |
| vr->K = 0.3; /* low coupling — stay responsive */ | |
| double phase_offset = layer * 2.0 * M_PI / p->n_layers; | |
| double act_sum = 0; | |
| for (int i = 0; i < p->D; i++) act_sum += x[i] * x[i]; | |
| double act_rms = sqrt(act_sum / p->D + 1e-8); | |
| for (int i = 0; i < N_OSC; i++) { | |
| /* Traveling wave + layer offset + activation modulation */ | |
| vr->theta[i] = 2.0 * M_PI * i / N_OSC + phase_offset | |
| + act_rms * sin(i * 0.39 + r * 1.7) * M_PI / 8.0; | |
| /* Strong gradient + layer-dependent wobble */ | |
| vr->omega[i] = (i - N_OSC / 2.0) * 0.2 * (1.0 + r * 0.5) | |
| + 0.15 * sin(layer * 0.27 + i * 1.1 + r * 0.8); | |
| } | |
| } | |
| /* COLLECT ring: activation-modulated gradient, absorbs from PROC */ | |
| { | |
| vqpu_t *vc = &p->vqpus[mc->ring_id[RING_COLLECT]]; | |
| vc->K = 0.3; | |
| double act_energy = 0; | |
| for (int i = 0; i < p->D; i++) act_energy += fabs(x[i]); | |
| act_energy /= p->D; | |
| for (int i = 0; i < N_OSC; i++) { | |
| int stride = p->D / N_OSC; | |
| double local_act = 0; | |
| for (int j = 0; j < stride && i * stride + j < p->D; j++) | |
| local_act += x[i * stride + j]; | |
| vc->theta[i] = 2.0 * M_PI * i / N_OSC | |
| + local_act * M_PI / 8.0; | |
| vc->omega[i] = (i - N_OSC / 2.0) * 0.2 | |
| + act_energy * sin(i * 0.8 + layer * 0.17); | |
| } | |
| memset(vc->c_re, 0, sizeof(vc->c_re)); | |
| memset(vc->c_im, 0, sizeof(vc->c_im)); | |
| } | |
| /* ── Load activation into input tendrils (wave-rider) ── */ | |
| for (int i = 0; i < mc->n_inputs; i++) { | |
| vqpu_t *v = &p->vqpus[mc->input_start + i]; | |
| int chunk = (i * N_OSC + N_OSC <= p->D) ? N_OSC : (p->D - i * N_OSC); | |
| if (chunk <= 0) break; | |
| encode_activation(v, x + i * N_OSC, chunk); | |
| v->active = 1; | |
| } | |
| /* ── Load weights into compute tendrils — wave-rider style ── */ | |
| /* Skip past q,k,v,o matrices to reach gate matrix */ | |
| const uint8_t *gate_wp = wp + p->qw + p->kw + p->vw + p->ow; | |
| for (int t = 0; t < mc->n_compute; t++) { | |
| vqpu_t *v = &p->vqpus[mc->compute_start + t]; | |
| /* Omega = weight lens (same every token) */ | |
| decode_ternary_to_lens(gate_wp, t, stride_gate, v->omega); | |
| /* Theta = traveling wave + activation perturbation (varies per token) */ | |
| int act_base = (t * N_OSC) % p->D; | |
| for (int i = 0; i < N_OSC; i++) { | |
| double wave = 2.0 * M_PI * i / N_OSC; | |
| double perturb = x[(act_base + i) % p->D] * M_PI / 4.0; | |
| v->theta[i] = wave + perturb; | |
| } | |
| v->active = 1; | |
| } | |
| /* ── Activate core rings ── */ | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| p->vqpus[mc->ring_id[r]].active = 1; | |
| /* ── Clear and activate output tendrils ── */ | |
| for (int i = 0; i < mc->n_outputs; i++) { | |
| vqpu_t *v = &p->vqpus[mc->output_start + i]; | |
| v->active = 1; | |
| memset(v->c_re, 0, sizeof(v->c_re)); | |
| memset(v->c_im, 0, sizeof(v->c_im)); | |
| } | |
| /* ── Build hot set ── */ | |
| p->n_hot = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| if (p->vqpus[i].active) | |
| p->hot_set[p->n_hot++] = i; | |
| /* ── SETTLE — the computation happens here ── */ | |
| settle_ring(p, SETTLE_STEPS); | |
| /* ── Read products from all channels ── */ | |
| memset(x_out, 0, p->D * sizeof(double)); | |
| /* From compute tendrils — scatter products across full D dimension. | |
| * Each tendril's harmonics determine WHERE in the output space | |
| * its product lands. This is the demodulation step. */ | |
| for (int t = 0; t < mc->n_compute; t++) { | |
| vqpu_t *v = &p->vqpus[mc->compute_start + t]; | |
| /* Per-tendril trainable output gain (0 == uninitialized → neutral 1.0) */ | |
| double gain = (v->train_gain != 0.0) ? v->train_gain : 1.0; | |
| double product = vqpu_read_products(v, p->g_coupling, p->lens_enhance) * gain; | |
| /* Scatter using harmonic phase as address */ | |
| for (int k = 1; k < N_HARM; k++) { | |
| if (v->c_mag[k] < 0.001) continue; | |
| double phase_addr = fmod(fabs(v->c_re[k] * 1000.0), (double)p->D); | |
| int idx = (int)phase_addr; | |
| if (idx >= 0 && idx < p->D) | |
| x_out[idx] += product * v->c_mag[k]; | |
| } | |
| /* Also direct map for primary channel */ | |
| int direct_idx = t * (p->D / mc->n_compute); | |
| if (direct_idx < p->D) | |
| x_out[direct_idx] += product * 0.5; | |
| } | |
| /* From core PROC rings — broadcast their interference pattern */ | |
| for (int r = RING_PROC_A; r <= RING_PROC_B; r++) { | |
| vqpu_t *v = &p->vqpus[mc->ring_id[r]]; | |
| double gain = (v->train_gain != 0.0) ? v->train_gain : 1.0; | |
| for (int k = 1; k < N_HARM; k++) { | |
| if (v->c_mag[k] < 0.001) continue; | |
| double product = vqpu_product(v, k, k, p->g_coupling, p->lens_enhance); | |
| /* Broadcast across D using oscillator phases as addresses */ | |
| for (int i = 0; i < N_OSC; i++) { | |
| int idx = (int)(fmod(fabs(v->theta[i]) * p->D / (2.0 * M_PI), p->D)); | |
| if (idx >= 0 && idx < p->D) | |
| x_out[idx] += product * cos(v->theta[i]) * 0.1 * gain; | |
| } | |
| } | |
| } | |
| /* From COLLECT ring — harmonic summary into output */ | |
| { | |
| vqpu_t *vc = &p->vqpus[mc->ring_id[RING_COLLECT]]; | |
| double gain = (vc->train_gain != 0.0) ? vc->train_gain : 1.0; | |
| for (int i = 0; i < p->D; i++) { | |
| double acc = 0; | |
| for (int k = 1; k < N_HARM; k++) | |
| acc += vc->c_re[k] * cos(2.0 * M_PI * k * i / p->D) | |
| + vc->c_im[k] * sin(2.0 * M_PI * k * i / p->D); | |
| x_out[i] += acc * 5.0 * gain; | |
| } | |
| } | |
| /* From output tendrils (fabric-accumulated products) */ | |
| for (int i = 0; i < mc->n_outputs; i++) { | |
| vqpu_t *v = &p->vqpus[mc->output_start + i]; | |
| double gain = (v->train_gain != 0.0) ? v->train_gain : 1.0; | |
| int base = i * (p->D / mc->n_outputs); | |
| int span = p->D / mc->n_outputs; | |
| double val = v->c_re[CH_FUND] * 10.0 * gain; | |
| for (int j = 0; j < span && base + j < p->D; j++) | |
| x_out[base + j] += val; | |
| } | |
| /* ── Residual connection ── */ | |
| for (int i = 0; i < p->D; i++) | |
| x_out[i] += x[i]; | |
| /* ── Output RMSNorm on last layer ── */ | |
| if (layer == p->n_layers - 1 && p->has_norms && p->norm_output) { | |
| double ss = 0; | |
| for (int i = 0; i < p->D; i++) ss += x_out[i] * x_out[i]; | |
| double rms = sqrt(ss / p->D + 1e-5); | |
| double inv = 1.0 / rms; | |
| for (int i = 0; i < p->D; i++) | |
| x_out[i] = x_out[i] * inv * (double)p->norm_output[i]; | |
| } | |
| /* Deactivate everything */ | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| p->vqpus[i].active = 0; | |
| } | |
| static void macro_forward(phoenix_t *p, int token) { | |
| if (!p->model_loaded || !p->core.ready) return; | |
| double *x = calloc(p->D, sizeof(double)); | |
| double *x_out = calloc(p->D, sizeof(double)); | |
| x[token % p->D] = 1.0; | |
| double t0 = now_ms(); | |
| for (int layer = 0; layer < p->n_layers; layer++) { | |
| macro_forward_layer(p, layer, x, x_out); | |
| /* Track signal propagation for first 3 layers */ | |
| if (layer < 3) { | |
| double dot = 0, nx = 0, no = 0; | |
| for (int i = 0; i < p->D; i++) { | |
| dot += x[i] * x_out[i]; | |
| nx += x[i] * x[i]; | |
| no += x_out[i] * x_out[i]; | |
| } | |
| double cos_sim = (nx > 0 && no > 0) | |
| ? dot / sqrt(nx * no) : 0; | |
| printf(" L%d cos(x,out)=%.4f\n", layer, cos_sim); | |
| } | |
| memcpy(x, x_out, p->D * sizeof(double)); | |
| } | |
| double elapsed = now_ms() - t0; | |
| memcpy(p->readout, x, p->D * sizeof(double)); | |
| int best = 0; | |
| double best_val = x[0]; | |
| for (int i = 1; i < p->D; i++) | |
| if (fabs(x[i]) > fabs(best_val)) { best_val = x[i]; best = i; } | |
| double energy = 0; | |
| for (int i = 0; i < p->D; i++) energy += fabs(x[i]); | |
| /* Core ring coherence */ | |
| double core_coh = 0; | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| core_coh += p->vqpus[p->core.ring_id[r]].coherence; | |
| core_coh /= MACRO_RINGS; | |
| printf(" tok=%d → sample=%d energy=%.2f core_coh=%.3f " | |
| "%.1fms/layer %.1fms (%.2f tok/s)\n", | |
| token, best, energy, core_coh, | |
| elapsed / p->n_layers, elapsed, | |
| elapsed > 0 ? 1000.0 / elapsed : 0); | |
| free(x); | |
| free(x_out); | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * DYNAMIC RING LIFECYCLE — spawn, reclaim, sweep | |
| * | |
| * Rings are biological: they grow when needed, retract when idle. | |
| * Core rings (4) are permanent. Everything else is a tendril that | |
| * can appear or disappear based on demand and utilization. | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static int spawn_tendril(phoenix_t *p, int parent_id, int role, | |
| int src_ch, int dst_ch, double weight) { | |
| /* Try to reuse a dormant slot first */ | |
| int id = -1; | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| if (p->vqpus[i].role == ROLE_DORMANT) { id = i; break; } | |
| } | |
| /* No dormant slot — grow if capacity allows */ | |
| if (id < 0) { | |
| if (p->n_vqpus >= p->capacity) return -1; | |
| id = p->n_vqpus++; | |
| } | |
| vqpu_t *v = &p->vqpus[id]; | |
| memset(v, 0, sizeof(*v)); | |
| v->K = 1.0; | |
| v->role = role; | |
| v->age = 0; | |
| v->utilization = 1.0; | |
| for (int i = 0; i < N_OSC; i++) | |
| v->theta[i] = 2.0 * M_PI * i / N_OSC; | |
| /* Wire to parent */ | |
| fabric_add(p, parent_id, id, src_ch, CH_FUND, weight); | |
| fabric_add(p, id, parent_id, CH_PROD4, dst_ch, weight); | |
| return id; | |
| } | |
| static void reclaim_tendril(phoenix_t *p, int id) { | |
| /* Never reclaim core rings */ | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| if (p->core.ring_id[r] == id) return; | |
| /* Kill all connections to/from this ring */ | |
| for (int i = 0; i < p->n_connections; i++) { | |
| if (!p->fabric[i].alive) continue; | |
| if (p->fabric[i].src == id || p->fabric[i].dst == id) { | |
| p->fabric[i].alive = 0; | |
| p->alive_conns--; | |
| } | |
| } | |
| /* Reset to dormant */ | |
| memset(&p->vqpus[id], 0, sizeof(vqpu_t)); | |
| p->vqpus[id].role = ROLE_DORMANT; | |
| } | |
| static int sweep_dormant(phoenix_t *p, double util_threshold) { | |
| int reclaimed = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| if (p->vqpus[i].role == ROLE_DORMANT) continue; | |
| /* Never touch core rings */ | |
| int is_core = 0; | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| if (p->core.ring_id[r] == i) { is_core = 1; break; } | |
| if (is_core) continue; | |
| if (p->vqpus[i].utilization < util_threshold && p->vqpus[i].age > 50) { | |
| reclaim_tendril(p, i); | |
| reclaimed++; | |
| } | |
| } | |
| return reclaimed; | |
| } | |
| /* Count active (non-dormant, non-core) rings */ | |
| static int count_active_tendrils(phoenix_t *p) { | |
| int count = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| if (p->vqpus[i].role == ROLE_DORMANT) continue; | |
| int is_core = 0; | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| if (p->core.ring_id[r] == i) { is_core = 1; break; } | |
| if (!is_core) count++; | |
| } | |
| return count; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * STATE PERSISTENCE — save/load the living topology | |
| * | |
| * The .bqmc file holds the entire macro core state: vQPU phases, | |
| * fabric connections, traffic history, core ring assignments. | |
| * Model weights are NOT saved (they come from the .bqsm file). | |
| * On restart, load .bqmc to resume the evolved topology. | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static int state_save(phoenix_t *p, const char *path) { | |
| FILE *f = fopen(path, "wb"); | |
| if (!f) { fprintf(stderr, "Cannot write state: %s\n", path); return -1; } | |
| /* Header */ | |
| uint32_t magic = STATE_MAGIC; | |
| uint32_t version = STATE_VERSION; | |
| uint32_t nv = p->n_vqpus; | |
| uint32_t nc = p->n_connections; | |
| uint32_t ac = p->alive_conns; | |
| uint32_t tc = p->total_cycles; | |
| fwrite(&magic, 4, 1, f); | |
| fwrite(&version, 4, 1, f); | |
| fwrite(&nv, 4, 1, f); | |
| fwrite(&nc, 4, 1, f); | |
| fwrite(&ac, 4, 1, f); | |
| fwrite(&tc, 4, 1, f); | |
| /* Macro core metadata */ | |
| fwrite(&p->core, sizeof(macro_core_t), 1, f); | |
| /* Physics constants */ | |
| fwrite(p->g_coupling, sizeof(p->g_coupling), 1, f); | |
| fwrite(p->lens_enhance, sizeof(p->lens_enhance), 1, f); | |
| /* Model dimensions (needed to verify on reload) */ | |
| uint32_t dims[6] = { p->D, p->FFN, p->n_layers, p->q_dim, p->kv_dim, p->V }; | |
| fwrite(dims, sizeof(dims), 1, f); | |
| /* All vQPU state — phases, omegas, harmonics, everything */ | |
| fwrite(p->vqpus, sizeof(vqpu_t), nv, f); | |
| /* All fabric connections */ | |
| fwrite(p->fabric, sizeof(conn_t), nc, f); | |
| long size = ftell(f); | |
| fclose(f); | |
| printf(" [STATE] Saved %d vQPUs, %d conns → %s (%.1f KB)\n", | |
| nv, ac, path, size / 1024.0); | |
| return 0; | |
| } | |
| static int state_load(phoenix_t *p, const char *path) { | |
| FILE *f = fopen(path, "rb"); | |
| if (!f) return -1; /* no state file — fresh start */ | |
| uint32_t magic, version, nv, nc, ac, tc; | |
| if (fread(&magic, 4, 1, f) != 1 || magic != STATE_MAGIC) { | |
| fprintf(stderr, " [STATE] Bad magic in %s\n", path); | |
| fclose(f); return -1; | |
| } | |
| fread(&version, 4, 1, f); | |
| fread(&nv, 4, 1, f); | |
| fread(&nc, 4, 1, f); | |
| fread(&ac, 4, 1, f); | |
| fread(&tc, 4, 1, f); | |
| if (version != STATE_VERSION) { | |
| fprintf(stderr, " [STATE] Version mismatch (got %d, want %d)\n", | |
| version, STATE_VERSION); | |
| fclose(f); return -1; | |
| } | |
| /* Macro core metadata */ | |
| fread(&p->core, sizeof(macro_core_t), 1, f); | |
| /* Physics constants */ | |
| fread(p->g_coupling, sizeof(p->g_coupling), 1, f); | |
| fread(p->lens_enhance, sizeof(p->lens_enhance), 1, f); | |
| /* Verify model dimensions match */ | |
| uint32_t dims[6]; | |
| fread(dims, sizeof(dims), 1, f); | |
| if ((int)dims[0] != p->D || (int)dims[2] != p->n_layers) { | |
| fprintf(stderr, " [STATE] Model mismatch: state D=%d vs model D=%d\n", | |
| dims[0], p->D); | |
| fclose(f); return -1; | |
| } | |
| /* Load vQPU state */ | |
| if (nv > (uint32_t)p->capacity) nv = p->capacity; | |
| fread(p->vqpus, sizeof(vqpu_t), nv, f); | |
| p->n_vqpus = nv; | |
| /* Load fabric */ | |
| if (nc > (uint32_t)p->capacity_conns) nc = p->capacity_conns; | |
| fread(p->fabric, sizeof(conn_t), nc, f); | |
| p->n_connections = nc; | |
| p->alive_conns = 0; | |
| for (int i = 0; i < (int)nc; i++) | |
| if (p->fabric[i].alive) p->alive_conns++; | |
| p->total_cycles = tc; | |
| fclose(f); | |
| printf(" [STATE] Loaded %d vQPUs, %d conns, %d cycles from %s\n", | |
| p->n_vqpus, p->alive_conns, p->total_cycles, path); | |
| return 0; | |
| } | |
| /* ── Self-verification: check (and optionally repair) structural coherence ── | |
| * | |
| * A self-restructuring topology can evolve into an inconsistent state: a | |
| * connection left pointing at a reclaimed vQPU, counts drifting out of sync | |
| * with the real population, or an oscillator phase gone NaN. Any of those | |
| * makes the next forward pass dereference garbage and crash. The optimizer | |
| * chases a score, not its own integrity — so this is the guard that keeps | |
| * "self-modifying" from meaning "self-destructing." | |
| * | |
| * With repair=1 it fixes what it can: | |
| * - drops connections whose src/dst are out of range or dormant | |
| * - drops connections with invalid harmonic channels | |
| * - recomputes alive_conns to match reality | |
| * - clamps n_vqpus / n_connections to capacity | |
| * - resets any non-finite phase / frequency / harmonic to a safe value | |
| * If a load-bearing core ring is invalid the damage is unrepairable and it | |
| * returns INTEGRITY_FATAL so the caller can discard the state and re-ingest. | |
| * | |
| * Returns the number of problems found (0 == clean). */ | |
| static int verify_integrity(phoenix_t *p, int repair) { | |
| int problems = 0; | |
| /* Population counts within bounds */ | |
| if (p->n_vqpus < 0 || p->n_vqpus > p->capacity) { | |
| problems++; | |
| if (repair) p->n_vqpus = p->n_vqpus < 0 ? 0 : | |
| (p->n_vqpus > p->capacity ? p->capacity : p->n_vqpus); | |
| } | |
| if (p->n_connections < 0 || p->n_connections > p->capacity_conns) { | |
| problems++; | |
| if (repair) p->n_connections = p->n_connections < 0 ? 0 : | |
| (p->n_connections > p->capacity_conns ? p->capacity_conns : p->n_connections); | |
| } | |
| /* Core rings are load-bearing — if any is invalid the state is unusable */ | |
| for (int r = 0; r < MACRO_RINGS; r++) { | |
| int id = p->core.ring_id[r]; | |
| if (id < 0 || id >= p->n_vqpus || p->vqpus[id].role == ROLE_DORMANT) | |
| return INTEGRITY_FATAL + problems; | |
| } | |
| /* Every alive connection must reference in-range, non-dormant vQPUs | |
| * through valid harmonic channels */ | |
| int alive = 0; | |
| for (int i = 0; i < p->n_connections; i++) { | |
| conn_t *c = &p->fabric[i]; | |
| if (!c->alive) continue; | |
| int bad = (c->src < 0 || c->src >= p->n_vqpus || | |
| c->dst < 0 || c->dst >= p->n_vqpus || | |
| c->src_harm < 0 || c->src_harm >= N_HARM || | |
| c->dst_harm < 0 || c->dst_harm >= N_HARM); | |
| if (!bad && (p->vqpus[c->src].role == ROLE_DORMANT || | |
| p->vqpus[c->dst].role == ROLE_DORMANT)) | |
| bad = 1; | |
| if (bad) { | |
| problems++; | |
| if (repair) { c->alive = 0; continue; } | |
| } | |
| alive++; | |
| } | |
| if (repair) p->alive_conns = alive; | |
| else if (alive != p->alive_conns) problems++; | |
| /* Sanitize oscillator state — a single NaN phase silently poisons the | |
| * Kuramoto step for the whole ring */ | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| vqpu_t *v = &p->vqpus[i]; | |
| for (int o = 0; o < N_OSC; o++) { | |
| if (!isfinite(v->theta[o])) { problems++; if (repair) v->theta[o] = 2.0 * M_PI * o / N_OSC; } | |
| if (!isfinite(v->omega[o])) { problems++; if (repair) v->omega[o] = 0.0; } | |
| } | |
| for (int k = 0; k < N_HARM; k++) { | |
| if (!isfinite(v->c_re[k])) { problems++; if (repair) v->c_re[k] = 0.0; } | |
| if (!isfinite(v->c_im[k])) { problems++; if (repair) v->c_im[k] = 0.0; } | |
| } | |
| } | |
| return problems; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * CONTINUOUS FORWARD — living inference with demand-driven growth | |
| * | |
| * Phase state carries between tokens. Rings spawn when compute | |
| * demand saturates existing tendrils. Idle rings get reclaimed. | |
| * The topology continuously evolves. | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void continuous_forward_layer(phoenix_t *p, int layer, | |
| double *x, double *x_out) { | |
| macro_core_t *mc = &p->core; | |
| const uint8_t *wp = p->weights + (size_t)layer * p->layer_bytes; | |
| int stride_gate = (p->D * p->FFN + 3) / 4 / (p->FFN > 0 ? p->FFN : 1); | |
| /* ── RMSNorm ── */ | |
| if (p->has_norms && p->norm_attn) { | |
| double ss = 0; | |
| for (int i = 0; i < p->D; i++) ss += x[i] * x[i]; | |
| double rms = sqrt(ss / p->D + 1e-5); | |
| double inv = 1.0 / rms; | |
| for (int i = 0; i < p->D; i++) | |
| x[i] = x[i] * inv * (double)p->norm_attn[layer * p->D + i]; | |
| } | |
| /* ── Core ring perturbation ── */ | |
| /* INTAKE: blend activation into existing phase state */ | |
| { | |
| vqpu_t *vi = &p->vqpus[mc->ring_id[RING_INTAKE]]; | |
| vi->K = 0.3; | |
| for (int i = 0; i < N_OSC; i++) { | |
| double sum = 0; | |
| int stride = p->D / N_OSC; | |
| for (int j = 0; j < stride && i * stride + j < p->D; j++) | |
| sum += x[i * stride + j]; | |
| /* BLEND — don't replace. Continuous state. */ | |
| vi->theta[i] = vi->theta[i] * 0.6 | |
| + (2.0 * M_PI * i / N_OSC + sum * M_PI / 4.0) * 0.4; | |
| } | |
| vi->utilization += 1.0; | |
| } | |
| /* PROC rings: blend layer signature into existing state */ | |
| for (int r = RING_PROC_A; r <= RING_PROC_B; r++) { | |
| vqpu_t *vr = &p->vqpus[mc->ring_id[r]]; | |
| vr->K = 0.3; | |
| double phase_offset = layer * 2.0 * M_PI / p->n_layers; | |
| double act_sum = 0; | |
| for (int i = 0; i < p->D; i++) act_sum += x[i] * x[i]; | |
| double act_rms = sqrt(act_sum / p->D + 1e-8); | |
| for (int i = 0; i < N_OSC; i++) { | |
| double target = 2.0 * M_PI * i / N_OSC + phase_offset | |
| + act_rms * sin(i * 0.39 + r * 1.7) * M_PI / 8.0; | |
| /* Blend: carry 70% of old state, inject 30% new */ | |
| vr->theta[i] = vr->theta[i] * 0.7 + target * 0.3; | |
| vr->omega[i] = (i - N_OSC / 2.0) * 0.2 * (1.0 + r * 0.5) | |
| + 0.15 * sin(layer * 0.27 + i * 1.1 + r * 0.8); | |
| } | |
| vr->utilization += 1.0; | |
| } | |
| /* COLLECT: blend reset */ | |
| { | |
| vqpu_t *vc = &p->vqpus[mc->ring_id[RING_COLLECT]]; | |
| vc->K = 0.3; | |
| double act_energy = 0; | |
| for (int i = 0; i < p->D; i++) act_energy += fabs(x[i]); | |
| act_energy /= p->D; | |
| for (int i = 0; i < N_OSC; i++) { | |
| int stride = p->D / N_OSC; | |
| double local_act = 0; | |
| for (int j = 0; j < stride && i * stride + j < p->D; j++) | |
| local_act += x[i * stride + j]; | |
| double target = 2.0 * M_PI * i / N_OSC + local_act * M_PI / 8.0; | |
| vc->theta[i] = vc->theta[i] * 0.5 + target * 0.5; | |
| vc->omega[i] = (i - N_OSC / 2.0) * 0.2 | |
| + act_energy * sin(i * 0.8 + layer * 0.17); | |
| } | |
| /* Partial reset of harmonics (not full wipe) */ | |
| for (int k = 0; k < N_HARM; k++) { | |
| vc->c_re[k] *= 0.3; | |
| vc->c_im[k] *= 0.3; | |
| } | |
| vc->utilization += 1.0; | |
| } | |
| /* ── Input tendrils: blend activation (continuous state) ── */ | |
| for (int i = 0; i < mc->n_inputs; i++) { | |
| vqpu_t *v = &p->vqpus[mc->input_start + i]; | |
| if (v->role == ROLE_DORMANT) continue; | |
| int chunk = (i * N_OSC + N_OSC <= p->D) ? N_OSC : (p->D - i * N_OSC); | |
| if (chunk <= 0) break; | |
| for (int o = 0; o < N_OSC; o++) { | |
| double wave = 2.0 * M_PI * o / N_OSC; | |
| double perturb = (o < chunk) ? x[i * N_OSC + o] * M_PI / 4.0 : 0.0; | |
| /* Blend: 60% new signal, 40% carried state */ | |
| v->theta[o] = v->theta[o] * 0.4 + (wave + perturb) * 0.6; | |
| } | |
| v->active = 1; | |
| v->utilization += 0.5; | |
| } | |
| /* ── Compute tendrils: rotating window per layer ── */ | |
| /* Only a subset of tendrils are active per layer. | |
| * This creates lifecycle: used tendrils strengthen, | |
| * unused ones decay → reclaim → replaced by fresh spawns. */ | |
| const uint8_t *gate_wp = wp + p->qw + p->kw + p->vw + p->ow; | |
| int compute_used = 0; | |
| int window_size = mc->n_compute / 4; | |
| if (window_size < 32) window_size = 32; | |
| if (window_size > mc->n_compute) window_size = mc->n_compute; | |
| int window_start = (layer * window_size / 3) % mc->n_compute; | |
| for (int w = 0; w < window_size; w++) { | |
| int t = (window_start + w) % mc->n_compute; | |
| int tid = mc->compute_start + t; | |
| if (tid >= p->n_vqpus) break; | |
| vqpu_t *v = &p->vqpus[tid]; | |
| if (v->role == ROLE_DORMANT) continue; | |
| decode_ternary_to_lens(gate_wp, t, stride_gate, v->omega); | |
| int act_base = (t * N_OSC) % p->D; | |
| for (int i = 0; i < N_OSC; i++) { | |
| double wave = 2.0 * M_PI * i / N_OSC; | |
| double perturb = x[(act_base + i) % p->D] * M_PI / 4.0; | |
| v->theta[i] = v->theta[i] * 0.3 + (wave + perturb) * 0.7; | |
| } | |
| v->active = 1; | |
| v->utilization += 1.0; | |
| compute_used++; | |
| } | |
| /* ── Activate core + output ── */ | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| p->vqpus[mc->ring_id[r]].active = 1; | |
| for (int i = 0; i < mc->n_outputs; i++) { | |
| int oid = mc->output_start + i; | |
| if (oid >= p->n_vqpus) break; | |
| vqpu_t *v = &p->vqpus[oid]; | |
| if (v->role == ROLE_DORMANT) continue; | |
| v->active = 1; | |
| /* Partial harmonic decay (not full wipe) */ | |
| for (int k = 0; k < N_HARM; k++) { | |
| v->c_re[k] *= 0.2; | |
| v->c_im[k] *= 0.2; | |
| } | |
| v->utilization += 0.5; | |
| } | |
| /* ── Build hot set + SETTLE ── */ | |
| p->n_hot = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| if (p->vqpus[i].active) | |
| p->hot_set[p->n_hot++] = i; | |
| settle_ring(p, SETTLE_STEPS); | |
| /* ── Read products (same scatter readout as macro_forward_layer) ── */ | |
| memset(x_out, 0, p->D * sizeof(double)); | |
| /* Compute tendrils: harmonic scatter */ | |
| double max_product = 0; | |
| int saturated_count = 0; | |
| for (int t = 0; t < mc->n_compute; t++) { | |
| int tid = mc->compute_start + t; | |
| if (tid >= p->n_vqpus || p->vqpus[tid].role == ROLE_DORMANT) continue; | |
| vqpu_t *v = &p->vqpus[tid]; | |
| double product = vqpu_read_products(v, p->g_coupling, p->lens_enhance); | |
| if (fabs(product) > max_product) max_product = fabs(product); | |
| if (fabs(product) > 0.5) saturated_count++; | |
| for (int k = 1; k < N_HARM; k++) { | |
| if (v->c_mag[k] < 0.001) continue; | |
| double phase_addr = fmod(fabs(v->c_re[k] * 1000.0), (double)p->D); | |
| int idx = (int)phase_addr; | |
| if (idx >= 0 && idx < p->D) | |
| x_out[idx] += product * v->c_mag[k]; | |
| } | |
| int direct_idx = t * (p->D / (mc->n_compute > 0 ? mc->n_compute : 1)); | |
| if (direct_idx < p->D) | |
| x_out[direct_idx] += product * 0.5; | |
| } | |
| /* Core PROC broadcast */ | |
| for (int r = RING_PROC_A; r <= RING_PROC_B; r++) { | |
| vqpu_t *v = &p->vqpus[mc->ring_id[r]]; | |
| for (int k = 1; k < N_HARM; k++) { | |
| if (v->c_mag[k] < 0.001) continue; | |
| double product = vqpu_product(v, k, k, p->g_coupling, p->lens_enhance); | |
| for (int i = 0; i < N_OSC; i++) { | |
| int idx = (int)(fmod(fabs(v->theta[i]) * p->D / (2.0 * M_PI), p->D)); | |
| if (idx >= 0 && idx < p->D) | |
| x_out[idx] += product * cos(v->theta[i]) * 0.1; | |
| } | |
| } | |
| } | |
| /* COLLECT harmonic summary */ | |
| { | |
| vqpu_t *vc = &p->vqpus[mc->ring_id[RING_COLLECT]]; | |
| for (int i = 0; i < p->D; i++) { | |
| double acc = 0; | |
| for (int k = 1; k < N_HARM; k++) | |
| acc += vc->c_re[k] * cos(2.0 * M_PI * k * i / p->D) | |
| + vc->c_im[k] * sin(2.0 * M_PI * k * i / p->D); | |
| x_out[i] += acc * 5.0; | |
| } | |
| } | |
| /* Output tendrils */ | |
| for (int i = 0; i < mc->n_outputs; i++) { | |
| int oid = mc->output_start + i; | |
| if (oid >= p->n_vqpus || p->vqpus[oid].role == ROLE_DORMANT) continue; | |
| vqpu_t *v = &p->vqpus[oid]; | |
| int base = i * (p->D / mc->n_outputs); | |
| int span = p->D / mc->n_outputs; | |
| double val = v->c_re[CH_FUND] * 10.0; | |
| for (int j = 0; j < span && base + j < p->D; j++) | |
| x_out[base + j] += val; | |
| } | |
| /* Residual */ | |
| for (int i = 0; i < p->D; i++) | |
| x_out[i] += x[i]; | |
| /* Output RMSNorm on last layer */ | |
| if (layer == p->n_layers - 1 && p->has_norms && p->norm_output) { | |
| double ss = 0; | |
| for (int i = 0; i < p->D; i++) ss += x_out[i] * x_out[i]; | |
| double rms = sqrt(ss / p->D + 1e-5); | |
| double inv = 1.0 / rms; | |
| for (int i = 0; i < p->D; i++) | |
| x_out[i] = x_out[i] * inv * (double)p->norm_output[i]; | |
| } | |
| /* ── Demand-driven spawning ── */ | |
| /* If >80% of compute tendrils are saturated, grow more */ | |
| if (compute_used > 0 && saturated_count > compute_used * 8 / 10) { | |
| int grow = compute_used / 10; | |
| if (grow < 4) grow = 4; | |
| if (grow > 32) grow = 32; | |
| int grown = 0; | |
| for (int g = 0; g < grow; g++) { | |
| int hub = (g % 2 == 0) | |
| ? mc->ring_id[RING_PROC_A] | |
| : mc->ring_id[RING_PROC_B]; | |
| int id = spawn_tendril(p, hub, ROLE_GATE, | |
| CH_FUND, CH_PROD4, 0.25); | |
| if (id >= 0) { | |
| mc->n_compute++; | |
| grown++; | |
| } | |
| } | |
| if (grown > 0) | |
| printf(" [SPAWN] +%d compute tendrils (demand: %d/%d saturated)\n", | |
| grown, saturated_count, compute_used); | |
| } | |
| /* Deactivate */ | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| p->vqpus[i].active = 0; | |
| /* Age all tendrils — faster decay drives lifecycle */ | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| p->vqpus[i].age++; | |
| p->vqpus[i].utilization *= 0.95; | |
| } | |
| } | |
| /* Forward declarations for JSON state emitter */ | |
| static void emit_state(const phoenix_t *p, const char *event); | |
| static void emit_token(const phoenix_t *p, int pos, int tok, int sample, | |
| double energy, double elapsed); | |
| /* Interference-wave activation constants. | |
| * PHASE_GAMMA — how strongly the per-layer weight drive rotates the phase | |
| * PHASE_WAVELEN— carrier wavelength (dims) the field rides on (wave-rider) | |
| * The propagating state is a complex phasor field that STAYS ON THE UNIT | |
| * CIRCLE: magnitude never collapses, so there is no fixed point to fall | |
| * into. The token's embedding seeds the phase; each layer's physics rotates | |
| * it (interference = phase accumulation). Different tokens seed different | |
| * phase, so the readout stays input-dependent across all layers instead of | |
| * relaxing to the rings' intrinsic attractor. */ | |
| /* ── Shared interference-wave forward ── | |
| * Fills z[D] with the final phasor field (real part). The propagating state | |
| * is a unit-magnitude complex field: the token's embedding seeds the phase, | |
| * each layer's weight physics rotates it (interference = phase accumulation), | |
| * and the magnitude never collapses. BOTH inference and training call this, | |
| * so the self-tuner optimizes the exact computation that generates tokens. */ | |
| static void phase_forward(phoenix_t *p, int token, double *z) { | |
| double *emb = calloc(p->D, sizeof(double)); | |
| double *phi = calloc(p->D, sizeof(double)); | |
| double *x_out = calloc(p->D, sizeof(double)); | |
| embed_token(p, token, emb); | |
| for (int d = 0; d < p->D; d++) { | |
| phi[d] = emb[d] * (M_PI / 2.0); | |
| z[d] = cos(2.0 * M_PI * d / PHASE_WAVELEN + phi[d]); | |
| } | |
| for (int layer = 0; layer < p->n_layers; layer++) { | |
| macro_forward_layer(p, layer, z, x_out); | |
| for (int d = 0; d < p->D; d++) { | |
| phi[d] += PHASE_GAMMA * x_out[d]; | |
| z[d] = cos(2.0 * M_PI * d / PHASE_WAVELEN + phi[d]); | |
| } | |
| } | |
| free(emb); free(phi); free(x_out); | |
| } | |
| static int continuous_forward(phoenix_t *p, int token, int token_pos) { | |
| if (!p->model_loaded || !p->core.ready) return -1; | |
| double *z = calloc(p->D, sizeof(double)); | |
| double t0 = now_ms(); | |
| phase_forward(p, token, z); | |
| double elapsed = now_ms() - t0; | |
| memcpy(p->readout, z, p->D * sizeof(double)); | |
| int best = project_to_vocab(p, z); | |
| double energy = 0; | |
| for (int i = 0; i < p->D; i++) energy += fabs(z[i]); | |
| /* Core coherences */ | |
| double core_coh[MACRO_RINGS]; | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| core_coh[r] = p->vqpus[p->core.ring_id[r]].coherence; | |
| int active = count_active_tendrils(p); | |
| printf(" [%3d] tok=%d → %d E=%.0f " | |
| "coh=[%.2f %.2f %.2f %.2f] " | |
| "tendrils=%d conns=%d %.1fms (%.1f t/s)\n", | |
| token_pos, token, best, energy, | |
| core_coh[0], core_coh[1], core_coh[2], core_coh[3], | |
| active, p->alive_conns, elapsed, | |
| elapsed > 0 ? 1000.0 / elapsed : 0); | |
| p->total_cycles++; | |
| emit_token(p, token_pos, token, best, energy, elapsed); | |
| free(z); | |
| return best; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * SCHEDULER + THOUGHT CYCLES (self-modification between inferences) | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void phoenix_idle_cycle(phoenix_t *p) { | |
| double t0 = now_ms(); | |
| ckpt_check(p); | |
| /* Compute ring coherence */ | |
| double sum = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) sum += p->vqpus[i].coherence; | |
| p->ring_coherence = sum / p->n_vqpus; | |
| if (!p->ckpt.pending) { | |
| if (p->total_cycles % 30 == 15 && p->alive_conns > 20) | |
| propose_prune(p); | |
| if (p->total_cycles % 40 == 25) | |
| propose_strengthen(p); | |
| if (p->total_cycles % 100 == 99) { | |
| double avg_util = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) | |
| avg_util += p->vqpus[i].utilization; | |
| avg_util /= p->n_vqpus; | |
| if (avg_util > 0.6 && p->n_vqpus + 10 <= p->capacity) | |
| propose_grow(p, 10); | |
| } | |
| } | |
| /* Light settle on a subset */ | |
| p->n_hot = 0; | |
| for (int i = 0; i < p->n_vqpus && p->n_hot < 30; i++) { | |
| p->hot_set[p->n_hot++] = i; | |
| p->vqpus[i].active = 1; | |
| } | |
| settle_ring(p, 20); | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| p->vqpus[i].active = 0; | |
| p->vqpus[i].age++; | |
| p->vqpus[i].utilization *= 0.99; | |
| } | |
| p->total_cycles++; | |
| p->last_cycle_ms = now_ms() - t0; | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * MAIN | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| static void phoenix_free(phoenix_t *p) { | |
| free(p->vqpus); | |
| free(p->fabric); | |
| free(p->hot_set); | |
| free(p->layer_base); | |
| free(p->readout); | |
| free(p->ckpt.vqpus); | |
| free(p->ckpt.fabric); | |
| if (p->weight_base) | |
| munmap((void *)p->weight_base, p->weights_size); | |
| } | |
| /* ── Build state file path from model path ── */ | |
| static void make_state_path(const char *model_path, char *out, int maxlen) { | |
| strncpy(out, model_path, maxlen - 6); | |
| out[maxlen - 6] = '\0'; | |
| char *dot = strrchr(out, '.'); | |
| if (dot) *dot = '\0'; | |
| strcat(out, ".bqmc"); | |
| } | |
| /* ── JSON state emitter for real-time dashboard ── | |
| * Emits one JSON line per event to a state log file. | |
| * The Python dashboard tails this file and renders live. */ | |
| static FILE *g_state_log = NULL; | |
| static void emit_state(const phoenix_t *p, const char *event) { | |
| if (!g_state_log) return; | |
| double coh[MACRO_RINGS]; | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| coh[r] = p->vqpus[p->core.ring_id[r]].coherence; | |
| double c2=0, c4=0, c6=0; | |
| for (int r = 0; r < MACRO_RINGS; r++) { | |
| c2 += p->vqpus[p->core.ring_id[r]].c_mag[CH_PROD2]; | |
| c4 += p->vqpus[p->core.ring_id[r]].c_mag[CH_PROD4]; | |
| c6 += p->vqpus[p->core.ring_id[r]].c_mag[CH_PROD6]; | |
| } | |
| fprintf(g_state_log, | |
| "{\"event\":\"%s\",\"tendrils\":%d,\"conns\":%d,\"coh\":[%.4f,%.4f,%.4f,%.4f]," | |
| "\"c2\":%.4f,\"c4\":%.4f,\"c6\":%.4f,\"cycles\":%d," | |
| "\"tune_imp\":%d,\"tune_rev\":%d,\"tune_best\":%.2f}\n", | |
| event, | |
| count_active_tendrils(p), p->alive_conns, | |
| coh[0], coh[1], coh[2], coh[3], | |
| c2, c4, c6, p->total_cycles, | |
| p->tune.improve_count, p->tune.revert_count, p->tune.best_score); | |
| fflush(g_state_log); | |
| } | |
| static void emit_token(const phoenix_t *p, int pos, int tok, int sample, | |
| double energy, double elapsed) { | |
| if (!g_state_log) return; | |
| double coh[MACRO_RINGS]; | |
| for (int r = 0; r < MACRO_RINGS; r++) | |
| coh[r] = p->vqpus[p->core.ring_id[r]].coherence; | |
| fprintf(g_state_log, | |
| "{\"event\":\"token\",\"pos\":%d,\"tok\":%d,\"sample\":%d," | |
| "\"energy\":%.2f,\"elapsed_ms\":%.1f,\"tok_per_s\":%.1f," | |
| "\"tendrils\":%d,\"conns\":%d," | |
| "\"coh\":[%.4f,%.4f,%.4f,%.4f]," | |
| "\"tune_imp\":%d,\"tune_rev\":%d,\"tune_best\":%.2f}\n", | |
| pos, tok, sample, energy, elapsed, | |
| elapsed > 0 ? 1000.0/elapsed : 0, | |
| count_active_tendrils(p), p->alive_conns, | |
| coh[0], coh[1], coh[2], coh[3], | |
| p->tune.improve_count, p->tune.revert_count, p->tune.best_score); | |
| fflush(g_state_log); | |
| } | |
| /* ═══════════════════════════════════════════════════════════════════ | |
| * SELF-TUNING SYSTEM | |
| * | |
| * The system fine-tunes its own omega (lens) profiles through | |
| * sparse perturbation + evaluation. Like LoRA: learn a residual | |
| * adjustment on top of frozen ternary weights. | |
| * | |
| * Cycle: perturb omega on N tendrils → run batch → measure quality | |
| * → if better, commit (keep perturbation) → if worse, revert. | |
| * | |
| * Quality metric: output diversity (how many distinct predictions) | |
| * + output confidence (inverse entropy of argmax distribution). | |
| * No labels needed — self-supervised on intrinsic signal quality. | |
| * | |
| * SOLIDIFY: After many perturbation rounds, accumulated omega | |
| * adjustments are "solidified" — the structure re-optimizes: | |
| * 1. Prune tendrils whose omega drifted toward zero (low contribution) | |
| * 2. Strengthen tendrils with high-traffic, high-omega-magnitude | |
| * 3. Rewire connections based on accumulated traffic patterns | |
| * 4. Reset perturbation baseline to the new solidified state | |
| * ═══════════════════════════════════════════════════════════════════ */ | |
| /* ── Load training data from a text file ── | |
| * Reads token IDs (one per line, or space-separated) from a file. | |
| * If file doesn't exist, generates a simple sequence for self-supervision. */ | |
| static int tune_load_data(phoenix_t *p, const char *path) { | |
| FILE *f = fopen(path, "r"); | |
| if (!f) { | |
| /* No training file: generate synthetic sequence */ | |
| int n = 256; | |
| p->tune.train_tokens = malloc(n * sizeof(int)); | |
| p->tune.n_train = n; | |
| for (int i = 0; i < n; i++) | |
| p->tune.train_tokens[i] = i; /* tokens 0..255 */ | |
| p->tune.train_pos = 0; | |
| return n; | |
| } | |
| /* Read token IDs from file */ | |
| int capacity = 1024; | |
| p->tune.train_tokens = malloc(capacity * sizeof(int)); | |
| p->tune.n_train = 0; | |
| int tok; | |
| while (fscanf(f, "%d", &tok) == 1) { | |
| if (p->tune.n_train >= capacity) { | |
| capacity *= 2; | |
| p->tune.train_tokens = realloc(p->tune.train_tokens, capacity * sizeof(int)); | |
| } | |
| p->tune.train_tokens[p->tune.n_train++] = tok; | |
| } | |
| fclose(f); | |
| p->tune.train_pos = 0; | |
| return p->tune.n_train; | |
| } | |
| /* ── Vocab statistics for the next-token objective (sampled) ── | |
| * The training reward only needs to know how favored the true target is | |
| * relative to the rest of the vocabulary — NOT the exact full-vocab argmax. | |
| * Computing the target's logit exactly and estimating the logit distribution | |
| * from a uniform stride sample of TRAIN_SAMPLE tokens turns an O(V·D) pass | |
| * (262k×3840 ≈ 1e9 ops) into O(SAMPLE·D) (~1e6) — about 1000× cheaper — while | |
| * preserving the z-score signal the hill-climber climbs. Inference still uses | |
| * the exact project_to_vocab; only training uses this estimate. | |
| * | |
| * best_id is the argmax over {target} ∪ sample, so pred==target means the | |
| * target out-scored every sampled token (a cheap top-of-vocab proxy). */ | |
| static void vocab_stats(phoenix_t *p, const double *x, int target, | |
| int *best_id, double *target_logit, | |
| double *mean_out, double *std_out) { | |
| const uint8_t *lm_head = p->weights + (size_t)p->layer_bytes * p->n_layers; | |
| int stride = p->V / 4; | |
| /* Exact logit for the true target token */ | |
| double tl = 0; | |
| { | |
| int byte_idx = target / 4, sh = (target % 4) * 2; | |
| for (int d = 0; d < p->D; d++) { | |
| int b = (lm_head[d * stride + byte_idx] >> sh) & 0x03; | |
| if (b == 0) tl -= x[d]; | |
| else if (b == 2) tl += x[d]; | |
| } | |
| } | |
| /* Estimate the logit distribution from a uniform stride sample */ | |
| int step = p->V / TRAIN_SAMPLE; | |
| if (step < 1) step = 1; | |
| double best_logit = -1e30, sum = 0, sumsq = 0; | |
| int bid = target, cnt = 0; | |
| { | |
| double lb = -1e30, s = 0, ss = 0; | |
| int li = target, c = 0; | |
| for (int idx = 0; idx < TRAIN_SAMPLE; idx++) { | |
| int v = idx * step; | |
| if (v >= p->V) continue; | |
| int byte_idx = v / 4, sh = (v % 4) * 2; | |
| double logit = 0; | |
| for (int d = 0; d < p->D; d++) { | |
| int b = (lm_head[d * stride + byte_idx] >> sh) & 0x03; | |
| if (b == 0) logit -= x[d]; | |
| else if (b == 2) logit += x[d]; | |
| } | |
| s += logit; ss += logit * logit; c++; | |
| if (logit > lb) { lb = logit; li = v; } | |
| } | |
| { | |
| sum += s; sumsq += ss; cnt += c; | |
| if (lb > best_logit) { best_logit = lb; bid = li; } | |
| } | |
| } | |
| double mean = cnt ? sum / cnt : 0.0; | |
| double var = cnt ? sumsq / cnt - mean * mean : 1.0; | |
| if (var < 1e-9) var = 1e-9; | |
| if (tl > best_logit) bid = target; /* target beat the whole sample */ | |
| *best_id = bid; *target_logit = tl; | |
| *mean_out = mean; *std_out = sqrt(var); | |
| } | |
| /* ── Score one (input → target) next-token pair ── | |
| * Runs the SAME phase_forward the chat pipeline uses, then rewards how | |
| * strongly the model favors the true next token. */ | |
| static double tune_eval_pair(phoenix_t *p, int input, int target, int *predicted) { | |
| double *z = calloc(p->D, sizeof(double)); | |
| phase_forward(p, input, z); | |
| int best; double tl, mean, std; | |
| vocab_stats(p, z, target, &best, &tl, &mean, &std); | |
| *predicted = best; | |
| free(z); | |
| return (tl - mean) / std; /* target z-score: higher = better prediction */ | |
| } | |
| /* ── Next-token training batch ── | |
| * Walks the corpus as a sequence (input = tok[i], target = tok[i+1]), scores | |
| * each pair, tracks argmax accuracy, and emits a "train" event carrying the | |
| * most recent input→target→prediction rows for the dashboard. */ | |
| static double tune_eval_batch(phoenix_t *p, int batch_size) { | |
| if (p->tune.n_train < 2 || !p->tune.train_tokens) | |
| return 0.0; /* need at least one (input,target) pair */ | |
| if (batch_size > 64) batch_size = 64; | |
| double total = 0; | |
| int correct = 0; | |
| int cin[64], ctgt[64], cpred[64]; | |
| int rows = 0; | |
| for (int i = 0; i < batch_size; i++) { | |
| int pos = p->tune.train_pos % (p->tune.n_train - 1); | |
| int input = p->tune.train_tokens[pos]; | |
| int target = p->tune.train_tokens[pos + 1]; | |
| p->tune.train_pos++; | |
| int pred; | |
| double s = tune_eval_pair(p, input, target, &pred); | |
| total += s; | |
| if (pred == target) correct++; | |
| if (rows < 64) { cin[rows] = input; ctgt[rows] = target; cpred[rows] = pred; rows++; } | |
| } | |
| double score = total / batch_size; | |
| p->tune.last_accuracy = (double)correct / batch_size; | |
| /* Emit training data for the dashboard panel */ | |
| if (g_state_log) { | |
| fprintf(g_state_log, | |
| "{\"event\":\"train\",\"pos\":%d,\"n_train\":%d,\"acc\":%.4f," | |
| "\"score\":%.4f,\"best\":%.4f,\"rows\":[", | |
| p->tune.train_pos, p->tune.n_train, | |
| p->tune.last_accuracy, score, p->tune.best_score); | |
| int show = rows < TRAIN_SHOW_ROWS ? rows : TRAIN_SHOW_ROWS; | |
| for (int r = 0; r < show; r++) | |
| fprintf(g_state_log, "%s[%d,%d,%d]", r ? "," : "", | |
| cin[r], ctgt[r], cpred[r]); | |
| fprintf(g_state_log, "]}\n"); | |
| fflush(g_state_log); | |
| } | |
| return score; | |
| } | |
| /* ── Perturb the trainable physics gains (g_coupling, lens_enhance) ── | |
| * The tuner must perturb parameters that actually reach the output. Most of | |
| * the state in macro_forward_layer is rebuilt from scratch each layer — every | |
| * ring/tendril theta and omega is re-derived from the activation and the | |
| * fixed ternary weights, so perturbing omega (or fabric weights, which the | |
| * final DFT overwrites) is a silent no-op: the score never moves. | |
| * | |
| * The mode-coupling gain matrix g_coupling[p][q] and the channel enhancement | |
| * lens_enhance[k] are the exception — they scale every interference product | |
| * that builds x_out (vqpu_product / vqpu_read_products) and are never | |
| * regenerated. They ARE the model's control surface. We back them up here so | |
| * tune_commit_revert can restore them if the perturbation hurts. */ | |
| static void tune_perturb(phoenix_t *p, int n_units, double lr) { | |
| macro_core_t *mc = &p->core; | |
| p->tune.n_perturbed = 0; | |
| if (mc->n_compute <= 0) return; | |
| int cap = (int)(sizeof(p->tune.perturb_idx) / sizeof(p->tune.perturb_idx[0])); | |
| int n = n_units * 2; /* a handful of tendrils per round */ | |
| if (n > cap) n = cap; | |
| if (n < 1) n = 1; | |
| /* Build a candidate pool of all trainable tendrils: compute tendrils, | |
| * both PROC rings, the COLLECT ring, and output tendrils. Each caller's | |
| * lr (~0.008–0.01) was tuned for radian omega steps; for a multiplicative | |
| * gain around 1.0 we want a ~10% step, so scale it up. */ | |
| double step = lr * 12.0; | |
| /* Collect candidate vQPU indices that can be perturbed */ | |
| int pool[64]; | |
| int pool_n = 0; | |
| /* Compute tendrils */ | |
| for (int t = 0; t < mc->n_compute && pool_n < 64; t++) | |
| pool[pool_n++] = mc->compute_start + t; | |
| /* PROC rings */ | |
| for (int r = RING_PROC_A; r <= RING_COLLECT && pool_n < 64; r++) | |
| pool[pool_n++] = mc->ring_id[r]; | |
| /* Output tendrils */ | |
| for (int t = 0; t < mc->n_outputs && pool_n < 64; t++) | |
| pool[pool_n++] = mc->output_start + t; | |
| for (int t = 0; t < n; t++) { | |
| int id = pool[rand() % pool_n]; | |
| if (id < 0 || id >= p->n_vqpus) continue; | |
| vqpu_t *v = &p->vqpus[id]; | |
| if (v->role == ROLE_DORMANT) continue; | |
| if (v->train_gain == 0.0) v->train_gain = 1.0; | |
| /* Record for possible revert */ | |
| int slot = p->tune.n_perturbed++; | |
| p->tune.perturb_idx[slot] = id; | |
| p->tune.perturb_old[slot] = v->train_gain; | |
| /* Box-Muller Gaussian, multiplicative */ | |
| double u1 = (rand() + 1.0) / (RAND_MAX + 1.0); | |
| double u2 = (rand() + 1.0) / (RAND_MAX + 1.0); | |
| double g = sqrt(-2 * log(u1)) * cos(2 * M_PI * u2); | |
| v->train_gain *= (1.0 + g * step); | |
| if (v->train_gain < 0.05) v->train_gain = 0.05; | |
| if (v->train_gain > 8.0) v->train_gain = 8.0; | |
| } | |
| } | |
| /* ── Commit or revert a perturbation round ── | |
| * The tuner perturbs a handful of per-tendril output gains, so revert restores | |
| * exactly those from the backup taken in tune_perturb. It deliberately does | |
| * NOT touch the structural checkpoint (ckpt_*) — that belongs to the idle | |
| * self-modifier and reverting it here would clobber unrelated topology work. */ | |
| static void tune_commit_revert(phoenix_t *p, double new_score) { | |
| if (new_score >= p->tune.best_score) { | |
| /* Keep perturbation — it improved quality */ | |
| p->tune.best_score = new_score; | |
| p->tune.improve_count++; | |
| } else { | |
| /* Restore just the tendril gains we touched this round */ | |
| for (int i = 0; i < p->tune.n_perturbed; i++) | |
| p->vqpus[p->tune.perturb_idx[i]].train_gain = p->tune.perturb_old[i]; | |
| p->tune.revert_count++; | |
| } | |
| } | |
| /* ── SOLIDIFY: re-optimize structure based on accumulated state ── | |
| * | |
| * After many perturbation rounds, the system has explored the omega | |
| * space and found what works. Solidify takes that learning and | |
| * permanently reshapes the topology: | |
| * | |
| * 1. Find tendrils whose omega magnitude → near zero (low contribution) | |
| * 2. Reclaim those tendrils (free resources) | |
| * 3. Find tendrils with high traffic + high omega magnitude | |
| * 4. Strengthen their connections (increase fabric weight) | |
| * 5. Spawn new tendrils near high-traffic hubs | |
| * 6. Reset the perturbation baseline to current solidified state | |
| */ | |
| static void tune_solidify(phoenix_t *p) { | |
| int reclaimed = 0, strengthened = 0, spawned = 0; | |
| /* 1. Find low-contribution tendrils (omega magnitude near zero) */ | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| vqpu_t *v = &p->vqpus[i]; | |
| if (v->role != ROLE_GATE) continue; | |
| if (!v->active) continue; | |
| double omega_mag = 0; | |
| for (int o = 0; o < N_OSC; o++) | |
| omega_mag += fabs(v->omega[o]); | |
| omega_mag /= N_OSC; | |
| /* Also check utilization — low traffic + low omega = dead weight */ | |
| if (omega_mag < 0.05 && v->utilization < 0.1) { | |
| /* Reclaim this tendril */ | |
| v->role = ROLE_DORMANT; | |
| v->active = 0; | |
| /* Remove its connections */ | |
| for (int c = 0; c < p->n_connections; c++) { | |
| if (p->fabric[c].alive && | |
| (p->fabric[c].src == i || p->fabric[c].dst == i)) { | |
| p->fabric[c].alive = 0; | |
| p->alive_conns--; | |
| } | |
| } | |
| reclaimed++; | |
| } | |
| } | |
| /* 2. Strengthen high-traffic connections */ | |
| for (int c = 0; c < p->n_connections; c++) { | |
| conn_t *conn = &p->fabric[c]; | |
| if (!conn->alive) continue; | |
| if (conn->traffic > 5.0) { | |
| conn->weight *= 1.1; | |
| if (conn->weight > 1.0) conn->weight = 1.0; | |
| strengthened++; | |
| } | |
| } | |
| /* 3. Spawn new tendrils near the busiest hubs */ | |
| int busiest_hub = -1; | |
| double max_traffic = 0; | |
| for (int i = 0; i < p->n_vqpus; i++) { | |
| if (p->vqpus[i].role == ROLE_GATE && p->vqpus[i].active) { | |
| if (p->vqpus[i].utilization > max_traffic) { | |
| max_traffic = p->vqpus[i].utilization; | |
| busiest_hub = i; | |
| } | |
| } | |
| } | |
| if (busiest_hub >= 0 && p->n_vqpus < p->capacity) { | |
| int hub_parent = p->vqpus[busiest_hub].layer_id >= 0 | |
| ? p->core.ring_id[RING_PROC_A] : busiest_hub; | |
| for (int s = 0; s < 3; s++) { | |
| int id = spawn_tendril(p, hub_parent, ROLE_GATE, | |
| CH_FUND, CH_PROD4, 0.3); | |
| if (id >= 0) { | |
| p->core.n_compute++; | |
| spawned++; | |
| } | |
| } | |
| } | |
| /* 4. Don't reset best_score — keep the running best across solidify events */ | |
| printf(" [SOLIDIFY] reclaimed=%d strengthened=%d spawned=%d" | |
| " → %d active, %d conns\n", | |
| reclaimed, strengthened, spawned, | |
| count_active_tendrils(p), p->alive_conns); | |
| } | |
| int main(int argc, char **argv) { | |
| srand(42); | |
| phoenix_t brain; | |
| phoenix_init(&brain); | |
| printf("Phoenix Brain — Living 4-Ring Macro Core\n"); | |
| printf("═══════════════════════════════════════════════════════\n"); | |
| printf(" 64 fixed oscillators + demand-driven tentacles\n"); | |
| printf(" Continuous state | Persistent topology | Self-pruning\n\n"); | |
| if (argc < 2) { | |
| fprintf(stderr, "Usage: %s <model.bqsm> [num_tokens|--chat]\n", argv[0]); | |
| return 1; | |
| } | |
| int chat_mode = (argc >= 3 && strcmp(argv[2], "--chat") == 0); | |
| int n_tokens = argc >= 3 && !chat_mode ? atoi(argv[2]) : 20; | |
| char state_path[512]; | |
| make_state_path(argv[1], state_path, sizeof(state_path)); | |
| /* Open state log for real-time dashboard */ | |
| g_state_log = fopen("/tmp/phoenix_state.jsonl", "w"); | |
| if (!g_state_log) g_state_log = stderr; | |
| /* ── Phase 1: Load model weights ── */ | |
| printf(" Model: %s\n", argv[1]); | |
| phoenix_ingest(&brain, argv[1]); | |
| if (!brain.model_loaded) { | |
| fprintf(stderr, "Failed to load model\n"); | |
| return 1; | |
| } | |
| /* ── Phase 2: Try to load saved state ── */ | |
| int resumed = 0; | |
| if (state_load(&brain, state_path) == 0) { | |
| /* Self-verify the loaded topology before trusting it. A state saved | |
| * mid-restructure can be structurally inconsistent; repair what we | |
| * can, and if the core rings themselves are gone, throw it away and | |
| * rebuild from clean ingestion rather than crash later. */ | |
| int issues = verify_integrity(&brain, 1); | |
| if (issues >= INTEGRITY_FATAL) { | |
| printf(" [STATE] Loaded state failed integrity check (core rings invalid)" | |
| " — discarding and re-ingesting clean topology\n"); | |
| phoenix_ingest(&brain, argv[1]); | |
| } else { | |
| if (issues > 0) | |
| printf(" [STATE] Integrity check repaired %d issue(s) in loaded topology\n", issues); | |
| else | |
| printf(" [STATE] Integrity check passed — topology coherent\n"); | |
| printf(" [STATE] Resumed evolved topology from %s\n", state_path); | |
| resumed = 1; | |
| } | |
| } else { | |
| printf(" [STATE] No saved state — fresh topology from ingestion\n"); | |
| } | |
| /* ── Print topology ── */ | |
| macro_core_t *mc = &brain.core; | |
| int active = count_active_tendrils(&brain); | |
| double ring_kb = (double)(brain.n_vqpus * sizeof(vqpu_t)) / 1024.0; | |
| double fab_kb = (double)(brain.alive_conns * sizeof(conn_t)) / 1024.0; | |
| printf("\n Topology:\n"); | |
| printf(" Core: 4 × %d = %d osc (permanent)\n", N_OSC, MACRO_RINGS * N_OSC); | |
| printf(" Tendrils: %d active\n", active); | |
| printf(" Connections:%d alive\n", brain.alive_conns); | |
| printf(" Memory: %.1f KB ring + %.1f KB fabric = %.1f KB\n", | |
| ring_kb, fab_kb, ring_kb + fab_kb); | |
| if (resumed) | |
| printf(" Cycles: %d (accumulated)\n", brain.total_cycles); | |
| /* ── Phase 3: Continuous inference ── */ | |
| /* In chat mode, skip initial test tokens — phoenix reads from ring buffer */ | |
| int initial_tendrils = active; | |
| int initial_conns = brain.alive_conns; | |
| if (!chat_mode) { | |
| printf("\n ── Continuous Inference (%d tokens) ──\n", n_tokens); | |
| printf(" [pos] tok\u2192sample E=energy coh=[I A B C]" | |
| " tendrils conns ms (t/s)\\n"); | |
| int test_tokens[] = { 0, 1, 2, 3, 4, 100, 200, 500, 1000, 2000, | |
| 5000, 10000, 42, 7, 13, 256, 512, 1024, 128, 64 }; | |
| int n_test = sizeof(test_tokens) / sizeof(test_tokens[0]); | |
| if (n_tokens > n_test) n_tokens = n_test; | |
| for (int pos = 0; pos < n_tokens; pos++) { | |
| int tok = test_tokens[pos % n_test]; | |
| /* Continuous forward — phase state carries between tokens */ | |
| continuous_forward(&brain, tok, pos); | |
| /* Between tokens: sweep dormant and run idle optimization */ | |
| if (pos > 0 && pos % 3 == 0) { | |
| int reclaimed = sweep_dormant(&brain, 0.1); | |
| if (reclaimed > 0) { | |
| printf(" [SWEEP] Reclaimed %d dormant tendrils" | |
| " \u2192 %d active, %d conns\\n", | |
| reclaimed, count_active_tendrils(&brain), | |
| brain.alive_conns); | |
| /* Update compute count */ | |
| brain.core.n_compute -= reclaimed; | |
| if (brain.core.n_compute < 0) brain.core.n_compute = 0; | |
| } | |
| /* Quick idle cycles for Hebbian adaptation */ | |
| for (int c = 0; c < 3; c++) | |
| phoenix_idle_cycle(&brain); | |
| } | |
| } | |
| } | |
| /* ── Phase 3b: Chat mode — ring buffer token I/O ── | |
| * | |
| * When launched with --chat, phoenix maps two shared-memory ring buffers: | |
| * - /tmp/phoenix_ring_in: dashboard writes token IDs (user input + predicted feedback) | |
| * - /tmp/phoenix_ring_out: phoenix writes predicted token IDs (output to display) | |
| * | |
| * Ring buffer layout: [head:u32][tail:u32][size:u32][cap:u32][tokens:cap*u32] | |
| * The dashboard pushes token IDs from tokenized user text. Phoenix pops them, | |
| * runs inference through the wave-rider pipeline, and pushes the predicted | |
| * token ID to the output ring. Self-tuning runs between predictions. | |
| * | |
| * Ring buffers never close — they persist across Start/Stop/restarts of | |
| * the dashboard. The state file (.bqmc) holds the brain's evolved topology. */ | |
| if (chat_mode) { | |
| const char *ring_in_path = "/tmp/phoenix_ring_in"; | |
| const char *ring_out_path = "/tmp/phoenix_ring_out"; | |
| int fd_in = open(ring_in_path, O_RDWR); | |
| int fd_out = open(ring_out_path, O_RDWR); | |
| if (fd_in < 0 || fd_out < 0) { | |
| fprintf(stderr, "Cannot open ring buffers. Start dashboard first.\n"); | |
| if (fd_in >= 0) close(fd_in); | |
| if (fd_out >= 0) close(fd_out); | |
| } else { | |
| volatile uint32_t *ring_in = mmap(NULL, RING_BUF_SIZE, | |
| PROT_READ | PROT_WRITE, MAP_SHARED, fd_in, 0); | |
| volatile uint32_t *ring_out = mmap(NULL, RING_BUF_SIZE, | |
| PROT_READ | PROT_WRITE, MAP_SHARED, fd_out, 0); | |
| close(fd_in); close(fd_out); | |
| if (ring_in == MAP_FAILED || ring_out == MAP_FAILED) { | |
| fprintf(stderr, "mmap failed\n"); | |
| } else { | |
| uint32_t last_sample = 0; | |
| printf("\n ── Chat Mode: ring buffer token I/O ──\n"); | |
| printf(" Reading from /tmp/phoenix_ring_in\n"); | |
| printf(" Writing to /tmp/phoenix_ring_out\n"); | |
| /* Initialize self-tuning corpus for chat mode. The batch | |
| * training block (post-chat) never runs here, so without this | |
| * tune.n_train stays 0 and tune_eval_batch divides by zero. */ | |
| if (brain.tune.n_train <= 0) { | |
| /* tune_load_data falls back to a synthetic 0..255 corpus | |
| * if the file is missing. */ | |
| int nt = tune_load_data(&brain, | |
| "/home/compunerd/models/train_tokens.txt"); | |
| brain.tune.perturb_lr = 0.01; | |
| brain.tune.perturb_count = 8; | |
| brain.tune.batch_size = 4; | |
| brain.tune.train_pos = 0; | |
| brain.tune.best_score = tune_eval_batch(&brain, brain.tune.batch_size); | |
| printf(" Self-tune corpus: %d tokens, baseline score=%.2f\n", | |
| nt, brain.tune.best_score); | |
| } | |
| printf("\n"); | |
| fflush(stdout); | |
| int chat_pos = 0; | |
| int idle_ticks = 0; | |
| while (1) { | |
| /* Poll ring_in: [head(0) tail(1) size(2) cap(3)] [tokens(4+)] */ | |
| uint32_t sz = ring_in[2]; | |
| if (sz == 0) { | |
| phoenix_idle_cycle(&brain); | |
| /* Self-verify periodically: the idle cycle restructures | |
| * the topology, so re-check its integrity and repair any | |
| * drift before it can crash a forward pass. */ | |
| if (idle_ticks % 100 == 0) { | |
| int fixed = verify_integrity(&brain, 1); | |
| if (fixed > 0 && g_state_log) { | |
| fprintf(g_state_log, | |
| "{\"event\":\"verify\",\"repaired\":%d,\"vqpus\":%d,\"conns\":%d}\n", | |
| fixed, count_active_tendrils(&brain), brain.alive_conns); | |
| fflush(g_state_log); | |
| } | |
| } | |
| /* Self-tune while idle so best/imp/rev keep evolving, | |
| * but rarely and cheaply: one perturbation eval only | |
| * after ~3s of true idle (300 ticks), batch of 2. This | |
| * keeps the loop responsive to incoming chat tokens — | |
| * a full batch here would block input for ~10s. */ | |
| if (++idle_ticks % 300 == 0) { | |
| tune_perturb(&brain, 4, 0.008); | |
| brain.tune.train_pos = 0; | |
| double score = tune_eval_batch(&brain, 2); | |
| tune_commit_revert(&brain, score); | |
| emit_state(&brain, | |
| score >= brain.tune.best_score ? "tune_improve" : "tune_revert"); | |
| } else { | |
| emit_state(&brain, "idle"); | |
| } | |
| usleep(10000); | |
| continue; | |
| } | |
| uint32_t head = ring_in[0]; | |
| uint32_t tok = ring_in[4 + head]; | |
| ring_in[0] = (head + 1) % RING_CAPACITY; | |
| ring_in[2] = sz - 1; | |
| if (tok == 0xFFFFFFFE) break; | |
| if (tok >= (uint32_t)brain.V) continue; | |
| if (g_state_log) { | |
| fprintf(g_state_log, | |
| "{\"event\":\"chat_input\",\"tok\":%u,\"pos\":%d}\n", | |
| tok, chat_pos); | |
| fflush(g_state_log); | |
| } | |
| int sample = continuous_forward(&brain, (int)tok, chat_pos); | |
| if (sample < 0) sample = (int)tok; /* engine not ready */ | |
| last_sample = (uint32_t)sample; | |
| /* Push the PREDICTED token to ring_out (not the input) */ | |
| uint32_t ot = ring_out[0]; uint32_t ot2 = ring_out[1]; | |
| uint32_t osz = ring_out[2]; | |
| uint32_t next = (ot2 + 1) % RING_CAPACITY; | |
| if (next != ot) { | |
| ring_out[4 + ot2] = last_sample; | |
| ring_out[1] = next; | |
| ring_out[2] = osz + 1; | |
| } | |
| chat_pos++; | |
| /* Self-tuning every 5 tokens */ | |
| if (chat_pos % 5 == 0) { | |
| tune_perturb(&brain, 4, 0.008 * (1.0 - chat_pos * 0.001)); | |
| brain.tune.train_pos = 0; | |
| double score = tune_eval_batch(&brain, 4); | |
| tune_commit_revert(&brain, score); | |
| emit_state(&brain, score >= brain.tune.best_score ? "tune_improve" : "tune_revert"); | |
| } | |
| /* Solidify every 15 tokens */ | |
| if (chat_pos % 15 == 0) { | |
| tune_solidify(&brain); | |
| emit_state(&brain, "solidify"); | |
| } | |
| if (chat_pos % 50 == 0) | |
| state_save(&brain, state_path); | |
| } | |
| /* Sentinel */ | |
| uint32_t ot = ring_out[0]; uint32_t ot2 = ring_out[1]; uint32_t osz = ring_out[2]; | |
| uint32_t next = (ot2 + 1) % RING_CAPACITY; | |
| if (next != ot) { | |
| ring_out[4 + ot2] = 0xFFFFFFFE; | |
| ring_out[1] = next; | |
| ring_out[2] = osz + 1; | |
| } | |
| munmap((void*)ring_in, RING_BUF_SIZE); | |
| munmap((void*)ring_out, RING_BUF_SIZE); | |
| printf("Chat mode ended.\n"); | |
| } | |
| } | |
| } | |
| /* ── Phase 4: Post-inference analysis ── */ | |
| active = count_active_tendrils(&brain); | |
| printf("\n ── Post-Inference State ──\n"); | |
| /* Core ring state */ | |
| const char *ring_names[] = {"INTAKE ", "PROC_A ", "PROC_B ", "COLLECT"}; | |
| for (int r = 0; r < MACRO_RINGS; r++) { | |
| vqpu_t *v = &brain.vqpus[mc->ring_id[r]]; | |
| printf(" %s: coh=%.3f c₂=%.3f c₄=%.3f c₆=%.3f util=%.2f\n", | |
| ring_names[r], v->coherence, | |
| v->c_mag[CH_PROD2], v->c_mag[CH_PROD4], v->c_mag[CH_PROD6], | |
| v->utilization); | |
| } | |
| /* Product channels */ | |
| double ch_total[4] = {0}; | |
| for (int i = 0; i < brain.n_vqpus; i++) { | |
| vqpu_t *v = &brain.vqpus[i]; | |
| if (v->role == ROLE_GATE) { | |
| ch_total[0] += fabs(vqpu_product(v, 1, 1, brain.g_coupling, brain.lens_enhance)); | |
| ch_total[1] += fabs(vqpu_product(v, 2, 2, brain.g_coupling, brain.lens_enhance)); | |
| ch_total[2] += fabs(vqpu_product(v, 2, 4, brain.g_coupling, brain.lens_enhance)); | |
| ch_total[3] += fabs(vqpu_product(v, 1, 2, brain.g_coupling, brain.lens_enhance)); | |
| } | |
| } | |
| printf("\n Product channels:\n"); | |
| printf(" c₂(4×)=%.2f c₄(24×)=%.2f c₆(10×)=%.2f c₃(1×)=%.2f\n", | |
| ch_total[0], ch_total[1], ch_total[2], ch_total[3]); | |
| /* Lifecycle summary */ | |
| int delta_tendrils = active - initial_tendrils; | |
| int delta_conns = brain.alive_conns - initial_conns; | |
| printf("\n Lifecycle:\n"); | |
| printf(" Tendrils: %d → %d (%+d)\n", | |
| initial_tendrils, active, delta_tendrils); | |
| printf(" Connections: %d → %d (%+d)\n", | |
| initial_conns, brain.alive_conns, delta_conns); | |
| printf(" Cycles: %d total\n", brain.total_cycles); | |
| printf(" Mods: %d confirmed, %d reverted\n", | |
| brain.mod_confirms, brain.mod_reverts); | |
| /* ── Phase 5: Self-tuning ── */ | |
| printf("\n ── Self-Tuning (omega perturbation + evaluation) ──\n"); | |
| /* Load training data (synthetic if no file) */ | |
| /* Load training data — prefer wiki corpus, fall back to sample texts */ | |
| const char *train_path = "/home/compunerd/models/train_wiki.txt"; | |
| FILE *tf = fopen(train_path, "r"); | |
| if (!tf) train_path = "/home/compunerd/models/train_tokens.txt"; | |
| else fclose(tf); | |
| int n_train = tune_load_data(&brain, train_path); | |
| brain.tune.best_score = 0; | |
| brain.tune.perturb_lr = 0.01; | |
| brain.tune.perturb_count = 8; | |
| brain.tune.batch_size = 8; | |
| brain.tune.improve_count = 0; | |
| brain.tune.revert_count = 0; | |
| printf(" Training data: %d tokens from %s\n", n_train, train_path); | |
| printf(" Perturbing %d tendrils per round, lr=%.4f, batch=%d\n", | |
| brain.tune.perturb_count, brain.tune.perturb_lr, | |
| brain.tune.batch_size); | |
| printf(" [round] score=cur best=best (imp/rev) tendrils conns\n"); | |
| /* Baseline evaluation */ | |
| brain.tune.train_pos = 0; | |
| brain.tune.best_score = tune_eval_batch(&brain, brain.tune.batch_size); | |
| printf(" [base] score=%.2f\n", brain.tune.best_score); | |
| /* Run tuning rounds — autonomous mode: many rounds with periodic | |
| * state saves so training persists across runs and can be stopped | |
| * safely with checkpoint recovery. */ | |
| int n_rounds = 2000; | |
| int save_every = 50; | |
| for (int round = 0; round < n_rounds; round++) { | |
| /* Perturb */ | |
| brain.tune.train_pos = 0; | |
| tune_perturb(&brain, brain.tune.perturb_count, brain.tune.perturb_lr); | |
| /* Evaluate with perturbation */ | |
| brain.tune.train_pos = 0; | |
| double new_score = tune_eval_batch(&brain, brain.tune.batch_size); | |
| /* Commit or revert */ | |
| tune_commit_revert(&brain, new_score); | |
| int active_t = count_active_tendrils(&brain); | |
| printf(" [%2d] score=%.2f best=%.2f (%d/%d) tend=%d conns=%d\n", | |
| round + 1, new_score, brain.tune.best_score, | |
| brain.tune.improve_count, brain.tune.revert_count, | |
| active_t, brain.alive_conns); | |
| /* Emit tuning state for dashboard */ | |
| brain.tune.best_score = brain.tune.best_score; | |
| emit_state(&brain, new_score >= brain.tune.best_score ? "tune_improve" : "tune_revert"); | |
| /* Solidify every 5 rounds */ | |
| if ((round + 1) % 5 == 0) { | |
| printf(" ── Solidifying structure ──\n"); | |
| tune_solidify(&brain); | |
| emit_state(&brain, "solidify"); | |
| } | |
| /* Decay learning rate over time, with a floor so training | |
| * continues to learn — never let it decay to zero. */ | |
| brain.tune.perturb_lr *= 0.95; | |
| if (brain.tune.perturb_lr < 0.001) brain.tune.perturb_lr = 0.001; | |
| /* Periodic checkpoint so training state survives across runs */ | |
| if ((round + 1) % save_every == 0) { | |
| state_save(&brain, state_path); | |
| printf(" [ckpt] saved state to %s (round %d)\n", | |
| state_path, round + 1); | |
| } | |
| } | |
| printf("\n Tuning results:\n"); | |
| printf(" Improved: %d rounds\n", brain.tune.improve_count); | |
| printf(" Reverted: %d rounds\n", brain.tune.revert_count); | |
| printf(" Best score: %.2f\n", brain.tune.best_score); | |
| /* ── Phase 6: Save evolved state ── */ | |
| state_save(&brain, state_path); | |
| /* Final sweep for reporting */ | |
| int dormant = 0; | |
| for (int i = 0; i < brain.n_vqpus; i++) | |
| if (brain.vqpus[i].role == ROLE_DORMANT) dormant++; | |
| printf("\n Summary\n"); | |
| printf(" ─────────────────────────────────────\n"); | |
| printf(" Core: %d osc (4 rings, permanent)\n", MACRO_RINGS * N_OSC); | |
| printf(" Active: %d tendrils\n", active); | |
| printf(" Dormant: %d (reclaimable)\n", dormant); | |
| printf(" Connections: %d alive\n", brain.alive_conns); | |
| printf(" State file: %s\n", state_path); | |
| printf(" Memory: %.1f KB\n", | |
| (double)(brain.n_vqpus * sizeof(vqpu_t) + | |
| brain.alive_conns * sizeof(conn_t)) / 1024.0); | |
| printf(" Tuning: %d improved, %d reverted (best=%.2f)\n", | |
| brain.tune.improve_count, brain.tune.revert_count, | |
| brain.tune.best_score); | |
| phoenix_free(&brain); | |
| return 0; | |
| } | |