feat: scaffold FCES-native C++ project with libtorch integration

- CMakeLists.txt with libtorch, GoogleTest, GoogleBenchmark, OpenMP, pybind11
- Header files: config, controller, population, fitness, evolution, spectral, oscillation, telemetry, optimizer
- Source implementations: controller (full micro-MLP forward pass, mutation, crossover), fitness (Welford's algorithm), oscillation (DFT), spectral (SVD rank), optimizer (sign-SGD stub)
- Tests: controller, population, fitness, optimizer (Google Test)
- Benchmarks: evolve throughput, optimizer step (Google Benchmark)
- Examples: simple optimization, PyTorch/libtorch integration
- Python extension: pybind11 bindings with setup.py
- README with architecture diagram and build instructions
This commit is contained in:
AI-anonymous
2026-05-19 16:05:15 +02:00
commit 9bbe253810
32 changed files with 2182 additions and 0 deletions

174
src/controller.cpp Normal file
View File

@@ -0,0 +1,174 @@
#include "fces/controller.hpp"
#include <algorithm>
#include <cmath>
#include <numeric>
namespace fces {
// Static members
std::atomic<uint64_t> FuzzyController::next_id_{0};
thread_local std::mt19937 FuzzyController::rng_{std::random_device{}()};
// ---------------------------------------------------------------
// Genome
// ---------------------------------------------------------------
void Genome::randomize(std::mt19937& rng) {
std::normal_distribution<float> dist(0.0f, 0.5f);
for (auto& w : weights) {
w = dist(rng);
}
gene_success.fill(0.0f);
}
Genome Genome::clone() const {
return *this; // Copy all fields
}
// ---------------------------------------------------------------
// FuzzyController
// ---------------------------------------------------------------
FuzzyController::FuzzyController()
: id(next_id_++), origin("random") {
genome.randomize(rng_);
// Bias output toward acceleration (V2.1 insight)
// Set output biases (last GENOME_OUTPUT_DIM elements) to +2.0
constexpr int bias_start = GENOME_SIZE - GENOME_OUTPUT_DIM;
for (int i = bias_start; i < GENOME_SIZE; ++i) {
genome.weights[i] = 2.0f;
}
}
FuzzyController::FuzzyController(Genome genome)
: id(next_id_++), genome(std::move(genome)), origin("constructed") {}
torch::Tensor FuzzyController::decide_update(
const std::vector<std::vector<float>>& layer_stats,
float loss_trend,
float step_pct,
float rollback_rate,
float grad_stability,
float spectral_alpha,
float stagnation_intensity,
float kzm_damping,
float projected_drift
) {
const int num_groups = static_cast<int>(layer_stats.size());
auto actions = torch::zeros({num_groups, GENOME_OUTPUT_DIM});
// Extract weight views for the micro-MLP
const float* w = genome.weights.data();
// Layer 1: input -> hidden
const float* W1 = w; // [GENOME_INPUT_DIM x GENOME_HIDDEN_DIM]
const float* b1 = w + (GENOME_INPUT_DIM * GENOME_HIDDEN_DIM); // [GENOME_HIDDEN_DIM]
// Layer 2: hidden -> output
const float* W2 = b1 + GENOME_HIDDEN_DIM; // [GENOME_HIDDEN_DIM x GENOME_OUTPUT_DIM]
const float* b2 = W2 + (GENOME_HIDDEN_DIM * GENOME_OUTPUT_DIM); // [GENOME_OUTPUT_DIM]
for (int g = 0; g < num_groups; ++g) {
// Build input vector
std::array<float, GENOME_INPUT_DIM> input{};
if (!layer_stats[g].empty()) {
// Copy available stats, pad with context
const int n = std::min(static_cast<int>(layer_stats[g].size()), GENOME_INPUT_DIM - 4);
for (int i = 0; i < n; ++i) {
input[i] = layer_stats[g][i];
}
}
// Append global context
input[GENOME_INPUT_DIM - 4] = loss_trend;
input[GENOME_INPUT_DIM - 3] = step_pct;
input[GENOME_INPUT_DIM - 2] = grad_stability;
input[GENOME_INPUT_DIM - 1] = stagnation_intensity;
// Forward pass: hidden = tanh(W1 * input + b1)
std::array<float, GENOME_HIDDEN_DIM> hidden{};
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
float sum = b1[h];
for (int i = 0; i < GENOME_INPUT_DIM; ++i) {
sum += W1[h * GENOME_INPUT_DIM + i] * input[i];
}
hidden[h] = std::tanh(sum);
}
// Output = W2 * hidden + b2
for (int o = 0; o < GENOME_OUTPUT_DIM; ++o) {
float sum = b2[o];
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
sum += W2[o * GENOME_HIDDEN_DIM + h] * hidden[h];
}
actions[g][o] = sum;
}
}
return actions;
}
FuzzyController FuzzyController::mutate(float current_loss, float sigma_scale) const {
Genome child_genome = genome.clone();
std::normal_distribution<float> noise(0.0f, genome.sigma_gene * sigma_scale);
for (size_t i = 0; i < child_genome.weights.size(); ++i) {
child_genome.weights[i] += noise(rng_);
}
FuzzyController child(child_genome);
child.origin = "mutation";
return child;
}
FuzzyController FuzzyController::crossover(const FuzzyController& partner, bool use_alignment) const {
Genome child_genome;
std::uniform_real_distribution<float> coin(0.0f, 1.0f);
for (size_t i = 0; i < child_genome.weights.size(); ++i) {
if (use_alignment && genome.gene_success[i] > partner.genome.gene_success[i]) {
child_genome.weights[i] = genome.weights[i];
} else if (use_alignment && partner.genome.gene_success[i] > genome.gene_success[i]) {
child_genome.weights[i] = partner.genome.weights[i];
} else {
// Uniform crossover
child_genome.weights[i] = (coin(rng_) < 0.5f)
? genome.weights[i]
: partner.genome.weights[i];
}
child_genome.gene_success[i] = 0.0f;
}
FuzzyController child(child_genome);
child.origin = "crossover";
return child;
}
FuzzyController FuzzyController::create_orthogonal_child(float intensity) const {
Genome child_genome = genome.clone();
// Negate a random subset of weights
std::uniform_real_distribution<float> coin(0.0f, 1.0f);
for (size_t i = 0; i < child_genome.weights.size(); ++i) {
if (coin(rng_) < 0.3f * intensity) {
child_genome.weights[i] = -child_genome.weights[i];
}
}
FuzzyController child(child_genome);
child.origin = "phoenix_rebirth";
return child;
}
std::pair<FuzzyController, FuzzyController> FuzzyController::banach_tarski_fission(float intensity) const {
Genome plus_genome = genome.clone();
Genome minus_genome = genome.clone();
std::normal_distribution<float> noise(0.0f, 0.1f * intensity);
for (size_t i = 0; i < genome.weights.size(); ++i) {
float delta = noise(rng_);
plus_genome.weights[i] += delta;
minus_genome.weights[i] -= delta;
}
return {FuzzyController(plus_genome), FuzzyController(minus_genome)};
}
} // namespace fces