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

82
include/fces/config.hpp Normal file
View File

@@ -0,0 +1,82 @@
#pragma once
/**
* @file config.hpp
* @brief FCES Configuration — compile-time defaults and runtime overrides.
*
* Maps directly from Python's FCESConfig (Pydantic model) to a C++ struct
* with constexpr defaults and builder-pattern construction.
*/
#include <cstdint>
#include <string>
namespace fces {
/**
* Core configuration for the FCES optimizer.
* All fields have sensible defaults matching the Python V49.0 implementation.
*/
struct FCESConfig {
// Learning rate (V49 optimal default)
float lr = 1.6e-3f;
// Weight decay coefficient
float weight_decay = 0.0f;
// Population size for evolutionary search
int population_size = 200;
// Total training steps (for progress-aware scheduling)
int total_steps = 5000;
// Signal mode for loss velocity calculation
std::string signal_mode = "relative";
// Grokking awareness coefficient (0.0 = disabled)
float grokking_coefficient = 0.1f;
// Spectral sensing frequency (every N steps)
int spectral_frequency = 10;
// Curriculum Spectral Regularization
bool csr_enabled = false;
int csr_warmup_steps = 500;
int csr_ramp_steps = 1000;
// Trust region clipping
float trust_region_clip = 0.01f;
// Rollback threshold
float rollback_threshold = 1.5f;
// Adaptive weight decay
bool adaptive_wd = false;
// Parasitic mode (gradient alignment reward)
bool parasitic_mode = false;
// Ablation mode: "", "force_sign", "force_grad"
std::string ablation_mode = "";
// Fractional factorial scoring (CRO trick)
bool use_fractional_scoring = false;
// Direct construction mode (pop_size=1)
bool direct_construction = false;
// Banach-Tarski fission
bool use_banach_fission = false;
// Auto-population (stabilize on divergence)
bool auto_population = false;
// Builder pattern
FCESConfig& set_lr(float v) { lr = v; return *this; }
FCESConfig& set_population_size(int v) { population_size = v; return *this; }
FCESConfig& set_total_steps(int v) { total_steps = v; return *this; }
FCESConfig& set_grokking_coefficient(float v) { grokking_coefficient = v; return *this; }
FCESConfig& set_direct_construction(bool v) { direct_construction = v; return *this; }
};
} // namespace fces

145
include/fces/controller.hpp Normal file
View File

@@ -0,0 +1,145 @@
#pragma once
/**
* @file controller.hpp
* @brief FuzzyController and Genome — the decision-making units of FCES.
*
* Each controller contains a Genome (neural network weights) that maps
* layer statistics to update decisions (multiplier, sign_gate, wd_mult).
*
* Port of: packages/fces/core/controller.py
*/
#include <array>
#include <cstdint>
#include <memory>
#include <random>
#include <string>
#include <vector>
#include <torch/torch.h>
namespace fces {
// Controller input dimension (layer stats features)
constexpr int GENOME_INPUT_DIM = 9;
// Controller hidden dimension
constexpr int GENOME_HIDDEN_DIM = 16;
// Controller output dimension: [multiplier, sign_gate, wd_mult]
constexpr int GENOME_OUTPUT_DIM = 3;
// Total genome size: input->hidden weights + hidden biases + hidden->output weights + output biases
constexpr int GENOME_SIZE =
(GENOME_INPUT_DIM * GENOME_HIDDEN_DIM) + // input -> hidden weights
GENOME_HIDDEN_DIM + // hidden biases
(GENOME_HIDDEN_DIM * GENOME_OUTPUT_DIM) + // hidden -> output weights
GENOME_OUTPUT_DIM; // output biases
/**
* Genome — the "DNA" of a fuzzy controller.
* A flat array of floats encoding a micro-MLP.
*/
struct Genome {
std::array<float, GENOME_SIZE> weights{};
std::array<float, GENOME_SIZE> gene_success{};
float sigma_gene = 0.1f;
float plasticity = 1.0f;
/// Initialize with random weights from a normal distribution
void randomize(std::mt19937& rng);
/// Deep copy
Genome clone() const;
};
/**
* FuzzyController — a single agent in the evolutionary population.
*
* Lifecycle:
* 1. Created via random initialization or crossover/mutation
* 2. Activated for `selection_interval` steps
* 3. Evaluated based on loss improvement during its tenure
* 4. Evolved (crossover/mutation) or culled based on fitness
*/
class FuzzyController {
public:
/// Unique identifier
uint64_t id;
/// The neural genome
Genome genome;
/// Fitness scores
float fitness = 0.0f;
float lifetime_fitness = 0.0f;
float ema_fitness = 0.0f;
int evaluation_count = 0;
int age = 0;
/// Origin tracking
std::string origin = "random";
/// Trust region violation counter
int trust_violations = 0;
/// Rolling fitness history (for Phase 23 strategies)
std::vector<float> fitness_history;
// ---------------------------------------------------------------
// Construction
// ---------------------------------------------------------------
FuzzyController();
explicit FuzzyController(Genome genome);
// ---------------------------------------------------------------
// Core Operations
// ---------------------------------------------------------------
/**
* Forward pass through the micro-MLP to produce update decisions.
*
* @param layer_stats Vector of per-layer feature maps
* @param loss_trend Current loss velocity
* @param step_pct Training progress [0, 1]
* @param rollback_rate Rolling average rollback frequency
* @param grad_stability Gradient coefficient of variation
* @param spectral_alpha Log spectral rank
* @param stagnation_intensity Stagnation counter / 500
* @param kzm_damping Kibble-Zurek damping factor
* @param projected_drift Projected loss drift
* @return Tensor of shape [num_groups, 3] — (mult, sign_gate, wd_mult)
*/
torch::Tensor 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
);
// ---------------------------------------------------------------
// Evolutionary Operators
// ---------------------------------------------------------------
/// Create a mutated child
FuzzyController mutate(float current_loss, float sigma_scale = 1.0f) const;
/// Crossover with another controller
FuzzyController crossover(const FuzzyController& partner, bool use_alignment = true) const;
/// Create an orthogonal counter-strategy (Phoenix Rebirth)
FuzzyController create_orthogonal_child(float intensity = 1.0f) const;
/// Banach-Tarski fission: split into two complementary children
std::pair<FuzzyController, FuzzyController> banach_tarski_fission(float intensity = 1.0f) const;
private:
static std::atomic<uint64_t> next_id_;
static thread_local std::mt19937 rng_;
};
} // namespace fces

View File

@@ -0,0 +1,54 @@
#pragma once
/**
* @file evolution.hpp
* @brief EvolutionManager — orchestrates population dynamics.
*
* Port of: packages/fces/core/evolution_manager.py
*/
#include "population.hpp"
namespace fces {
/**
* EvolutionManager — controls the scheduling of evolutionary operations.
*
* Responsibilities:
* - Controller rotation (sticky selection with interval)
* - Population dynamics (auto-sizing, lockdown)
* - Triggering evolution at intervals
*/
class EvolutionManager {
public:
explicit EvolutionManager(
Population& population,
int selection_interval = 50,
bool auto_population = false,
bool direct_construction = false
);
/// Get the currently active controller
FuzzyController& get_active_controller();
/// Update population dynamics based on current training state
void update_population_dynamics(
float loss_velocity,
float ema_loss,
int step_counter,
int total_steps
);
/// Steps the active controller has been in control
int steps_active = 0;
/// Selection interval (how long a controller stays active)
int selection_interval;
private:
Population& population_;
bool auto_population_;
bool direct_construction_;
};
} // namespace fces

90
include/fces/fitness.hpp Normal file
View File

@@ -0,0 +1,90 @@
#pragma once
/**
* @file fitness.hpp
* @brief Fitness evaluation — loss signal processing and multi-objective evaluation.
*
* Port of: packages/fces/core/fitness_engine.py + fitness.py
*/
#include <cmath>
#include <vector>
namespace fces {
/**
* Running statistics tracker (Welford's algorithm).
* Thread-safe, O(1) memory, numerically stable.
*/
class RunningStats {
public:
void update(float value);
float z_score(float value) const;
float get_mean() const { return mean_; }
float get_std() const;
int get_count() const { return count_; }
void reset();
private:
int count_ = 0;
float mean_ = 0.0f;
float m2_ = 0.0f;
};
/**
* FitnessEngine — processes raw loss values into controller fitness signals.
*/
class FitnessEngine {
public:
explicit FitnessEngine(float grokking_coefficient = 0.1f);
/**
* Calculate loss velocity signal.
*
* @param current_loss Current step loss
* @param ema_loss Exponential moving average loss
* @param mode "relative" or "absolute"
* @return Velocity signal (negative = improving)
*/
float calculate_loss_signal(float current_loss, float ema_loss, const std::string& mode = "relative") const;
/**
* Compute Kibble-Zurek Mechanism damping factor.
* Prevents topological defects during phase transitions.
*/
float compute_kzm_damping(float spectral_alpha) const;
private:
float grokking_coefficient_;
};
/**
* Fitness metrics for multi-objective evaluation.
*/
struct FitnessMetrics {
float loss_improvement = 0.0f;
float sparsity_score = 0.0f;
float stability_score = 0.0f;
float novelty_score = 0.0f;
/// Weighted combination
float total(float alpha = 0.7f, float beta = 0.3f) const {
return alpha * loss_improvement + beta * sparsity_score;
}
};
/**
* FuzzyFitnessEvaluator — multi-objective fitness evaluation with fuzzy weighting.
*/
class FuzzyFitnessEvaluator {
public:
FitnessMetrics evaluate(
float loss_before,
float loss_after,
float sparsity = 0.0f,
float val_loss = -1.0f
) const;
};
} // namespace fces

View File

@@ -0,0 +1,87 @@
#pragma once
/**
* @file optimizer.hpp
* @brief FCESOptimizer — the main entry point. libtorch-compatible optimizer.
*/
#include <torch/torch.h>
#include <memory>
#include <vector>
#include <string>
#include "config.hpp"
#include "population.hpp"
#include "fitness.hpp"
#include "evolution.hpp"
#include "spectral.hpp"
#include "oscillation.hpp"
#include "telemetry.hpp"
namespace fces {
/**
* FCESOptimizer — Fuzzy Controlled Evolutionary Search V49.0 (C++ Port).
*
* Usage:
* auto optimizer = FCESOptimizer(model->parameters(), FCESConfig{}.set_lr(1.6e-3));
* // In training loop:
* optimizer.zero_grad();
* auto loss = model->forward(input);
* loss.backward();
* optimizer.step();
* optimizer.update_fitness(loss.item<float>());
*/
class FCESOptimizer : public torch::optim::Optimizer {
public:
explicit FCESOptimizer(
std::vector<torch::Tensor> params,
FCESConfig config = FCESConfig{}
);
/// Perform a single optimization step
torch::Tensor step(LossClosure closure = nullptr) override;
/// Update evolutionary fitness with current loss
void update_fitness(float loss);
/// Backup model weights to CPU RAM
void backup_to_ram();
/// Restore model weights from CPU RAM backup
void restore_from_ram();
/// Get current step count
int step_count() const { return step_counter_; }
/// Calculate model sparsity
float calculate_sparsity() const;
private:
FCESConfig config_;
Population population_;
FitnessEngine fitness_engine_;
FuzzyFitnessEvaluator fitness_evaluator_;
std::unique_ptr<EvolutionManager> evolution_manager_;
OscillationDetector oscillation_detector_;
RunningStats grad_norm_tracker_;
// State
int step_counter_ = 0;
float ema_loss_ = 0.0f;
float last_step_loss_ = 0.0f;
float best_loss_window_ = std::numeric_limits<float>::infinity();
float rollback_ema_ = 0.0f;
int stagnation_counter_ = 0;
float last_loss_velocity_ = 0.0f;
// RAM backup
std::vector<torch::Tensor> ram_backup_;
// Internal methods
void gather_stats();
void apply_parameter_updates(const torch::Tensor& actions);
void handle_rollback();
};
} // namespace fces

View File

@@ -0,0 +1,29 @@
#pragma once
/**
* @file oscillation.hpp
* @brief FFT-based oscillation detection (Phase 25).
*/
#include <vector>
namespace fces {
class OscillationDetector {
public:
static constexpr int WINDOW_SIZE = 64;
static constexpr float POWER_THRESHOLD = 0.5f;
void update(float loss);
bool detect() const;
float get_score() const;
float get_variance_50() const;
void reset();
private:
std::vector<float> loss_history_;
static std::vector<float> detrend(const std::vector<float>& signal);
static std::vector<float> compute_power_spectrum(const std::vector<float>& signal);
};
} // namespace fces

165
include/fces/population.hpp Normal file
View File

@@ -0,0 +1,165 @@
#pragma once
/**
* @file population.hpp
* @brief Population management — the evolutionary ecosystem.
*
* Manages a population of FuzzyControllers with:
* - Elitism (protected top-N)
* - Tournament selection with age weighting
* - Crossover, mutation, and Phoenix rebirth
* - Island migration (optional)
* - Novelty search (optional)
* - Phase 23 stale elite mitigation strategies
* - Phase 24 violator synchronization
*
* Port of: packages/fces/core/population.py (~1260 LOC)
*/
#include <string>
#include <vector>
#include <optional>
#include "controller.hpp"
namespace fces {
/**
* Elite selection strategy for stale elite mitigation (Phase 23).
*/
enum class EliteStrategy {
Cumulative, // Raw cumulative fitness
EMA, // Exponential moving average
Rolling, // Rolling window average
Reset, // Periodic reset every 500 steps
AgePenalty // fitness / log(age + 2)
};
/**
* Population — manages the ecosystem of FuzzyControllers.
*/
class Population {
public:
// Configuration constants
static constexpr int ELITE_COUNT = 2;
static constexpr float NOVELTY_WEIGHT = 0.1f;
static constexpr float ISLAND_MIGRATION_RATE = 0.05f;
static constexpr int BEHAVIORAL_ARCHIVE_SIZE = 100;
// ---------------------------------------------------------------
// Construction
// ---------------------------------------------------------------
explicit Population(
int active_size = 75,
int repo_size = 10000,
EliteStrategy elite_strategy = EliteStrategy::Cumulative,
bool link_mutation = false,
bool link_elite = false,
bool link_violator = false,
bool use_fuzzy_pacer = false,
bool use_fuzzy_importance = false,
bool direct_construction = false,
bool use_banach_fission = false
);
// ---------------------------------------------------------------
// Core API
// ---------------------------------------------------------------
/// Get the currently active controller (sticky selection)
FuzzyController& get_active_controller();
/// Select a controller via fitness-weighted tournament
FuzzyController& select_weighted();
/// Get the best controller in the active population
FuzzyController& get_best_active();
/// Get the worst non-elite controller
FuzzyController& get_worst_active();
/// Remove a specific controller (unless elite)
void kill(FuzzyController& controller);
/// Update a controller's fitness
void update_controller_fitness(FuzzyController& controller, float reward, bool increment_eval = true);
/// Mark a controller as a violator (rollback)
void mark_violated(FuzzyController& controller);
/// Get the effective fitness considering elite strategy and training progress
float get_effective_fitness(const FuzzyController& controller, float training_progress) const;
// ---------------------------------------------------------------
// Evolution
// ---------------------------------------------------------------
/**
* Evolve the population: select parents, crossover/mutate, replace worst.
*
* @param current_loss Current training loss
* @param velocity Loss velocity
* @param training_progress Training progress [0, 1]
*/
void evolve(float current_loss, float velocity = 0.0f, float training_progress = 0.0f);
/// Resize the population (dynamic expansion/contraction)
void resize(int target_size, float training_progress = 0.5f);
/// Reduce mutation variance after rollback
void calm_down();
// ---------------------------------------------------------------
// Accessors
// ---------------------------------------------------------------
int size() const { return static_cast<int>(gladiators_.size()); }
float global_sigma_modifier() const { return global_sigma_modifier_; }
/// Compute diversity index (behavioral spread)
float get_diversity_index() const;
/// Serialization
// TODO: state_dict / load_state_dict
private:
std::vector<FuzzyController> gladiators_;
std::vector<FuzzyController> repository_;
std::vector<FuzzyController> violated_controllers_;
float global_sigma_modifier_ = 1.0f;
// Sticky controller selection
FuzzyController* active_controller_ = nullptr;
int steps_active_ = 0;
int selection_interval_ = 20;
// Configuration
EliteStrategy elite_strategy_;
bool link_mutation_;
bool link_elite_;
bool link_violator_;
bool use_fuzzy_pacer_;
bool use_fuzzy_importance_;
bool direct_construction_;
bool use_banach_fission_;
// Novelty search
std::vector<std::vector<float>> behavioral_archive_;
// Fitness history for fuzzy pacer
std::vector<float> fitness_history_;
// Phase 23: periodic reset counter
int reset_step_counter_ = 0;
// ---------------------------------------------------------------
// Internal
// ---------------------------------------------------------------
std::vector<FuzzyController*> get_elites();
void add_to_repository(const FuzzyController& controller);
};
} // namespace fces

53
include/fces/spectral.hpp Normal file
View File

@@ -0,0 +1,53 @@
#pragma once
/**
* @file spectral.hpp
* @brief Spectral Sensor and Controller — grokking awareness via rank tracking.
*
* Port of: packages/fces/core/spectral_sensor.py + spectral_controller.py
*/
#include <string>
#include <unordered_map>
#include <vector>
#include <torch/torch.h>
namespace fces {
/**
* SpectralSensor — tracks the effective rank of weight matrices.
*
* Used for grokking detection: when the model transitions from
* memorization to generalization, the effective rank drops.
*/
class SpectralSensor {
public:
explicit SpectralSensor(torch::nn::Module& model);
/// Track a layer's weight tensor
void track_layer(const std::string& name, const torch::Tensor& weight);
/// Get the global (average) effective rank
float get_global_rank() const;
/// Reset all tracked layers
void reset();
private:
std::unordered_map<std::string, float> layer_ranks_;
/// Compute effective rank via SVD
static float compute_effective_rank(const torch::Tensor& weight);
};
/**
* SpectralController — converts spectral rank into optimizer decisions.
*/
class SpectralController {
public:
/// Compute the spectral alpha (gating factor for rank-aware updates)
float compute_alpha(float global_rank, float grokking_coefficient) const;
};
} // namespace fces

View File

@@ -0,0 +1,26 @@
#pragma once
/**
* @file telemetry.hpp
* @brief Structured logging and telemetry for FCES.
*/
#include <string>
namespace fces {
class Telemetry {
public:
static Telemetry& get();
void info(const std::string& event, const std::string& detail = "");
void warning(const std::string& event, const std::string& detail = "");
void error(const std::string& event, const std::string& detail = "");
void push_to_remote();
private:
Telemetry() = default;
};
} // namespace fces