Recovered source transcript
1// ═══════════════════════════════════════════════════════════════════════════════
2// NEUROLOGICAL MATHEMATICS FRAMEWORK v1.0
3// Complete Brain-Spine-Neuron Mathematical Foundation
4// ═══════════════════════════════════════════════════════════════════════════════
5//
6// This module implements the full neurological mathematical framework:
7//
8// LEVEL 1: NEURON (Single Mind = Single Neuron)
9// - Hodgkin-Huxley equations for action potentials
10// - Nernst equation for ion equilibrium
11// - Goldman-Hodgkin-Katz equation for membrane potential
12// - Synaptic transmission (AMPA, NMDA, GABA)
13// - Spike-timing dependent plasticity (STDP)
14//
15// LEVEL 2: NEURAL NETWORK (Mind Farm = Neural Tissue)
16// - Connectivity patterns (small-world, scale-free)
17// - Population dynamics (Wilson-Cowan equations)
18// - Neural field theory (Amari equations)
19// - Synchronization (Kuramoto model)
20//
21// LEVEL 3: BRAIN SYSTEM (Full Nervous System)
22// - Cortical columns and layers
23// - Thalamo-cortical loops
24// - Basal ganglia circuits
25// - Cerebellar computation
26// - Spinal cord reflexes
27//
28// ═══════════════════════════════════════════════════════════════════════════════
29
30#pragma once
31
32#include <cstdint>
33#include <cmath>
34#include <vector>
35#include <array>
36#include <functional>
37
38#include "constants.hpp"
39#include "fast_math.hpp"
40
41namespace mind_farm {
42namespace neuro {
43
44// ═══════════════════════════════════════════════════════════════════════════════
45// PHYSICAL CONSTANTS
46// ═══════════════════════════════════════════════════════════════════════════════
47
48constexpr float FARADAY = 96485.0f; // C/mol - Faraday constant
49constexpr float GAS_R = 8.314f; // J/(mol·K) - Gas constant
50constexpr float TEMP_K = 310.0f; // K - Body temperature (37°C)
51constexpr float RT_F = GAS_R * TEMP_K / FARADAY; // ~26.7 mV at 37°C
52
53// Ion concentrations (mM)
54constexpr float NA_OUT = 145.0f; // [Na+]out
55constexpr float NA_IN = 12.0f; // [Na+]in
56constexpr float K_OUT = 4.0f; // [K+]out
57constexpr float K_IN = 155.0f; // [K+]in
58constexpr float CL_OUT = 120.0f; // [Cl-]out
59constexpr float CL_IN = 4.0f; // [Cl-]in
60constexpr float CA_OUT = 2.0f; // [Ca2+]out
61constexpr float CA_IN = 0.0001f; // [Ca2+]in (~100 nM)
62
63// ═══════════════════════════════════════════════════════════════════════════════
64// LEVEL 1: SINGLE NEURON MATHEMATICS
65// ═══════════════════════════════════════════════════════════════════════════════
66
67// Nernst Equation: E_ion = (RT/zF) * ln([ion]_out/[ion]_in)
68// Calculates equilibrium potential for a single ion
69inline float nernst(float z, float conc_out, float conc_in) {
70 return (RT_F / z) * std::log(conc_out / conc_in) * 1000.0f; // Convert to mV
71}
72
73// Goldman-Hodgkin-Katz Equation
74// V_m = (RT/F) * ln((P_Na[Na]_o + P_K[K]_o + P_Cl[Cl]_i) / (P_Na[Na]_i + P_K[K]_i + P_Cl[Cl]_o))
75struct GHKEquation {
76 float P_Na = 1.0f; // Na+ permeability (relative)
77 float P_K = 20.0f; // K+ permeability (at rest, ~20x Na+)
78 float P_Cl = 5.0f; // Cl- permeability
79
80 float membrane_potential() const {
81 float num = P_Na * NA_OUT + P_K * K_OUT + P_Cl * CL_IN;
82 float den = P_Na * NA_IN + P_K * K_IN + P_Cl * CL_OUT;
83 return RT_F * std::log(num / den) * 1000.0f; // mV
84 }
85};
86
87// ═══════════════════════════════════════════════════════════════════════════════
88// HODGKIN-HUXLEY MODEL
89// The fundamental equations of neuronal action potentials
90//
91// C_m * dV/dt = I_ext - g_Na*m³*h*(V-E_Na) - g_K*n⁴*(V-E_K) - g_L*(V-E_L)
92//
93// Gating variables:
94// dx/dt = α_x(V)*(1-x) - β_x(V)*x for x ∈ {m, h, n}
95//
96// ═══════════════════════════════════════════════════════════════════════════════
97
98struct HodgkinHuxley {
99 // Membrane properties
100 float C_m = 1.0f; // μF/cm² - Membrane capacitance
101 float g_Na = 120.0f; // mS/cm² - Sodium conductance
102 float g_K = 36.0f; // mS/cm² - Potassium conductance
103 float g_L = 0.3f; // mS/cm² - Leak conductance
104
105 // Reversal potentials (mV)
106 float E_Na = 50.0f;
107 float E_K = -77.0f;
108 float E_L = -54.4f;
109
110 // State variables
111 float V = -65.0f; // mV - Membrane potential
112 float m = 0.05f; // Na+ activation
113 float h = 0.6f; // Na+ inactivation
114 float n = 0.32f; // K+ activation
115
116 // Rate functions for gating variables
117 // α_m(V) = 0.1(V+40)/(1-exp(-(V+40)/10))
118 float alpha_m(float V_) const {
119 float x = V_ + 40.0f;
120 if (std::abs(x) < 1e-6f) return 1.0f; // L'Hôpital limit
121 return 0.1f * x / (1.0f - std::exp(-x / 10.0f));
122 }
123
124 // β_m(V) = 4*exp(-(V+65)/18)
125 float beta_m(float V_) const {
126 return 4.0f * std::exp(-(V_ + 65.0f) / 18.0f);
127 }
128
129 // α_h(V) = 0.07*exp(-(V+65)/20)
130 float alpha_h(float V_) const {
131 return 0.07f * std::exp(-(V_ + 65.0f) / 20.0f);
132 }
133
134 // β_h(V) = 1/(1+exp(-(V+35)/10))
135 float beta_h(float V_) const {
136 return 1.0f / (1.0f + std::exp(-(V_ + 35.0f) / 10.0f));
137 }
138
139 // α_n(V) = 0.01(V+55)/(1-exp(-(V+55)/10))
140 float alpha_n(float V_) const {
141 float x = V_ + 55.0f;
142 if (std::abs(x) < 1e-6f) return 0.1f;
143 return 0.01f * x / (1.0f - std::exp(-x / 10.0f));
144 }
145
146 // β_n(V) = 0.125*exp(-(V+65)/80)
147 float beta_n(float V_) const {
148 return 0.125f * std::exp(-(V_ + 65.0f) / 80.0f);
149 }
150
151 // Ionic currents
152 float I_Na() const { return g_Na * m*m*m * h * (V - E_Na); }
153 float I_K() const { return g_K * n*n*n*n * (V - E_K); }
154 float I_L() const { return g_L * (V - E_L); }
155
156 // Time step using Euler method
157 // dt in ms, I_ext in μA/cm²
158 void step(float dt, float I_ext) {
159 // Gating variable derivatives
160 float dm = alpha_m(V) * (1.0f - m) - beta_m(V) * m;
161 float dh = alpha_h(V) * (1.0f - h) - beta_h(V) * h;
162 float dn = alpha_n(V) * (1.0f - n) - beta_n(V) * n;
163
164 // Membrane potential derivative
165 float dV = (I_ext - I_Na() - I_K() - I_L()) / C_m;
166
167 // Euler integration
168 V += dV * dt;
169 m += dm * dt;
170 h += dh * dt;
171 n += dn * dt;
172
173 // Clamp gating variables to [0,1]
174 m = std::clamp(m, 0.0f, 1.0f);
175 h = std::clamp(h, 0.0f, 1.0f);
176 n = std::clamp(n, 0.0f, 1.0f);
177 }
178
179 // Check if neuron is spiking (V > 0 mV)
180 bool is_spiking() const { return V > 0.0f; }
181};
182
183// ═══════════════════════════════════════════════════════════════════════════════
184// SYNAPTIC TRANSMISSION
185// Models for AMPA, NMDA, and GABA receptors
186// ═══════════════════════════════════════════════════════════════════════════════
187
188// AMPA Receptor (fast excitatory)
189// I_AMPA = g_AMPA * s * (V - E_AMPA)
190// ds/dt = -s/τ_AMPA + Σ_j δ(t - t_j)
191struct AMPASynapse {
192 float g_max = 0.35f; // nS - Maximum conductance
193 float E_rev = 0.0f; // mV - Reversal potential
194 float tau = 2.0f; // ms - Decay time constant
195 float s = 0.0f; // Synaptic variable
196
197 float current(float V_post) const {
198 return g_max * s * (V_post - E_rev);
199 }
200
201 void receive_spike() {
202 s += 1.0f;
203 }
204
205 void step(float dt) {
206 s *= std::exp(-dt / tau);
207 }
208};
209
210// NMDA Receptor (slow excitatory, voltage-dependent Mg2+ block)
211// I_NMDA = g_NMDA * s * B(V) * (V - E_NMDA)
212// B(V) = 1 / (1 + [Mg2+]_o * exp(-0.062*V) / 3.57)
213struct NMDASynapse {
214 float g_max = 0.5f; // nS
215 float E_rev = 0.0f; // mV
216 float tau_rise = 2.0f; // ms
217 float tau_decay = 100.0f;// ms - NMDA is slow!
218 float Mg_o = 1.0f; // mM - External Mg2+ concentration
219 float s = 0.0f;
220 float x = 0.0f; // Rise variable
221
222 // Mg2+ block factor
223 float B(float V) const {
224 return 1.0f / (1.0f + Mg_o * std::exp(-0.062f * V) / 3.57f);
225 }
226
227 float current(float V_post) const {
228 return g_max * s * B(V_post) * (V_post - E_rev);
229 }
230
231 void receive_spike() {
232 x += 1.0f;
233 }
234
235 void step(float dt) {
236 float dx = -x / tau_rise;
237 float ds = -s / tau_decay + x / tau_rise;
238 x += dx * dt;
239 s += ds * dt;
240 }
241};
242
243// GABA-A Receptor (fast inhibitory)
244struct GABAASynapse {
245 float g_max = 0.8f; // nS
246 float E_rev = -80.0f; // mV (Cl- reversal)
247 float tau = 5.0f; // ms
248 float s = 0.0f;
249
250 float current(float V_post) const {
251 return g_max * s * (V_post - E_rev);
252 }
253
254 void receive_spike() {
255 s += 1.0f;
256 }
257
258 void step(float dt) {
259 s *= std::exp(-dt / tau);
260 }
261};
262
263// ═══════════════════════════════════════════════════════════════════════════════
264// SPIKE-TIMING DEPENDENT PLASTICITY (STDP)
265// Δw = A+ * exp(-Δt/τ+) if Δt > 0 (post after pre → LTP)
266// Δw = -A- * exp(Δt/τ-) if Δt < 0 (pre after post → LTD)
267// ═══════════════════════════════════════════════════════════════════════════════
268
269struct STDP {
270 float A_plus = 0.005f; // LTP amplitude
271 float A_minus = 0.00525f;// LTD amplitude (slightly larger for stability)
272 float tau_plus = 20.0f; // ms - LTP time constant
273 float tau_minus = 20.0f; // ms - LTD time constant
274 float w_max = 1.0f; // Maximum weight
275 float w_min = 0.0f; // Minimum weight
276
277 // Calculate weight change given spike time difference
278 // delta_t = t_post - t_pre
279 float delta_w(float delta_t, float w) const {
280 if (delta_t > 0) {
281 // Post after pre → LTP
282 return A_plus * (w_max - w) * std::exp(-delta_t / tau_plus);
283 } else {
284 // Pre after post → LTD
285 return -A_minus * (w - w_min) * std::exp(delta_t / tau_minus);
286 }
287 }
288};
289
290// ═══════════════════════════════════════════════════════════════════════════════
291// LEVEL 2: NEURAL NETWORK / POPULATION MATHEMATICS
292// ═══════════════════════════════════════════════════════════════════════════════
293
294// Wilson-Cowan Equations (population dynamics)
295// τ_E * dE/dt = -E + (1 - r_E*E) * S(w_EE*E - w_EI*I + I_E)
296// τ_I * dI/dt = -I + (1 - r_I*I) * S(w_IE*E - w_II*I + I_I)
297// where S(x) = 1/(1 + exp(-a*(x-θ))) is the sigmoid
298struct WilsonCowan {
299 // Time constants (ms)
300 float tau_E = 10.0f;
301 float tau_I = 20.0f;
302
303 // Connection weights
304 float w_EE = 12.0f; // E → E
305 float w_EI = 4.0f; // I → E (inhibition of excitatory)
306 float w_IE = 13.0f; // E → I
307 float w_II = 11.0f; // I → I
308
309 // Refractory parameters
310 float r_E = 1.0f;
311 float r_I = 1.0f;
312
313 // Sigmoid parameters
314 float a = 1.0f;
315 float theta = 4.0f;
316
317 // External inputs
318 float I_E = 0.0f;
319 float I_I = 0.0f;
320
321 // Population activities
322 float E = 0.1f; // Excitatory population
323 float I = 0.1f; // Inhibitory population
324
325 float sigmoid(float x) const {
326 return 1.0f / (1.0f + std::exp(-a * (x - theta)));
327 }
328
329 void step(float dt) {
330 float input_E = w_EE * E - w_EI * I + I_E;
331 float input_I = w_IE * E - w_II * I + I_I;
332
333 float dE = (-E + (1.0f - r_E * E) * sigmoid(input_E)) / tau_E;
334 float dI = (-I + (1.0f - r_I * I) * sigmoid(input_I)) / tau_I;
335
336 E += dE * dt;
337 I += dI * dt;
338
339 E = std::clamp(E, 0.0f, 1.0f);
340 I = std::clamp(I, 0.0f, 1.0f);
341 }
342};
343
344// Neural Field Theory (Amari Equation)
345// τ * ∂u(x,t)/∂t = -u(x,t) + ∫w(x-x')*f(u(x',t))dx' + s(x,t)
346// where f is the firing rate function and w is the connectivity kernel
347template<size_t N>
348struct NeuralField {
349 float tau = 10.0f;
350 float threshold = 0.0f;
351 float steepness = 1.0f;
352
353 // Mexican hat connectivity: w(x) = A*exp(-x²/σ_e²) - B*exp(-x²/σ_i²)
354 float A = 1.5f; // Excitation amplitude
355 float B = 0.75f; // Inhibition amplitude
356 float sigma_e = 1.0f;// Excitation width
357 float sigma_i = 2.0f;// Inhibition width
358
359 std::array<float, N> u; // Activity field
360 std::array<float, N> input; // External input
361
362 void initialize() {
363 u.fill(0.0f);
364 input.fill(0.0f);
365 }
366
367 // Firing rate function
368 float f(float x) const {
369 return 1.0f / (1.0f + std::exp(-steepness * (x - threshold)));
370 }
371
372 // Connectivity kernel
373 float w(float dx) const {
374 float dx2 = dx * dx;
375 return A * std::exp(-dx2 / (2.0f * sigma_e * sigma_e)) -
376 B * std::exp(-dx2 / (2.0f * sigma_i * sigma_i));
377 }
378
379 void step(float dt) {
380 std::array<float, N> du;
381
382 for (size_t i = 0; i < N; ++i) {
383 // Compute integral ∫w(x-x')*f(u(x'))dx'
384 float integral = 0.0f;
385 for (size_t j = 0; j < N; ++j) {
386 float dx = static_cast<float>(i) - static_cast<float>(j);
387 integral += w(dx) * f(u[j]);
388 }
389 integral /= N; // Normalize
390
391 du[i] = (-u[i] + integral + input[i]) / tau;
392 }
393
394 for (size_t i = 0; i < N; ++i) {
395 u[i] += du[i] * dt;
396 }
397 }
398};
399
400// Kuramoto Model (synchronization)
401// dθ_i/dt = ω_i + (K/N) * Σ_j sin(θ_j - θ_i)
402template<size_t N>
403struct KuramotoModel {
404 float K = 1.0f; // Coupling strength
405
406 std::array<float, N> theta; // Phases
407 std::array<float, N> omega; // Natural frequencies
408
409 void initialize(float omega_mean, float omega_std) {
410 for (size_t i = 0; i < N; ++i) {
411 // Random phase in [0, 2π]
412 theta[i] = static_cast<float>(i) / N * 2.0f * M_PI;
413 // Random frequency around mean
414 omega[i] = omega_mean + omega_std * (static_cast<float>(i) / N - 0.5f);
415 }
416 }
417
418 // Order parameter r*e^(iψ) = (1/N) * Σ_j e^(iθ_j)
419 float order_parameter() const {
420 float cos_sum = 0.0f, sin_sum = 0.0f;
421 for (size_t i = 0; i < N; ++i) {
422 cos_sum += std::cos(theta[i]);
423 sin_sum += std::sin(theta[i]);
424 }
425 return std::sqrt(cos_sum*cos_sum + sin_sum*sin_sum) / N;
426 }
427
428 void step(float dt) {
429 std::array<float, N> dtheta;
430
431 for (size_t i = 0; i < N; ++i) {
432 float coupling = 0.0f;
433 for (size_t j = 0; j < N; ++j) {
434 coupling += std::sin(theta[j] - theta[i]);
435 }
436 dtheta[i] = omega[i] + (K / N) * coupling;
437 }
438
439 for (size_t i = 0; i < N; ++i) {
440 theta[i] += dtheta[i] * dt;
441 // Wrap to [0, 2π]
442 while (theta[i] > 2.0f * M_PI) theta[i] -= 2.0f * M_PI;
443 while (theta[i] < 0.0f) theta[i] += 2.0f * M_PI;
444 }
445 }
446};
447
448// ═══════════════════════════════════════════════════════════════════════════════
449// LEVEL 3: BRAIN SYSTEM MATHEMATICS
450// ═══════════════════════════════════════════════════════════════════════════════
451
452// Cortical Column Model
453// 6 layers: I, II/III, IV, V, VI
454struct CorticalColumn {
455 // Layer populations (E/I per layer)
456 std::array<WilsonCowan, 6> layers;
457
458 // Inter-layer connectivity pattern
459 // Canonical microcircuit: Input → L4 → L2/3 → L5 → L6 → Thalamus
460 void initialize() {
461 // Set layer-specific parameters
462 for (int i = 0; i < 6; ++i) {
463 layers[i].E = 0.1f;
464 layers[i].I = 0.1f;
465 }
466 }
467
468 // Feedforward processing
469 void feedforward_input(float input) {
470 // Input arrives at Layer 4
471 layers[3].I_E = input;
472 }
473
474 void step(float dt) {
475 // L4 → L2/3
476 layers[1].I_E = layers[3].E * 0.5f;
477
478 // L2/3 → L5
479 layers[4].I_E = layers[1].E * 0.6f;
480
481 // L5 → L6
482 layers[5].I_E = layers[4].E * 0.4f;
483
484 // L6 feedback to L4
485 layers[3].I_E += layers[5].E * 0.2f;
486
487 // Update all layers
488 for (auto& layer : layers) {
489 layer.step(dt);
490 }
491 }
492
493 // Output from L5 (to subcortical structures)
494 float output() const { return layers[4].E; }
495};
496
497// Thalamo-Cortical Loop
498// Thalamus acts as relay and modulator
499struct ThalamoCorticalLoop {
500 WilsonCowan thalamus;
501 WilsonCowan cortex;
502 WilsonCowan reticular; // TRN - inhibitory
503
504 // Connectivity
505 float w_TC = 1.0f; // Thalamus → Cortex
506 float w_CT = 0.5f; // Cortex → Thalamus
507 float w_TR = 0.3f; // Thalamus → Reticular
508 float w_RT = 0.8f; // Reticular → Thalamus (inhibitory)
509 float w_CR = 0.2f; // Cortex → Reticular
510
511 void step(float dt, float sensory_input) {
512 // Thalamus receives sensory input and cortical feedback
513 thalamus.I_E = sensory_input + w_CT * cortex.E;
514 thalamus.I_I = w_RT * reticular.E; // TRN inhibition
515
516 // Cortex receives thalamic input
517 cortex.I_E = w_TC * thalamus.E;
518
519 // Reticular receives collaterals
520 reticular.I_E = w_TR * thalamus.E + w_CR * cortex.E;
521
522 thalamus.step(dt);
523 cortex.step(dt);
524 reticular.step(dt);
525 }
526};
527
528// Basal Ganglia Circuit
529// Direct and Indirect pathways for action selection
530struct BasalGanglia {
531 // Nuclei
532 float striatum_D1 = 0.0f; // Direct pathway
533 float striatum_D2 = 0.0f; // Indirect pathway
534 float GPe = 0.5f; // Globus Pallidus external
535 float GPi = 0.5f; // Globus Pallidus internal
536 float STN = 0.2f; // Subthalamic Nucleus
537 float SNr = 0.5f; // Substantia Nigra reticulata
538
539 // Dopamine modulation
540 float dopamine = 1.0f; // D1 enhance, D2 suppress
541
542 float tau = 20.0f;
543
544 void step(float dt, float cortical_input) {
545 // Cortex → Striatum
546 float d_D1 = (-striatum_D1 + cortical_input * dopamine) / tau;
547 float d_D2 = (-striatum_D2 + cortical_input / dopamine) / tau;
548
549 // Direct: Striatum D1 → GPi (inhibitory)
550 // Indirect: Striatum D2 → GPe → STN → GPi
551 float d_GPe = (-GPe + (1.0f - striatum_D2)) / tau;
552 float d_STN = (-STN + (1.0f - GPe)) / tau;
553 float d_GPi = (-GPi + STN - striatum_D1) / tau;
554
555 striatum_D1 += d_D1 * dt;
556 striatum_D2 += d_D2 * dt;
557 GPe += d_GPe * dt;
558 STN += d_STN * dt;
559 GPi += d_GPi * dt;
560
561 // Clamp
562 striatum_D1 = std::clamp(striatum_D1, 0.0f, 1.0f);
563 striatum_D2 = std::clamp(striatum_D2, 0.0f, 1.0f);
564 GPe = std::clamp(GPe, 0.0f, 1.0f);
565 STN = std::clamp(STN, 0.0f, 1.0f);
566 GPi = std::clamp(GPi, 0.0f, 1.0f);
567 }
568
569 // Thalamic disinhibition (output)
570 float output() const { return 1.0f - GPi; }
571};
572
573// Cerebellar Computation (error-driven learning)
574struct Cerebellum {
575 static constexpr size_t N_GRANULE = 1000;
576 static constexpr size_t N_PURKINJE = 10;
577
578 // Mossy fiber input
579 std::array<float, 64> mossy_input;
580
581 // Granule cell expansion (sparse coding)
582 std::array<float, N_GRANULE> granule;
583
584 // Purkinje cells
585 std::array<float, N_PURKINJE> purkinje;
586
587 // Parallel fiber → Purkinje weights (plastic)
588 std::array<std::array<float, N_GRANULE>, N_PURKINJE> weights;
589
590 // Climbing fiber error signal
591 float climbing_fiber = 0.0f;
592
593 float learning_rate = 0.01f;
594
595 void initialize() {
596 mossy_input.fill(0.0f);
597 granule.fill(0.0f);
598 purkinje.fill(0.0f);
599
600 // Random initial weights
601 for (auto& w_row : weights) {
602 for (auto& w : w_row) {
603 w = 0.5f;
604 }
605 }
606 }
607
608 void step(float dt) {
609 // Granule cell activation (sparse)
610 for (size_t i = 0; i < N_GRANULE; ++i) {
611 float input_sum = 0.0f;
612 for (size_t j = 0; j < mossy_input.size(); ++j) {
613 input_sum += mossy_input[j] * ((i * j) % 2 == 0 ? 1.0f : 0.0f);
614 }
615 granule[i] = (input_sum > 0.5f) ? 1.0f : 0.0f;
616 }
617
618 // Purkinje cell computation
619 for (size_t p = 0; p < N_PURKINJE; ++p) {
620 float pf_input = 0.0f;
621 for (size_t g = 0; g < N_GRANULE; ++g) {
622 pf_input += weights[p][g] * granule[g];
623 }
624 purkinje[p] = 1.0f / (1.0f + std::exp(-pf_input + 5.0f));
625 }
626
627 // LTD at parallel fiber synapses (climbing fiber signal)
628 if (climbing_fiber > 0.5f) {
629 for (size_t p = 0; p < N_PURKINJE; ++p) {
630 for (size_t g = 0; g < N_GRANULE; ++g) {
631 if (granule[g] > 0.5f) {
632 weights[p][g] -= learning_rate * climbing_fiber;
633 weights[p][g] = std::max(0.0f, weights[p][g]);
634 }
635 }
636 }
637 }
638 }
639
640 // Deep cerebellar nuclei output (disinhibition)
641 float output() const {
642 float sum = 0.0f;
643 for (float p : purkinje) sum += p;
644 return 1.0f - sum / N_PURKINJE;
645 }
646};
647
648// Spinal Cord Reflex Arc
649// Simple 3-neuron circuit: Sensory → Interneuron → Motor
650struct SpinalReflex {
651 HodgkinHuxley sensory;
652 HodgkinHuxley interneuron;
653 HodgkinHuxley motor;
654
655 AMPASynapse s_to_i; // Sensory → Interneuron
656 AMPASynapse i_to_m; // Interneuron → Motor
657
658 float sensory_threshold = 5.0f;
659
660 void step(float dt, float stimulus) {
661 // Sensory neuron responds to stimulus
662 sensory.step(dt, stimulus);
663
664 // If sensory spikes, activate synapse
665 if (sensory.is_spiking()) {
666 s_to_i.receive_spike();
667 }
668 s_to_i.step(dt);
669
670 // Interneuron receives synaptic current
671 interneuron.step(dt, s_to_i.current(interneuron.V));
672
673 // Interneuron drives motor neuron
674 if (interneuron.is_spiking()) {
675 i_to_m.receive_spike();
676 }
677 i_to_m.step(dt);
678
679 motor.step(dt, i_to_m.current(motor.V));
680 }
681
682 // Motor output (muscle activation)
683 float motor_output() const {
684 return motor.is_spiking() ? 1.0f : 0.0f;
685 }
686};
687
688// ═══════════════════════════════════════════════════════════════════════════════
689// INTEGRATED NERVOUS SYSTEM
690// Connects all components
691// ═══════════════════════════════════════════════════════════════════════════════
692
693struct NervousSystem {
694 // Cortical areas
695 std::array<CorticalColumn, 4> cortical_columns; // Simplified cortex
696
697 // Subcortical structures
698 ThalamoCorticalLoop thalamo_cortical;
699 BasalGanglia basal_ganglia;
700 Cerebellum cerebellum;
701
702 // Spinal cord
703 std::array<SpinalReflex, 4> spinal_segments;
704
705 // Global state
706 float arousal = 0.5f; // Reticular activating system
707 float attention = 0.5f; // Selective attention modulation
708
709 void initialize() {
710 for (auto& col : cortical_columns) col.initialize();
711 cerebellum.initialize();
712 }
713
714 void step(float dt, const std::array<float, 4>& sensory_inputs) {
715 // 1. Sensory input → Thalamus → Cortex
716 float avg_input = 0.0f;
717 for (float s : sensory_inputs) avg_input += s;
718 avg_input /= 4.0f;
719
720 thalamo_cortical.step(dt, avg_input * arousal);
721
722 // 2. Cortex → Basal Ganglia (action selection)
723 basal_ganglia.step(dt, thalamo_cortical.cortex.E);
724
725 // 3. Cortex + Basal Ganglia → Cerebellum (motor learning)
726 for (size_t i = 0; i < cerebellum.mossy_input.size(); ++i) {
727 cerebellum.mossy_input[i] = (i < 4) ? sensory_inputs[i] : 0.0f;
728 }
729 cerebellum.step(dt);
730
731 // 4. Motor output → Spinal cord
732 float motor_command = basal_ganglia.output() * cerebellum.output();
733 for (size_t i = 0; i < 4; ++i) {
734 // Descending motor command + local sensory
735 float stimulus = motor_command * 10.0f + sensory_inputs[i] * 5.0f;
736 spinal_segments[i].step(dt, stimulus);
737 }
738
739 // 5. Update arousal (homeostatic)
740 arousal = 0.99f * arousal + 0.01f * avg_input;
741 }
742
743 // Get motor outputs
744 std::array<float, 4> motor_outputs() const {
745 std::array<float, 4> out;
746 for (size_t i = 0; i < 4; ++i) {
747 out[i] = spinal_segments[i].motor_output();
748 }
749 return out;
750 }
751
752 // Consciousness metric (integrated information)
753 float consciousness() const {
754 float phi = 0.0f;
755 phi += thalamo_cortical.cortex.E;
756 phi += thalamo_cortical.thalamus.E;
757 phi += (1.0f - basal_ganglia.GPi);
758 phi += arousal;
759 return phi / 4.0f;
760 }
761};
762
763} // namespace neuro
764} // namespace mind_farm
765