Recovered source transcript
1// ==============================================================================
2// The-Tired-AGI Core: FGTP Engine Implementation
3// Energy Field + Driver Function f_a5
4// ==============================================================================
5
6#include "fgtp_engine.hpp"
7#include <cmath>
8#include <algorithm>
9#include <numeric>
10#include <execution>
11#include <limits>
12
13namespace tired_agi {
14
15// ==============================================================================
16// Constructor
17// ==============================================================================
18
19FGTPEngine::FGTPEngine(FGTPConfig config) noexcept
20 : config_(config)
21 , helix_engine_()
22{
23 // Initialize momentum buffers (empty initially, will grow as needed)
24 momentum_buffers_.reserve(1024);
25}
26
27// ==============================================================================
28// Energy Field Computation
29// ==============================================================================
30
31EnergyField FGTPEngine::compute_energy_field(const HelixState& helix) const noexcept {
32 EnergyField field;
33 field.phi = helix.phi;
34 field.entropy = helix.entropy;
35 field.tensor = helix.tensor;
36 field.drift = helix.drift;
37 field.tick = helix.tick;
38
39 // Core energy equation: E = φ × (1 + entropy) × (1 + |tensor|)
40 field.energy = config_.phi_weight * helix.phi
41 * (1.0 + config_.entropy_weight * helix.entropy)
42 * (1.0 + config_.tensor_weight * std::abs(helix.tensor));
43
44 stat_total_computations_.fetch_add(1, std::memory_order_relaxed);
45 update_statistics(field, 0.0);
46
47 return field;
48}
49
50EnergyField FGTPEngine::compute_energy_field(
51 const double* embedding,
52 size_t size,
53 uint64_t tick
54) noexcept {
55 // Compute helix state first
56 HelixState helix = helix_engine_.compute(embedding, size, tick);
57 return compute_energy_field(helix);
58}
59
60// ==============================================================================
61// Energy Gradient Computation
62// ==============================================================================
63
64EnergyGradient FGTPEngine::compute_gradient(
65 const double* embedding,
66 size_t size,
67 double epsilon
68) noexcept {
69 EnergyGradient grad;
70
71 if (size < 3) {
72 // Not enough dimensions for 3D gradient
73 return grad;
74 }
75
76 // Allocate workspace for perturbed embeddings
77 std::vector<double> perturbed(embedding, embedding + size);
78
79 // Compute central energy
80 EnergyField center = compute_energy_field(embedding, size, 0);
81 double E_center = center.energy;
82
83 // Compute partial derivatives using finite differences
84 // ∂E/∂x
85 perturbed[0] = embedding[0] + epsilon;
86 double E_plus_x = compute_energy_field(perturbed.data(), size, 0).energy;
87 perturbed[0] = embedding[0] - epsilon;
88 double E_minus_x = compute_energy_field(perturbed.data(), size, 0).energy;
89 grad.dx = (E_plus_x - E_minus_x) / (2.0 * epsilon);
90 perturbed[0] = embedding[0]; // Restore
91
92 // ∂E/∂y
93 perturbed[1] = embedding[1] + epsilon;
94 double E_plus_y = compute_energy_field(perturbed.data(), size, 0).energy;
95 perturbed[1] = embedding[1] - epsilon;
96 double E_minus_y = compute_energy_field(perturbed.data(), size, 0).energy;
97 grad.dy = (E_plus_y - E_minus_y) / (2.0 * epsilon);
98 perturbed[1] = embedding[1]; // Restore
99
100 // ∂E/∂z
101 perturbed[2] = embedding[2] + epsilon;
102 double E_plus_z = compute_energy_field(perturbed.data(), size, 0).energy;
103 perturbed[2] = embedding[2] - epsilon;
104 double E_minus_z = compute_energy_field(perturbed.data(), size, 0).energy;
105 grad.dz = (E_plus_z - E_minus_z) / (2.0 * epsilon);
106 perturbed[2] = embedding[2]; // Restore
107
108 // Compute gradient magnitude
109 grad.magnitude = std::sqrt(grad.dx * grad.dx + grad.dy * grad.dy + grad.dz * grad.dz);
110
111 return grad;
112}
113
114// ==============================================================================
115// Complete Energy State Computation
116// ==============================================================================
117
118EnergyState FGTPEngine::compute_energy_state(
119 const double* embedding,
120 size_t size,
121 const double* velocity,
122 uint64_t tick
123) noexcept {
124 EnergyState state;
125
126 // Compute energy field
127 state.field = compute_energy_field(embedding, size, tick);
128
129 // Compute gradient
130 state.gradient = compute_gradient(embedding, size);
131
132 // Compute kinetic energy (if velocity provided)
133 if (velocity != nullptr) {
134 state.kinetic = compute_kinetic_energy(velocity, size);
135 } else {
136 state.kinetic = 0.0;
137 }
138
139 // Compute potential energy (position-dependent)
140 state.potential = compute_potential_energy(embedding, size);
141
142 // Total energy
143 state.total = state.kinetic + state.potential + state.field.energy;
144
145 return state;
146}
147
148// ==============================================================================
149// Driver Function f_a5
150// ==============================================================================
151
152DriverResult FGTPEngine::apply_driver(
153 const double* embedding,
154 size_t size,
155 const EnergyField& field,
156 const double* external_force
157) noexcept {
158 DriverResult result;
159 result.embedding.resize(size);
160 result.operations = 0;
161
162 // Copy input to output (will be modified)
163 std::copy(embedding, embedding + size, result.embedding.begin());
164
165 // Compute energy gradient (direction of steepest descent)
166 EnergyGradient grad = compute_gradient(embedding, size);
167
168 // Compute update direction based on gradient descent with momentum
169 std::vector<double> update(size, 0.0);
170
171 // Basic gradient component (first 3 dimensions use computed gradient)
172 if (size >= 3) {
173 update[0] = -grad.dx;
174 update[1] = -grad.dy;
175 update[2] = -grad.dz;
176 result.operations += 3;
177 }
178
179 // For remaining dimensions, use approximate gradient via finite differences
180 for (size_t i = 3; i < size; ++i) {
181 std::vector<double> perturbed(embedding, embedding + size);
182 perturbed[i] += 1e-5;
183 double E_plus = compute_energy_field(perturbed.data(), size, field.tick).energy;
184 perturbed[i] = embedding[i] - 1e-5;
185 double E_minus = compute_energy_field(perturbed.data(), size, field.tick).energy;
186 update[i] = -(E_plus - E_minus) / (2e-5);
187 result.operations++;
188 }
189
190 // Apply gradient clipping if enabled
191 if (config_.use_gradient_clipping) {
192 clip_gradient(update.data(), size);
193 }
194
195 // Add external force if provided
196 if (external_force != nullptr) {
197 for (size_t i = 0; i < size; ++i) {
198 update[i] += external_force[i];
199 }
200 result.operations += size;
201 }
202
203 // Apply momentum if enabled
204 if (config_.use_momentum && !momentum_buffers_.empty()) {
205 // Find or create momentum buffer for this embedding size
206 // For simplicity, use a fixed momentum buffer (could be per-agent)
207 static thread_local std::vector<double> momentum;
208 if (momentum.size() != size) {
209 momentum.resize(size, 0.0);
210 }
211
212 for (size_t i = 0; i < size; ++i) {
213 momentum[i] = config_.momentum * momentum[i] + (1.0 - config_.momentum) * update[i];
214 update[i] = momentum[i];
215 }
216 result.operations += size;
217 }
218
219 // Apply update with learning rate
220 double initial_energy = field.energy;
221 for (size_t i = 0; i < size; ++i) {
222 result.embedding[i] += config_.learning_rate * update[i];
223 }
224 result.operations += size;
225
226 // Compute energy after update
227 EnergyField new_field = compute_energy_field(result.embedding.data(), size, field.tick);
228 result.delta_energy = new_field.energy - initial_energy;
229
230 // Clip delta energy if too large
231 if (std::abs(result.delta_energy) > config_.max_delta_energy) {
232 // Scale back the update
233 double scale = config_.max_delta_energy / std::abs(result.delta_energy);
234 for (size_t i = 0; i < size; ++i) {
235 result.embedding[i] = embedding[i] + scale * config_.learning_rate * update[i];
236 }
237 // Recompute energy
238 new_field = compute_energy_field(result.embedding.data(), size, field.tick);
239 result.delta_energy = new_field.energy - initial_energy;
240 }
241
242 // Validate bounds
243 result.bounded = true;
244 if (config_.validate_bounds) {
245 result.bounded = validate_bounds(result.embedding);
246 if (!result.bounded) {
247 stat_total_violations_.fetch_add(1, std::memory_order_relaxed);
248 }
249 }
250
251 // Compute fitness delta (proportional to energy increase and phi)
252 result.fitness_delta = result.delta_energy * new_field.phi;
253
254 stat_total_driver_apps_.fetch_add(1, std::memory_order_relaxed);
255 update_statistics(new_field, result.delta_energy);
256
257 return result;
258}
259
260// ==============================================================================
261// Batch Driver Application
262// ==============================================================================
263
264std::vector<DriverResult> FGTPEngine::apply_driver_batch(
265 const std::vector<std::vector<double>>& embeddings,
266 const std::vector<EnergyField>& fields
267) noexcept {
268 std::vector<DriverResult> results(embeddings.size());
269
270 // Parallel execution using C++17 parallel algorithms
271 std::vector<size_t> indices(embeddings.size());
272 std::iota(indices.begin(), indices.end(), 0);
273
274 std::for_each(
275 std::execution::par_unseq,
276 indices.begin(),
277 indices.end(),
278 [&](size_t i) {
279 results[i] = apply_driver(
280 embeddings[i].data(),
281 embeddings[i].size(),
282 fields[i]
283 );
284 }
285 );
286
287 return results;
288}
289
290// ==============================================================================
291// Advanced Energy Computations
292// ==============================================================================
293
294double FGTPEngine::compute_hamiltonian(const EnergyState& state) const noexcept {
295 // Hamiltonian H = T + V + E_field
296 return state.kinetic + state.potential + state.field.energy;
297}
298
299double FGTPEngine::compute_lagrangian(double kinetic, double potential) const noexcept {
300 // Lagrangian L = T - V
301 return kinetic - potential;
302}
303
304double FGTPEngine::compute_action(
305 const std::vector<EnergyState>& trajectory,
306 double dt
307) const noexcept {
308 // Action S = ∫ L dt
309 double action = 0.0;
310 for (const auto& state : trajectory) {
311 double L = compute_lagrangian(state.kinetic, state.potential);
312 action += L * dt;
313 }
314 return action;
315}
316
317std::vector<double> FGTPEngine::optimize_trajectory(
318 const std::vector<double>& start,
319 const std::vector<double>& end,
320 size_t steps
321) noexcept {
322 // Principle of least action: find trajectory that minimizes action
323 // Use simple linear interpolation as starting guess, then refine
324
325 std::vector<double> best_trajectory = start;
326 double best_action = std::numeric_limits<double>::infinity();
327
328 // Generate candidate trajectory via interpolation
329 std::vector<EnergyState> trajectory(steps);
330 for (size_t i = 0; i < steps; ++i) {
331 double t = static_cast<double>(i) / static_cast<double>(steps - 1);
332 std::vector<double> pos(start.size());
333 for (size_t j = 0; j < start.size(); ++j) {
334 pos[j] = (1.0 - t) * start[j] + t * end[j];
335 }
336
337 // Compute velocity (finite difference)
338 std::vector<double> velocity(start.size(), 0.0);
339 if (i > 0) {
340 for (size_t j = 0; j < start.size(); ++j) {
341 velocity[j] = (pos[j] - trajectory[i-1].field.phi) / 1.0; // dt = 1.0
342 }
343 }
344
345 trajectory[i] = compute_energy_state(pos.data(), pos.size(), velocity.data(), i);
346 }
347
348 double action = compute_action(trajectory, 1.0);
349
350 // For now, return the interpolated trajectory
351 // A full implementation would use variational calculus or gradient descent
352 // on the action functional
353 return best_trajectory;
354}
355
356// ==============================================================================
357// Statistics
358// ==============================================================================
359
360FGTPEngine::Statistics FGTPEngine::get_statistics() const noexcept {
361 Statistics stats;
362 stats.total_computations = stat_total_computations_.load(std::memory_order_relaxed);
363 stats.total_driver_applications = stat_total_driver_apps_.load(std::memory_order_relaxed);
364 stats.total_violations = stat_total_violations_.load(std::memory_order_relaxed);
365 stats.max_energy_seen = stat_max_energy_.load(std::memory_order_relaxed);
366 stats.min_energy_seen = stat_min_energy_.load(std::memory_order_relaxed);
367
368 if (stats.total_computations > 0) {
369 stats.average_energy = stat_sum_energy_.load(std::memory_order_relaxed) / stats.total_computations;
370 stats.average_phi = stat_sum_phi_.load(std::memory_order_relaxed) / stats.total_computations;
371 } else {
372 stats.average_energy = 0.0;
373 stats.average_phi = 0.0;
374 }
375
376 if (stats.total_driver_applications > 0) {
377 stats.average_delta_energy = stat_sum_delta_energy_.load(std::memory_order_relaxed) / stats.total_driver_applications;
378 } else {
379 stats.average_delta_energy = 0.0;
380 }
381
382 return stats;
383}
384
385void FGTPEngine::reset_statistics() noexcept {
386 stat_total_computations_.store(0, std::memory_order_relaxed);
387 stat_total_driver_apps_.store(0, std::memory_order_relaxed);
388 stat_total_violations_.store(0, std::memory_order_relaxed);
389 stat_sum_energy_.store(0.0, std::memory_order_relaxed);
390 stat_sum_phi_.store(0.0, std::memory_order_relaxed);
391 stat_sum_delta_energy_.store(0.0, std::memory_order_relaxed);
392 stat_max_energy_.store(0.0, std::memory_order_relaxed);
393 stat_min_energy_.store(1e9, std::memory_order_relaxed);
394}
395
396// ==============================================================================
397// Helper Functions
398// ==============================================================================
399
400bool FGTPEngine::validate_bounds(const std::vector<double>& embedding) const noexcept {
401 // Check embedding norm
402 double norm = vector_norm(embedding.data(), embedding.size());
403 if (norm > config_.max_embedding_norm) {
404 return false;
405 }
406
407 // Check for NaN or Inf
408 for (double val : embedding) {
409 if (!std::isfinite(val)) {
410 return false;
411 }
412 }
413
414 return true;
415}
416
417void FGTPEngine::clip_gradient(double* gradient, size_t size) const noexcept {
418 double norm = vector_norm(gradient, size);
419 if (norm > config_.gradient_clip) {
420 double scale = config_.gradient_clip / norm;
421 for (size_t i = 0; i < size; ++i) {
422 gradient[i] *= scale;
423 }
424 }
425}
426
427double FGTPEngine::compute_kinetic_energy(const double* velocity, size_t size) const noexcept {
428 // T = (1/2) m v²
429 // Assume unit mass
430 double v_squared = 0.0;
431 for (size_t i = 0; i < size; ++i) {
432 v_squared += velocity[i] * velocity[i];
433 }
434 return 0.5 * v_squared;
435}
436
437double FGTPEngine::compute_potential_energy(const double* embedding, size_t size) const noexcept {
438 // Potential energy proportional to distance from unity (x=1)
439 // V = k × |x - 1|²
440 double sum_sq = 0.0;
441 for (size_t i = 0; i < size; ++i) {
442 double diff = embedding[i] - 1.0;
443 sum_sq += diff * diff;
444 }
445 return 0.5 * sum_sq / size; // Normalize by dimensionality
446}
447
448void FGTPEngine::update_statistics(const EnergyField& field, double delta_energy) const noexcept {
449 // Update running sums
450 stat_sum_energy_.fetch_add(field.energy, std::memory_order_relaxed);
451 stat_sum_phi_.fetch_add(field.phi, std::memory_order_relaxed);
452 stat_sum_delta_energy_.fetch_add(delta_energy, std::memory_order_relaxed);
453
454 // Update max/min (simple compare-and-swap loop)
455 double current_max = stat_max_energy_.load(std::memory_order_relaxed);
456 while (field.energy > current_max) {
457 if (stat_max_energy_.compare_exchange_weak(current_max, field.energy, std::memory_order_relaxed)) {
458 break;
459 }
460 }
461
462 double current_min = stat_min_energy_.load(std::memory_order_relaxed);
463 while (field.energy < current_min) {
464 if (stat_min_energy_.compare_exchange_weak(current_min, field.energy, std::memory_order_relaxed)) {
465 break;
466 }
467 }
468}
469
470} // namespace tired_agi
471