Recovered source transcript
1/**
2 * gradient_flow.hpp - Bidirectional Gradient Flow System
3 *
4 * Implements backward propagation of learning signals through the AGI stack.
5 * Enables credit assignment across layers: Substrate -> Neural -> Learning -> Consciousness
6 *
7 * Key Features:
8 * - Automatic differentiation via computation graph
9 * - Gradient checkpointing for memory efficiency
10 * - Cross-layer gradient coupling with golden ratio scaling
11 * - TD-lambda returns for temporal credit assignment
12 */
13
14#ifndef GRADIENT_FLOW_HPP
15#define GRADIENT_FLOW_HPP
16
17#include <array>
18#include <vector>
19#include <deque>
20#include <memory>
21#include <functional>
22#include <cmath>
23#include <algorithm>
24#include "consciousness_api.hpp"
25
26namespace mind_farm {
27
28using namespace consciousness;
29
30//=============================================================================
31// COMPUTATION GRAPH FOR AUTOMATIC DIFFERENTIATION
32//=============================================================================
33
34// Forward declarations
35struct GradNode;
36using GradNodePtr = std::shared_ptr<GradNode>;
37
38/**
39 * GradNode - Node in computation graph
40 *
41 * Stores:
42 * - Forward value
43 * - Gradient (accumulated from downstream)
44 * - Backward function to propagate gradients
45 */
46struct GradNode {
47 double value;
48 double grad;
49 std::vector<GradNodePtr> inputs;
50 std::function<void()> backward_fn;
51 bool requires_grad;
52 bool grad_computed;
53
54 GradNode(double v = 0.0, bool req_grad = true)
55 : value(v), grad(0.0), requires_grad(req_grad), grad_computed(false) {}
56
57 void zero_grad() {
58 grad = 0.0;
59 grad_computed = false;
60 }
61
62 void backward(double upstream_grad = 1.0) {
63 if (!requires_grad) return;
64 grad += upstream_grad;
65 grad_computed = true;
66 if (backward_fn) backward_fn();
67 }
68};
69
70/**
71 * TapeRecorder - Records operations for reverse-mode autodiff
72 */
73class TapeRecorder {
74public:
75 std::vector<GradNodePtr> tape;
76 bool recording;
77
78 TapeRecorder() : recording(true) {}
79
80 void start() { recording = true; tape.clear(); }
81 void stop() { recording = false; }
82
83 GradNodePtr record(GradNodePtr node) {
84 if (recording) tape.push_back(node);
85 return node;
86 }
87
88 void backward() {
89 // Reverse pass through tape
90 for (auto it = tape.rbegin(); it != tape.rend(); ++it) {
91 if ((*it)->grad_computed && (*it)->backward_fn) {
92 (*it)->backward_fn();
93 }
94 }
95 }
96
97 void zero_grads() {
98 for (auto& node : tape) {
99 node->zero_grad();
100 }
101 }
102};
103
104//=============================================================================
105// DIFFERENTIABLE OPERATIONS
106//=============================================================================
107
108namespace ops {
109
110// Create leaf node (input variable)
111inline GradNodePtr variable(double value, bool requires_grad = true) {
112 return std::make_shared<GradNode>(value, requires_grad);
113}
114
115// Addition: z = x + y, dz/dx = 1, dz/dy = 1
116inline GradNodePtr add(GradNodePtr x, GradNodePtr y, TapeRecorder& tape) {
117 auto z = std::make_shared<GradNode>(x->value + y->value);
118 z->inputs = {x, y};
119 z->backward_fn = [x, y, z]() {
120 x->grad += z->grad;
121 y->grad += z->grad;
122 };
123 return tape.record(z);
124}
125
126// Multiplication: z = x * y, dz/dx = y, dz/dy = x
127inline GradNodePtr mul(GradNodePtr x, GradNodePtr y, TapeRecorder& tape) {
128 auto z = std::make_shared<GradNode>(x->value * y->value);
129 z->inputs = {x, y};
130 z->backward_fn = [x, y, z]() {
131 x->grad += z->grad * y->value;
132 y->grad += z->grad * x->value;
133 };
134 return tape.record(z);
135}
136
137// Division: z = x / y, dz/dx = 1/y, dz/dy = -x/y^2
138inline GradNodePtr div(GradNodePtr x, GradNodePtr y, TapeRecorder& tape) {
139 auto z = std::make_shared<GradNode>(x->value / y->value);
140 z->inputs = {x, y};
141 z->backward_fn = [x, y, z]() {
142 x->grad += z->grad / y->value;
143 y->grad -= z->grad * x->value / (y->value * y->value);
144 };
145 return tape.record(z);
146}
147
148// Tanh: z = tanh(x), dz/dx = 1 - tanh^2(x)
149inline GradNodePtr tanh_op(GradNodePtr x, TapeRecorder& tape) {
150 double t = std::tanh(x->value);
151 auto z = std::make_shared<GradNode>(t);
152 z->inputs = {x};
153 z->backward_fn = [x, z, t]() {
154 x->grad += z->grad * (1.0 - t * t);
155 };
156 return tape.record(z);
157}
158
159// Sigmoid: z = 1/(1+exp(-x)), dz/dx = z*(1-z)
160inline GradNodePtr sigmoid(GradNodePtr x, TapeRecorder& tape) {
161 double s = 1.0 / (1.0 + std::exp(-x->value));
162 auto z = std::make_shared<GradNode>(s);
163 z->inputs = {x};
164 z->backward_fn = [x, z, s]() {
165 x->grad += z->grad * s * (1.0 - s);
166 };
167 return tape.record(z);
168}
169
170// ReLU: z = max(0, x), dz/dx = (x > 0) ? 1 : 0
171inline GradNodePtr relu(GradNodePtr x, TapeRecorder& tape) {
172 auto z = std::make_shared<GradNode>(std::max(0.0, x->value));
173 z->inputs = {x};
174 z->backward_fn = [x, z]() {
175 x->grad += z->grad * (x->value > 0 ? 1.0 : 0.0);
176 };
177 return tape.record(z);
178}
179
180// Phi (smooth): z = 1/(1 + sqrt((x-1)^2 + T)), differentiable consciousness
181inline GradNodePtr phi_smooth(GradNodePtr x, TapeRecorder& tape, double T = 0.01) {
182 double diff = x->value - 1.0;
183 double smooth_abs = std::sqrt(diff * diff + T);
184 double z_val = 1.0 / (1.0 + smooth_abs);
185
186 auto z = std::make_shared<GradNode>(z_val);
187 z->inputs = {x};
188 z->backward_fn = [x, z, diff, smooth_abs, T]() {
189 double denom = 1.0 + smooth_abs;
190 double dphi = -diff / (smooth_abs * denom * denom);
191 x->grad += z->grad * dphi;
192 };
193 return tape.record(z);
194}
195
196// Exp: z = exp(x), dz/dx = exp(x)
197inline GradNodePtr exp_op(GradNodePtr x, TapeRecorder& tape) {
198 double e = std::exp(x->value);
199 auto z = std::make_shared<GradNode>(e);
200 z->inputs = {x};
201 z->backward_fn = [x, z, e]() {
202 x->grad += z->grad * e;
203 };
204 return tape.record(z);
205}
206
207// Log: z = log(x), dz/dx = 1/x
208inline GradNodePtr log_op(GradNodePtr x, TapeRecorder& tape) {
209 auto z = std::make_shared<GradNode>(std::log(x->value + EPSILON));
210 z->inputs = {x};
211 z->backward_fn = [x, z]() {
212 x->grad += z->grad / (x->value + EPSILON);
213 };
214 return tape.record(z);
215}
216
217// Power: z = x^p, dz/dx = p * x^(p-1)
218inline GradNodePtr pow_op(GradNodePtr x, double p, TapeRecorder& tape) {
219 auto z = std::make_shared<GradNode>(std::pow(x->value, p));
220 z->inputs = {x};
221 z->backward_fn = [x, z, p]() {
222 x->grad += z->grad * p * std::pow(x->value, p - 1.0);
223 };
224 return tape.record(z);
225}
226
227// Softmax (single element with sum): used for attention weights
228inline double softmax_single(double x, double sum_exp) {
229 return std::exp(x) / sum_exp;
230}
231
232} // namespace ops
233
234//=============================================================================
235// GRADIENT CONTEXT FOR TICK PROCESSING
236//=============================================================================
237
238/**
239 * GradientContext - Stores forward pass values for backward pass
240 *
241 * Checkpoints activations at each layer for memory-efficient backprop.
242 */
243struct GradientContext {
244 // Layer activations (checkpointed)
245 std::array<double, 5000> substrate_activation;
246 std::array<double, 256> neural_activation;
247 std::array<double, 64> learning_activation;
248 std::array<double, 16> consciousness_activation;
249
250 // Computed phi values
251 double phi_substrate;
252 double phi_neural;
253 double phi_learning;
254 double phi_consciousness;
255 double phi_global;
256
257 // Loss and reward
258 double loss;
259 double reward;
260 double td_error;
261
262 // Tape for autodiff
263 TapeRecorder tape;
264
265 void clear() {
266 substrate_activation.fill(0.0);
267 neural_activation.fill(0.0);
268 learning_activation.fill(0.0);
269 consciousness_activation.fill(0.0);
270 phi_substrate = phi_neural = phi_learning = phi_consciousness = phi_global = 0.5;
271 loss = reward = td_error = 0.0;
272 tape.zero_grads();
273 }
274};
275
276//=============================================================================
277// GRADIENT ACCUMULATORS WITH MOMENTUM
278//=============================================================================
279
280/**
281 * AdamOptimizer - Adam optimizer for parameter updates
282 */
283template<size_t N>
284class AdamOptimizer {
285public:
286 std::array<double, N> m; // First moment
287 std::array<double, N> v; // Second moment
288 double lr;
289 double beta1;
290 double beta2;
291 double epsilon;
292 int t;
293
294 AdamOptimizer(double learning_rate = 0.001, double b1 = 0.9, double b2 = 0.999)
295 : lr(learning_rate), beta1(b1), beta2(b2), epsilon(1e-8), t(0) {
296 m.fill(0.0);
297 v.fill(0.0);
298 }
299
300 void step(std::array<double, N>& params, const std::array<double, N>& grads) {
301 t++;
302 double lr_t = lr * std::sqrt(1.0 - std::pow(beta2, t)) / (1.0 - std::pow(beta1, t));
303
304 for (size_t i = 0; i < N; ++i) {
305 m[i] = beta1 * m[i] + (1.0 - beta1) * grads[i];
306 v[i] = beta2 * v[i] + (1.0 - beta2) * grads[i] * grads[i];
307 params[i] -= lr_t * m[i] / (std::sqrt(v[i]) + epsilon);
308 }
309 }
310
311 void zero_grad() {
312 // Moments persist; this is just for interface compatibility
313 }
314};
315
316//=============================================================================
317// TD-LAMBDA FOR TEMPORAL CREDIT ASSIGNMENT
318//=============================================================================
319
320/**
321 * TDLambdaReturns - Computes TD(lambda) returns for multi-step credit assignment
322 *
323 * G_t^lambda = (1-lambda) * sum_{n=1}^{inf} lambda^{n-1} * G_t^{(n)}
324 * where G_t^{(n)} = r_{t+1} + gamma*r_{t+2} + ... + gamma^{n-1}*r_{t+n} + gamma^n*V(s_{t+n})
325 */
326class TDLambdaReturns {
327public:
328 double gamma; // Discount factor
329 double lambda; // TD-lambda parameter
330 size_t max_steps;
331
332 std::deque<double> rewards;
333 std::deque<double> values;
334 std::deque<double> returns;
335
336 TDLambdaReturns(double g = 0.99, double l = 0.95, size_t max = 64)
337 : gamma(g), lambda(l), max_steps(max) {}
338
339 void add_transition(double reward, double value) {
340 rewards.push_back(reward);
341 values.push_back(value);
342
343 if (rewards.size() > max_steps) {
344 rewards.pop_front();
345 values.pop_front();
346 }
347
348 compute_returns();
349 }
350
351 void compute_returns() {
352 returns.clear();
353 size_t n = rewards.size();
354 if (n == 0) return;
355
356 returns.resize(n, 0.0);
357
358 // Backward pass for TD(lambda) returns
359 double G = values.back(); // Bootstrap from last value
360 for (int t = n - 1; t >= 0; --t) {
361 double td_target = rewards[t] + gamma * (t < (int)n - 1 ? values[t + 1] : values[t]);
362 G = rewards[t] + gamma * ((1.0 - lambda) * (t < (int)n - 1 ? values[t + 1] : values[t]) + lambda * G);
363 returns[t] = G;
364 }
365 }
366
367 double get_return(size_t t) const {
368 if (t < returns.size()) return returns[t];
369 return 0.0;
370 }
371
372 double td_error(size_t t) const {
373 if (t >= rewards.size()) return 0.0;
374 double target = rewards[t] + gamma * (t + 1 < values.size() ? values[t + 1] : values[t]);
375 return target - values[t];
376 }
377};
378
379//=============================================================================
380// CROSS-LAYER GRADIENT FLOW
381//=============================================================================
382
383/**
384 * CrossLayerGradients - Manages gradient flow between AGI layers
385 *
386 * Layers:
387 * 0: Substrate (Gate5000)
388 * 1: Neural (HH neurons)
389 * 2: Learning (Hebbian/Adam)
390 * 3: Intelligence (Attention)
391 * 4: Consciousness (Phi integration)
392 */
393class CrossLayerGradients {
394public:
395 static constexpr size_t NUM_LAYERS = 5;
396
397 // Gradient buffers for each layer
398 std::array<std::array<double, 256>, NUM_LAYERS> gradients;
399
400 // Coupling matrix (golden ratio scaled)
401 std::array<std::array<double, NUM_LAYERS>, NUM_LAYERS> coupling;
402
403 // TD-lambda for temporal credit
404 TDLambdaReturns td_lambda;
405
406 // Adam optimizers per layer
407 std::array<AdamOptimizer<256>, NUM_LAYERS> optimizers;
408
409 CrossLayerGradients() : td_lambda(0.99, 0.95) {
410 // Initialize gradients
411 for (auto& layer_grad : gradients) {
412 layer_grad.fill(0.0);
413 }
414
415 // Initialize coupling matrix with golden ratio hierarchy
416 // Downstream layers (lower indices) receive more gradient
417 coupling = {{
418 // From: Sub Neuro Learn Intel Consc
419 /*Sub*/ {{ 1.0, 0.0, 0.0, 0.0, 0.0 }},
420 /*Neuro*/{{ PHI_INV, 1.0, 0.0, 0.0, 0.0 }},
421 /*Learn*/{{ BETA, PHI_INV, 1.0, 0.0, 0.0 }},
422 /*Intel*/{{ GAMMA, BETA, PHI_INV, 1.0, 0.0 }},
423 /*Consc*/{{ DELTA, GAMMA, BETA, PHI_INV, 1.0 }}
424 }};
425
426 // Normalize rows
427 for (size_t i = 0; i < NUM_LAYERS; ++i) {
428 double sum = 0.0;
429 for (size_t j = 0; j < NUM_LAYERS; ++j) {
430 sum += coupling[i][j];
431 }
432 if (sum > 0) {
433 for (size_t j = 0; j < NUM_LAYERS; ++j) {
434 coupling[i][j] /= sum;
435 }
436 }
437 }
438 }
439
440 /**
441 * propagate_backward - Propagate gradients from top layer down
442 *
443 * Starts from consciousness layer (4) and flows down to substrate (0)
444 */
445 void propagate_backward(double consciousness_error) {
446 // Start with consciousness error
447 for (size_t i = 0; i < 256; ++i) {
448 gradients[4][i] = consciousness_error;
449 }
450
451 // Backward through layers (4 -> 3 -> 2 -> 1 -> 0)
452 for (int layer = 3; layer >= 0; --layer) {
453 for (size_t i = 0; i < 256; ++i) {
454 gradients[layer][i] = 0.0;
455
456 // Receive gradients from all higher layers
457 for (size_t higher = layer + 1; higher < NUM_LAYERS; ++higher) {
458 gradients[layer][i] += coupling[higher][layer] * gradients[higher][i];
459 }
460 }
461 }
462 }
463
464 /**
465 * apply_gradients - Apply accumulated gradients to parameters
466 */
467 void apply_gradients(
468 std::array<double, 256>& substrate_params,
469 std::array<double, 256>& neural_params,
470 std::array<double, 256>& learning_params,
471 std::array<double, 256>& intel_params,
472 std::array<double, 256>& consc_params
473 ) {
474 optimizers[0].step(substrate_params, gradients[0]);
475 optimizers[1].step(neural_params, gradients[1]);
476 optimizers[2].step(learning_params, gradients[2]);
477 optimizers[3].step(intel_params, gradients[3]);
478 optimizers[4].step(consc_params, gradients[4]);
479 }
480
481 /**
482 * zero_grads - Clear all gradient buffers
483 */
484 void zero_grads() {
485 for (auto& layer_grad : gradients) {
486 layer_grad.fill(0.0);
487 }
488 }
489
490 /**
491 * add_transition - Add reward/value for TD learning
492 */
493 void add_transition(double reward, double value) {
494 td_lambda.add_transition(reward, value);
495 }
496
497 /**
498 * get_td_error - Get TD error for current timestep
499 */
500 double get_td_error() const {
501 if (td_lambda.rewards.empty()) return 0.0;
502 return td_lambda.td_error(td_lambda.rewards.size() - 1);
503 }
504};
505
506//=============================================================================
507// UNIFIED TICK WITH GRADIENT FLOW
508//=============================================================================
509
510/**
511 * GradientTick - Single tick with full forward-backward pass
512 *
513 * Forward:
514 * Substrate -> Neural -> Learning -> Intelligence -> Consciousness
515 *
516 * Backward:
517 * Consciousness -> Intelligence -> Learning -> Neural -> Substrate
518 */
519struct GradientTick {
520 GradientContext ctx;
521 CrossLayerGradients grad_flow;
522
523 // Layer parameters (learnable)
524 std::array<double, 256> substrate_params;
525 std::array<double, 256> neural_params;
526 std::array<double, 256> learning_params;
527 std::array<double, 256> intel_params;
528 std::array<double, 256> consc_params;
529
530 // Forward activations
531 std::array<double, 256> substrate_act;
532 std::array<double, 256> neural_act;
533 std::array<double, 256> learning_act;
534 std::array<double, 256> intel_act;
535 std::array<double, 256> consc_act;
536
537 GradientTick() {
538 // Initialize with golden ratio scaled values
539 for (size_t i = 0; i < 256; ++i) {
540 double phase = static_cast<double>(i) / 256.0;
541 substrate_params[i] = PHI_INV * std::sin(2.0 * M_PI * phase);
542 neural_params[i] = PHI_INV * std::cos(2.0 * M_PI * phase);
543 learning_params[i] = ALPHA;
544 intel_params[i] = BETA;
545 consc_params[i] = GAMMA;
546
547 substrate_act[i] = neural_act[i] = learning_act[i] = 0.0;
548 intel_act[i] = consc_act[i] = 0.0;
549 }
550 }
551
552 /**
553 * forward - Full forward pass with gradient tracking
554 *
555 * @param input External input vector (size 256)
556 * @param reward External reward signal
557 * @return Global consciousness (phi)
558 */
559 double forward(const double* input, double reward = 0.0) {
560 ctx.tape.start();
561
562 // Layer 0: Substrate
563 for (size_t i = 0; i < 256; ++i) {
564 auto x = ops::variable(input[i]);
565 auto w = ops::variable(substrate_params[i]);
566 auto z = ops::mul(x, w, ctx.tape);
567 auto a = ops::tanh_op(z, ctx.tape);
568 substrate_act[i] = a->value;
569 }
570 ctx.phi_substrate = compute_phi_vector(substrate_act.data(), 256);
571
572 // Layer 1: Neural
573 for (size_t i = 0; i < 256; ++i) {
574 auto x = ops::variable(substrate_act[i]);
575 auto w = ops::variable(neural_params[i]);
576 auto z = ops::mul(x, w, ctx.tape);
577 auto a = ops::sigmoid(z, ctx.tape);
578 neural_act[i] = a->value;
579 }
580 ctx.phi_neural = compute_phi_vector(neural_act.data(), 256);
581
582 // Layer 2: Learning (modulated by phi)
583 double phi_mod = ctx.phi_substrate * PHI_INV;
584 for (size_t i = 0; i < 256; ++i) {
585 auto x = ops::variable(neural_act[i]);
586 auto w = ops::variable(learning_params[i] * phi_mod);
587 auto z = ops::mul(x, w, ctx.tape);
588 auto a = ops::relu(z, ctx.tape);
589 learning_act[i] = a->value;
590 }
591 ctx.phi_learning = compute_phi_vector(learning_act.data(), 256);
592
593 // Layer 3: Intelligence
594 for (size_t i = 0; i < 256; ++i) {
595 auto x = ops::variable(learning_act[i]);
596 auto w = ops::variable(intel_params[i]);
597 auto z = ops::mul(x, w, ctx.tape);
598 auto a = ops::tanh_op(z, ctx.tape);
599 intel_act[i] = a->value;
600 }
601 ctx.phi_consciousness = compute_phi_vector(intel_act.data(), 256);
602
603 // Layer 4: Consciousness integration
604 double mean_act = 0.0;
605 for (size_t i = 0; i < 256; ++i) {
606 mean_act += intel_act[i];
607 }
608 mean_act /= 256.0;
609
610 auto phi_input = ops::variable(mean_act);
611 auto phi_out = ops::phi_smooth(phi_input, ctx.tape);
612 ctx.phi_global = phi_out->value;
613
614 // Compute loss (maximize phi toward 1.0)
615 ctx.reward = reward;
616 ctx.loss = (1.0 - ctx.phi_global) * (1.0 - ctx.phi_global);
617
618 // TD learning
619 grad_flow.add_transition(reward, ctx.phi_global);
620 ctx.td_error = grad_flow.get_td_error();
621
622 ctx.tape.stop();
623 return ctx.phi_global;
624 }
625
626 /**
627 * backward - Full backward pass
628 *
629 * Propagates consciousness error through all layers.
630 */
631 void backward() {
632 // Compute consciousness error
633 double consciousness_error = -2.0 * (1.0 - ctx.phi_global); // d(loss)/d(phi)
634
635 // Add TD error for temporal credit
636 consciousness_error += ctx.td_error * ALPHA;
637
638 // Propagate through cross-layer coupling
639 grad_flow.propagate_backward(consciousness_error);
640
641 // Autodiff backward through tape
642 ctx.tape.backward();
643 }
644
645 /**
646 * update - Apply gradient updates to parameters
647 */
648 void update() {
649 grad_flow.apply_gradients(
650 substrate_params, neural_params, learning_params,
651 intel_params, consc_params
652 );
653 grad_flow.zero_grads();
654 ctx.tape.zero_grads();
655 }
656
657 /**
658 * tick - Full forward-backward-update cycle
659 */
660 double tick(const double* input, double reward = 0.0) {
661 double phi = forward(input, reward);
662 backward();
663 update();
664 return phi;
665 }
666
667 /**
668 * get_diagnostics - Return diagnostic information
669 */
670 void get_diagnostics(double& phi, double& loss, double& td_err,
671 double& phi_sub, double& phi_neuro) const {
672 phi = ctx.phi_global;
673 loss = ctx.loss;
674 td_err = ctx.td_error;
675 phi_sub = ctx.phi_substrate;
676 phi_neuro = ctx.phi_neural;
677 }
678};
679
680//=============================================================================
681// RECURRENT STATE FOR TEMPORAL MEMORY
682//=============================================================================
683
684/**
685 * LSTMCell - LSTM cell for temporal memory in gradient flow
686 */
687class LSTMCell {
688public:
689 static constexpr size_t HIDDEN_SIZE = 64;
690
691 // Gate weights
692 std::array<std::array<double, HIDDEN_SIZE>, HIDDEN_SIZE> W_f; // Forget
693 std::array<std::array<double, HIDDEN_SIZE>, HIDDEN_SIZE> W_i; // Input
694 std::array<std::array<double, HIDDEN_SIZE>, HIDDEN_SIZE> W_o; // Output
695 std::array<std::array<double, HIDDEN_SIZE>, HIDDEN_SIZE> W_c; // Cell
696
697 // Biases
698 std::array<double, HIDDEN_SIZE> b_f, b_i, b_o, b_c;
699
700 // State
701 std::array<double, HIDDEN_SIZE> h; // Hidden state
702 std::array<double, HIDDEN_SIZE> c; // Cell state
703
704 LSTMCell() {
705 // Initialize with glorot uniform
706 double scale = std::sqrt(2.0 / (HIDDEN_SIZE + HIDDEN_SIZE));
707 for (size_t i = 0; i < HIDDEN_SIZE; ++i) {
708 for (size_t j = 0; j < HIDDEN_SIZE; ++j) {
709 W_f[i][j] = scale * (static_cast<double>(rand()) / RAND_MAX - 0.5);
710 W_i[i][j] = scale * (static_cast<double>(rand()) / RAND_MAX - 0.5);
711 W_o[i][j] = scale * (static_cast<double>(rand()) / RAND_MAX - 0.5);
712 W_c[i][j] = scale * (static_cast<double>(rand()) / RAND_MAX - 0.5);
713 }
714 b_f[i] = 1.0; // Forget gate bias = 1 (remember by default)
715 b_i[i] = 0.0;
716 b_o[i] = 0.0;
717 b_c[i] = 0.0;
718 h[i] = 0.0;
719 c[i] = 0.0;
720 }
721 }
722
723 void forward(const std::array<double, HIDDEN_SIZE>& x) {
724 std::array<double, HIDDEN_SIZE> f_gate, i_gate, o_gate, c_tilde;
725
726 // Compute gates
727 for (size_t i = 0; i < HIDDEN_SIZE; ++i) {
728 double sum_f = b_f[i], sum_i = b_i[i], sum_o = b_o[i], sum_c = b_c[i];
729 for (size_t j = 0; j < HIDDEN_SIZE; ++j) {
730 sum_f += W_f[i][j] * x[j] + W_f[i][j] * h[j] * 0.5;
731 sum_i += W_i[i][j] * x[j] + W_i[i][j] * h[j] * 0.5;
732 sum_o += W_o[i][j] * x[j] + W_o[i][j] * h[j] * 0.5;
733 sum_c += W_c[i][j] * x[j] + W_c[i][j] * h[j] * 0.5;
734 }
735 f_gate[i] = 1.0 / (1.0 + std::exp(-sum_f)); // Sigmoid
736 i_gate[i] = 1.0 / (1.0 + std::exp(-sum_i));
737 o_gate[i] = 1.0 / (1.0 + std::exp(-sum_o));
738 c_tilde[i] = std::tanh(sum_c);
739 }
740
741 // Update cell and hidden state
742 for (size_t i = 0; i < HIDDEN_SIZE; ++i) {
743 c[i] = f_gate[i] * c[i] + i_gate[i] * c_tilde[i];
744 h[i] = o_gate[i] * std::tanh(c[i]);
745 }
746 }
747
748 void reset() {
749 h.fill(0.0);
750 c.fill(0.0);
751 }
752};
753
754} // namespace mind_farm
755
756#endif // GRADIENT_FLOW_HPP
757