style: run clang-format and configure pre-commit hooks

This commit is contained in:
AI-anonymous
2026-05-20 00:18:23 +02:00
parent 041eab7155
commit 3b15770437
28 changed files with 2226 additions and 2061 deletions

51
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,51 @@
# Pre-commit configuration for FCES-native
repos:
# 1. Standard hooks for general file cleanliness
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
# 2. C++ Formatting using clang-format (fetched dynamically)
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.5
hooks:
- id: clang-format
types_or: [c++, c]
# 3. C++ Static Analysis using local cppcheck
- repo: local
hooks:
- id: cppcheck
name: cppcheck
entry: cppcheck
language: system
types_or: [c++, c]
args: [
"--enable=warning,portability",
"--suppress=missingIncludeSystem",
"--suppress=unusedFunction",
"--suppress=normalCheckLevelMaxBranches",
"--inline-suppr",
"--error-exitcode=1",
"-Iinclude"
]
# 4. Python Linter and Formatter (ruff)
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
args: [ --fix ]
- id: ruff-format
# 5. Python Type Checking (mypy)
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
args: [ "--ignore-missing-imports", "--strict" ]
additional_dependencies: [ "types-requests", "pydantic" ]

View File

@@ -1,15 +1,17 @@
#include <benchmark/benchmark.h>
#include "fces/population.hpp"
#include "fces/controller.hpp" #include "fces/controller.hpp"
#include "fces/population.hpp"
#include <benchmark/benchmark.h>
using namespace fces; using namespace fces;
static void BM_ControllerDecideUpdate(benchmark::State &state) { static void BM_ControllerDecideUpdate(benchmark::State &state) {
FuzzyController ctrl; FuzzyController ctrl;
std::vector<std::vector<float>> stats(state.range(0), {0.1f, 0.2f, 0.3f, 0.4f, 0.5f}); std::vector<std::vector<float>> stats(state.range(0),
{0.1f, 0.2f, 0.3f, 0.4f, 0.5f});
for (auto _ : state) { for (auto _ : state) {
auto actions = ctrl.decide_update(stats, 0.0f, 0.5f, 0.0f, 0.1f, 0.0f, 0.0f, 1.0f, 0.0f); auto actions = ctrl.decide_update(stats, 0.0f, 0.5f, 0.0f, 0.1f, 0.0f, 0.0f,
1.0f, 0.0f);
benchmark::DoNotOptimize(actions); benchmark::DoNotOptimize(actions);
} }
} }

View File

@@ -1,13 +1,14 @@
#include "fces/optimizer.hpp"
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
#include <torch/torch.h> #include <torch/torch.h>
#include "fces/optimizer.hpp"
using namespace fces; using namespace fces;
static void BM_OptimizerStep(benchmark::State &state) { static void BM_OptimizerStep(benchmark::State &state) {
auto model = torch::nn::Linear(state.range(0), state.range(0) / 2); auto model = torch::nn::Linear(state.range(0), state.range(0) / 2);
std::vector<torch::Tensor> params; std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p); for (auto &p : model->parameters())
params.push_back(p);
FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f)); FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f));

View File

@@ -3,9 +3,9 @@
* @brief Example: train a small neural network with FCES via libtorch. * @brief Example: train a small neural network with FCES via libtorch.
*/ */
#include "fces/optimizer.hpp"
#include <iostream> #include <iostream>
#include <torch/torch.h> #include <torch/torch.h>
#include "fces/optimizer.hpp"
struct TinyNet : torch::nn::Module { struct TinyNet : torch::nn::Module {
torch::nn::Linear fc1{nullptr}, fc2{nullptr}; torch::nn::Linear fc1{nullptr}, fc2{nullptr};
@@ -25,15 +25,13 @@ int main() {
auto model = std::make_shared<TinyNet>(); auto model = std::make_shared<TinyNet>();
std::vector<torch::Tensor> params; std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p); for (auto &p : model->parameters())
params.push_back(p);
fces::FCESOptimizer optimizer( fces::FCESOptimizer optimizer(params, fces::FCESConfig{}
params,
fces::FCESConfig{}
.set_lr(1.6e-3f) .set_lr(1.6e-3f)
.set_population_size(200) .set_population_size(200)
.set_total_steps(1000) .set_total_steps(1000));
);
// Generate synthetic regression data // Generate synthetic regression data
auto x_train = torch::randn({100, 10}); auto x_train = torch::randn({100, 10});
@@ -48,8 +46,8 @@ int main() {
optimizer.update_fitness(loss.item<float>()); optimizer.update_fitness(loss.item<float>());
if (epoch % 10 == 0) { if (epoch % 10 == 0) {
std::cout << "Epoch " << epoch std::cout << "Epoch " << epoch << " | Loss: " << loss.item<float>()
<< " | Loss: " << loss.item<float>() << std::endl; << std::endl;
} }
} }

View File

@@ -3,9 +3,9 @@
* @brief Minimal example: optimize a quadratic function with FCES. * @brief Minimal example: optimize a quadratic function with FCES.
*/ */
#include "fces/optimizer.hpp"
#include <iostream> #include <iostream>
#include <torch/torch.h> #include <torch/torch.h>
#include "fces/optimizer.hpp"
int main() { int main() {
// Target: minimize f(x) = ||x - target||^2 // Target: minimize f(x) = ||x - target||^2
@@ -23,8 +23,7 @@ int main() {
optimizer.update_fitness(loss.item<float>()); optimizer.update_fitness(loss.item<float>());
if (step % 50 == 0) { if (step % 50 == 0) {
std::cout << "Step " << step std::cout << "Step " << step << " | Loss: " << loss.item<float>()
<< " | Loss: " << loss.item<float>()
<< " | x: " << x << std::endl; << " | x: " << x << std::endl;
} }
} }

View File

@@ -3,11 +3,11 @@
* @brief Example showcasing telemetry instrumentation and model inference. * @brief Example showcasing telemetry instrumentation and model inference.
*/ */
#include <iostream>
#include <chrono>
#include <torch/torch.h>
#include "fces/optimizer.hpp" #include "fces/optimizer.hpp"
#include "fces/telemetry.hpp" #include "fces/telemetry.hpp"
#include <chrono>
#include <iostream>
#include <torch/torch.h>
// Define a simple neural network for nonlinear regression: y = x^2 // Define a simple neural network for nonlinear regression: y = x^2
struct RegressionNet : torch::nn::Module { struct RegressionNet : torch::nn::Module {
@@ -25,7 +25,8 @@ struct RegressionNet : torch::nn::Module {
}; };
int main() { int main() {
fces::Telemetry::get().info("app_start", "Telemetry and Inference demo initialized."); fces::Telemetry::get().info("app_start",
"Telemetry and Inference demo initialized.");
// 1. Create Model and Data // 1. Create Model and Data
auto model = std::make_shared<RegressionNet>(); auto model = std::make_shared<RegressionNet>();
@@ -42,13 +43,11 @@ int main() {
fces::FCESOptimizer optimizer( fces::FCESOptimizer optimizer(
params, params,
fces::FCESConfig{} fces::FCESConfig{}.set_lr(2e-3f).set_population_size(150).set_total_steps(
.set_lr(2e-3f) 100));
.set_population_size(150)
.set_total_steps(100)
);
fces::Telemetry::get().info("training_start", "Beginning neural net optimization with FCES."); fces::Telemetry::get().info("training_start",
"Beginning neural net optimization with FCES.");
auto start_train = std::chrono::high_resolution_clock::now(); auto start_train = std::chrono::high_resolution_clock::now();
@@ -62,19 +61,24 @@ int main() {
optimizer.update_fitness(loss.item<float>()); optimizer.update_fitness(loss.item<float>());
if (epoch % 20 == 0) { if (epoch % 20 == 0) {
fces::Telemetry::get().info("epoch_checkpoint", fces::Telemetry::get().info(
"Epoch " + std::to_string(epoch) + " | Loss: " + std::to_string(loss.item<float>())); "epoch_checkpoint", "Epoch " + std::to_string(epoch) + " | Loss: " +
std::to_string(loss.item<float>()));
} }
} }
auto end_train = std::chrono::high_resolution_clock::now(); auto end_train = std::chrono::high_resolution_clock::now();
double train_duration = std::chrono::duration<double, std::milli>(end_train - start_train).count(); double train_duration =
std::chrono::duration<double, std::milli>(end_train - start_train)
.count();
fces::Telemetry::get().info("training_complete", fces::Telemetry::get().info("training_complete",
"Duration: " + std::to_string(train_duration) + " ms"); "Duration: " + std::to_string(train_duration) +
" ms");
// 4. Inference Phase // 4. Inference Phase
fces::Telemetry::get().info("inference_phase_start", "Evaluating model on new test inputs."); fces::Telemetry::get().info("inference_phase_start",
"Evaluating model on new test inputs.");
// Generate test inputs // Generate test inputs
auto x_test = torch::tensor({-1.5f, -0.5f, 0.0f, 0.5f, 1.5f}).unsqueeze(1); auto x_test = torch::tensor({-1.5f, -0.5f, 0.0f, 0.5f, 1.5f}).unsqueeze(1);
@@ -91,23 +95,31 @@ int main() {
y_pred = model->forward(x_test); y_pred = model->forward(x_test);
} }
auto end_inf = std::chrono::high_resolution_clock::now(); auto end_inf = std::chrono::high_resolution_clock::now();
double inf_duration = std::chrono::duration<double, std::milli>(end_inf - start_inf).count(); double inf_duration =
std::chrono::duration<double, std::milli>(end_inf - start_inf).count();
// Log telemetry for inference performance // Log telemetry for inference performance
fces::Telemetry::get().info("inference_perf", fces::Telemetry::get().info(
"Inputs: " + std::to_string(x_test.size(0)) + " | Latency: " + std::to_string(inf_duration) + " ms"); "inference_perf", "Inputs: " + std::to_string(x_test.size(0)) +
" | Latency: " + std::to_string(inf_duration) +
" ms");
// Print predictions and expected values side-by-side // Print predictions and expected values side-by-side
std::cout << "\n================ INFERENCE RESULTS ================" << std::endl; std::cout << "\n================ INFERENCE RESULTS ================"
std::cout << "Input (x) | Predicted (y_pred) | Expected (y_expected)" << std::endl; << std::endl;
std::cout << "----------------------------------------------------" << std::endl; std::cout << "Input (x) | Predicted (y_pred) | Expected (y_expected)"
<< std::endl;
std::cout << "----------------------------------------------------"
<< std::endl;
for (int i = 0; i < x_test.size(0); ++i) { for (int i = 0; i < x_test.size(0); ++i) {
float x_val = x_test[i][0].item<float>(); float x_val = x_test[i][0].item<float>();
float pred_val = y_pred[i][0].item<float>(); float pred_val = y_pred[i][0].item<float>();
float exp_val = y_expected[i][0].item<float>(); float exp_val = y_expected[i][0].item<float>();
std::printf(" %7.2f | %7.4f | %7.4f\n", x_val, pred_val, exp_val); std::printf(" %7.2f | %7.4f | %7.4f\n", x_val,
pred_val, exp_val);
} }
std::cout << "====================================================\n" << std::endl; std::cout << "====================================================\n"
<< std::endl;
fces::Telemetry::get().info("app_finish", "Exiting demo successfully."); fces::Telemetry::get().info("app_finish", "Exiting demo successfully.");
return 0; return 0;

View File

@@ -72,11 +72,26 @@ struct FCESConfig {
bool auto_population = false; bool auto_population = false;
// Builder pattern // Builder pattern
FCESConfig& set_lr(float v) { lr = v; return *this; } FCESConfig &set_lr(float v) {
FCESConfig& set_population_size(int v) { population_size = v; return *this; } lr = v;
FCESConfig& set_total_steps(int v) { total_steps = v; return *this; } return *this;
FCESConfig& set_grokking_coefficient(float v) { grokking_coefficient = v; return *this; } }
FCESConfig& set_direct_construction(bool v) { direct_construction = 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 } // namespace fces

View File

@@ -27,7 +27,8 @@ constexpr int GENOME_INPUT_DIM = 14;
constexpr int GENOME_HIDDEN_DIM = 8; constexpr int GENOME_HIDDEN_DIM = 8;
// Controller output dimension: [multiplier, sign_gate, wd_mult] // Controller output dimension: [multiplier, sign_gate, wd_mult]
constexpr int GENOME_OUTPUT_DIM = 3; constexpr int GENOME_OUTPUT_DIM = 3;
// Total genome size: input->hidden weights + hidden biases + hidden->output weights + output biases // Total genome size: input->hidden weights + hidden biases + hidden->output
// weights + output biases
constexpr int GENOME_SIZE = constexpr int GENOME_SIZE =
(GENOME_INPUT_DIM * GENOME_HIDDEN_DIM) + // input -> hidden weights (GENOME_INPUT_DIM * GENOME_HIDDEN_DIM) + // input -> hidden weights
GENOME_HIDDEN_DIM + // hidden biases GENOME_HIDDEN_DIM + // hidden biases
@@ -109,17 +110,12 @@ public:
* @param projected_drift Projected loss drift * @param projected_drift Projected loss drift
* @return Tensor of shape [num_groups, 3] — (mult, sign_gate, wd_mult) * @return Tensor of shape [num_groups, 3] — (mult, sign_gate, wd_mult)
*/ */
torch::Tensor decide_update( torch::Tensor
const std::vector<std::vector<float>>& layer_stats, decide_update(const std::vector<std::vector<float>> &layer_stats,
float loss_trend, float loss_trend, float step_pct, float rollback_rate,
float step_pct, float grad_stability, float spectral_alpha,
float rollback_rate, float stagnation_intensity, float kzm_damping,
float grad_stability, float projected_drift);
float spectral_alpha,
float stagnation_intensity,
float kzm_damping,
float projected_drift
);
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Evolutionary Operators // Evolutionary Operators
@@ -129,13 +125,15 @@ public:
FuzzyController mutate(float current_loss, float sigma_scale = 1.0f) const; FuzzyController mutate(float current_loss, float sigma_scale = 1.0f) const;
/// Crossover with another controller /// Crossover with another controller
FuzzyController crossover(const FuzzyController& partner, bool use_alignment = true) const; FuzzyController crossover(const FuzzyController &partner,
bool use_alignment = true) const;
/// Create an orthogonal counter-strategy (Phoenix Rebirth) /// Create an orthogonal counter-strategy (Phoenix Rebirth)
FuzzyController create_orthogonal_child(float intensity = 1.0f) const; FuzzyController create_orthogonal_child(float intensity = 1.0f) const;
/// Banach-Tarski fission: split into two complementary children /// Banach-Tarski fission: split into two complementary children
std::pair<FuzzyController, FuzzyController> banach_tarski_fission(float intensity = 1.0f) const; std::pair<FuzzyController, FuzzyController>
banach_tarski_fission(float intensity = 1.0f) const;
private: private:
static std::atomic<uint64_t> next_id_; static std::atomic<uint64_t> next_id_;

View File

@@ -21,23 +21,16 @@ namespace fces {
*/ */
class EvolutionManager { class EvolutionManager {
public: public:
explicit EvolutionManager( explicit EvolutionManager(Population &population, int selection_interval = 50,
Population& population,
int selection_interval = 50,
bool auto_population = false, bool auto_population = false,
bool direct_construction = false bool direct_construction = false);
);
/// Get the currently active controller /// Get the currently active controller
FuzzyController &get_active_controller(); FuzzyController &get_active_controller();
/// Update population dynamics based on current training state /// Update population dynamics based on current training state
void update_population_dynamics( void update_population_dynamics(float loss_velocity, float ema_loss,
float loss_velocity, int step_counter, int total_steps);
float ema_loss,
int step_counter,
int total_steps
);
/// Steps the active controller has been in control /// Steps the active controller has been in control
int steps_active = 0; int steps_active = 0;

View File

@@ -2,14 +2,15 @@
/** /**
* @file fitness.hpp * @file fitness.hpp
* @brief Fitness evaluation — loss signal processing and multi-objective evaluation. * @brief Fitness evaluation — loss signal processing and multi-objective
* evaluation.
* *
* Port of: packages/fces/core/fitness_engine.py + fitness.py * Port of: packages/fces/core/fitness_engine.py + fitness.py
*/ */
#include <cmath> #include <cmath>
#include <vector>
#include <string> #include <string>
#include <vector>
namespace fces { namespace fces {
@@ -48,7 +49,8 @@ public:
* @param mode "relative" or "absolute" * @param mode "relative" or "absolute"
* @return Velocity signal (negative = improving) * @return Velocity signal (negative = improving)
*/ */
float calculate_loss_signal(float current_loss, float ema_loss, const std::string& mode = "relative") const; float calculate_loss_signal(float current_loss, float ema_loss,
const std::string &mode = "relative") const;
/** /**
* Compute Kibble-Zurek Mechanism damping factor. * Compute Kibble-Zurek Mechanism damping factor.
@@ -112,7 +114,8 @@ struct FitnessMetrics {
}; };
/** /**
* FuzzyFitnessEvaluator — multi-objective fitness evaluation with fuzzy weighting. * FuzzyFitnessEvaluator — multi-objective fitness evaluation with fuzzy
* weighting.
*/ */
class FuzzyFitnessEvaluator { class FuzzyFitnessEvaluator {
public: public:

View File

@@ -5,17 +5,17 @@
* @brief FCESOptimizer — the main entry point. libtorch-compatible optimizer. * @brief FCESOptimizer — the main entry point. libtorch-compatible optimizer.
*/ */
#include <torch/torch.h>
#include <memory> #include <memory>
#include <vector>
#include <string> #include <string>
#include <torch/torch.h>
#include <vector>
#include "config.hpp" #include "config.hpp"
#include "population.hpp"
#include "fitness.hpp"
#include "evolution.hpp" #include "evolution.hpp"
#include "spectral.hpp" #include "fitness.hpp"
#include "oscillation.hpp" #include "oscillation.hpp"
#include "population.hpp"
#include "spectral.hpp"
#include "telemetry.hpp" #include "telemetry.hpp"
namespace fces { namespace fces {
@@ -24,7 +24,8 @@ namespace fces {
* FCESOptimizer — Fuzzy Controlled Evolutionary Search V49.0 (C++ Port). * FCESOptimizer — Fuzzy Controlled Evolutionary Search V49.0 (C++ Port).
* *
* Usage: * Usage:
* auto optimizer = FCESOptimizer(model->parameters(), FCESConfig{}.set_lr(1.6e-3)); * auto optimizer = FCESOptimizer(model->parameters(),
* FCESConfig{}.set_lr(1.6e-3));
* // In training loop: * // In training loop:
* optimizer.zero_grad(); * optimizer.zero_grad();
* auto loss = model->forward(input); * auto loss = model->forward(input);
@@ -32,7 +33,8 @@ namespace fces {
* optimizer.step(); * optimizer.step();
* optimizer.update_fitness(loss.item<float>()); * optimizer.update_fitness(loss.item<float>());
*/ */
struct FCESOptimizerOptions : public torch::optim::OptimizerCloneableOptions<FCESOptimizerOptions> { struct FCESOptimizerOptions
: public torch::optim::OptimizerCloneableOptions<FCESOptimizerOptions> {
explicit FCESOptimizerOptions(double lr = 0.01) : lr_(lr) {} explicit FCESOptimizerOptions(double lr = 0.01) : lr_(lr) {}
double get_lr() const override { return lr_; } double get_lr() const override { return lr_; }
@@ -43,10 +45,8 @@ struct FCESOptimizerOptions : public torch::optim::OptimizerCloneableOptions<FCE
class FCESOptimizer : public torch::optim::Optimizer { class FCESOptimizer : public torch::optim::Optimizer {
public: public:
explicit FCESOptimizer( explicit FCESOptimizer(std::vector<torch::Tensor> params,
std::vector<torch::Tensor> params, FCESConfig config = FCESConfig{});
FCESConfig config = FCESConfig{}
);
/// Perform a single optimization step /// Perform a single optimization step
torch::Tensor step(LossClosure closure = nullptr) override; torch::Tensor step(LossClosure closure = nullptr) override;

View File

@@ -25,7 +25,8 @@ public:
private: private:
std::vector<float> loss_history_; std::vector<float> loss_history_;
static std::vector<float> detrend(const std::vector<float> &signal); static std::vector<float> detrend(const std::vector<float> &signal);
static std::vector<float> compute_power_spectrum(const std::vector<float>& signal); static std::vector<float>
compute_power_spectrum(const std::vector<float> &signal);
}; };
} // namespace fces } // namespace fces

View File

@@ -16,9 +16,9 @@
* Port of: packages/fces/core/population.py (~1260 LOC) * Port of: packages/fces/core/population.py (~1260 LOC)
*/ */
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <optional>
#include "controller.hpp" #include "controller.hpp"
@@ -50,18 +50,13 @@ public:
// Construction // Construction
// --------------------------------------------------------------- // ---------------------------------------------------------------
explicit Population( explicit Population(int active_size = 75, int repo_size = 10000,
int active_size = 75,
int repo_size = 10000,
EliteStrategy elite_strategy = EliteStrategy::Cumulative, EliteStrategy elite_strategy = EliteStrategy::Cumulative,
bool link_mutation = false, bool link_mutation = false, bool link_elite = false,
bool link_elite = false, bool link_violator = false, bool use_fuzzy_pacer = false,
bool link_violator = false,
bool use_fuzzy_pacer = false,
bool use_fuzzy_importance = false, bool use_fuzzy_importance = false,
bool direct_construction = false, bool direct_construction = false,
bool use_banach_fission = false bool use_banach_fission = false);
);
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Core API // Core API
@@ -83,13 +78,15 @@ public:
void kill(FuzzyController &controller); void kill(FuzzyController &controller);
/// Update a controller's fitness /// Update a controller's fitness
void update_controller_fitness(FuzzyController& controller, float reward, bool increment_eval = true); void update_controller_fitness(FuzzyController &controller, float reward,
bool increment_eval = true);
/// Mark a controller as a violator (rollback) /// Mark a controller as a violator (rollback)
void mark_violated(FuzzyController &controller); void mark_violated(FuzzyController &controller);
/// Get the effective fitness considering elite strategy and training progress /// Get the effective fitness considering elite strategy and training progress
float get_effective_fitness(const FuzzyController& controller, float training_progress) const; float get_effective_fitness(const FuzzyController &controller,
float training_progress) const;
// --------------------------------------------------------------- // ---------------------------------------------------------------
// Evolution // Evolution
@@ -102,7 +99,8 @@ public:
* @param velocity Loss velocity * @param velocity Loss velocity
* @param training_progress Training progress [0, 1] * @param training_progress Training progress [0, 1]
*/ */
void evolve(float current_loss, float velocity = 0.0f, float training_progress = 0.0f); void evolve(float current_loss, float velocity = 0.0f,
float training_progress = 0.0f);
/// Resize the population (dynamic expansion/contraction) /// Resize the population (dynamic expansion/contraction)
void resize(int target_size, float training_progress = 0.5f); void resize(int target_size, float training_progress = 0.5f);

View File

@@ -13,8 +13,8 @@
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <torch/extension.h> #include <torch/extension.h>
#include "fces/optimizer.hpp"
#include "fces/config.hpp" #include "fces/config.hpp"
#include "fces/optimizer.hpp"
namespace py = pybind11; namespace py = pybind11;
@@ -26,13 +26,14 @@ PYBIND11_MODULE(fces_native, m) {
.def_readwrite("lr", &fces::FCESConfig::lr) .def_readwrite("lr", &fces::FCESConfig::lr)
.def_readwrite("population_size", &fces::FCESConfig::population_size) .def_readwrite("population_size", &fces::FCESConfig::population_size)
.def_readwrite("total_steps", &fces::FCESConfig::total_steps) .def_readwrite("total_steps", &fces::FCESConfig::total_steps)
.def_readwrite("grokking_coefficient", &fces::FCESConfig::grokking_coefficient) .def_readwrite("grokking_coefficient",
.def_readwrite("direct_construction", &fces::FCESConfig::direct_construction); &fces::FCESConfig::grokking_coefficient)
.def_readwrite("direct_construction",
&fces::FCESConfig::direct_construction);
py::class_<fces::FCESOptimizer>(m, "FCESOptimizer") py::class_<fces::FCESOptimizer>(m, "FCESOptimizer")
.def(py::init<std::vector<torch::Tensor>, fces::FCESConfig>(), .def(py::init<std::vector<torch::Tensor>, fces::FCESConfig>(),
py::arg("params"), py::arg("params"), py::arg("config") = fces::FCESConfig{})
py::arg("config") = fces::FCESConfig{})
.def("step", &fces::FCESOptimizer::step) .def("step", &fces::FCESOptimizer::step)
.def("update_fitness", &fces::FCESOptimizer::update_fitness) .def("update_fitness", &fces::FCESOptimizer::update_fitness)
.def("backup_to_ram", &fces::FCESOptimizer::backup_to_ram) .def("backup_to_ram", &fces::FCESOptimizer::backup_to_ram)

View File

@@ -29,11 +29,11 @@ Genome Genome::clone() const {
// FuzzyController // FuzzyController
// --------------------------------------------------------------- // ---------------------------------------------------------------
FuzzyController::FuzzyController() FuzzyController::FuzzyController() : id(next_id_++), origin("random") {
: id(next_id_++), origin("random") {
genome.randomize(rng_); genome.randomize(rng_);
// Bias output toward acceleration (V2.1 insight) // Bias output toward acceleration (V2.1 insight)
// Set output biases (last GENOME_OUTPUT_DIM elements) to +2.0, -1.0, 0.0 with noise // Set output biases (last GENOME_OUTPUT_DIM elements) to +2.0, -1.0, 0.0 with
// noise
constexpr int bias_start = GENOME_SIZE - GENOME_OUTPUT_DIM; constexpr int bias_start = GENOME_SIZE - GENOME_OUTPUT_DIM;
std::normal_distribution<float> bias_noise(0.0f, 0.5f); std::normal_distribution<float> bias_noise(0.0f, 0.5f);
genome.weights[bias_start] = 2.0f + bias_noise(rng_); genome.weights[bias_start] = 2.0f + bias_noise(rng_);
@@ -51,16 +51,10 @@ FuzzyController::FuzzyController(Genome genome)
: id(next_id_++), genome(std::move(genome)), origin("constructed") {} : id(next_id_++), genome(std::move(genome)), origin("constructed") {}
torch::Tensor FuzzyController::decide_update( torch::Tensor FuzzyController::decide_update(
const std::vector<std::vector<float>>& layer_stats, const std::vector<std::vector<float>> &layer_stats, float loss_trend,
float loss_trend, float step_pct, float rollback_rate, float grad_stability,
float step_pct, float spectral_alpha, float stagnation_intensity, float kzm_damping,
float rollback_rate, float projected_drift) {
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()); const int num_groups = static_cast<int>(layer_stats.size());
auto actions = torch::zeros({num_groups, GENOME_OUTPUT_DIM}); auto actions = torch::zeros({num_groups, GENOME_OUTPUT_DIM});
@@ -70,11 +64,14 @@ torch::Tensor FuzzyController::decide_update(
// Layer 1: input -> hidden // Layer 1: input -> hidden
const float *W1 = w; // [(GENOME_INPUT_DIM + 1) x GENOME_HIDDEN_DIM] const float *W1 = w; // [(GENOME_INPUT_DIM + 1) x GENOME_HIDDEN_DIM]
// Layer 2: hidden -> output // Layer 2: hidden -> output
const float* W2 = w + ((GENOME_INPUT_DIM + 1) * GENOME_HIDDEN_DIM); // [(GENOME_HIDDEN_DIM + 1) x GENOME_OUTPUT_DIM] const float *W2 =
w + ((GENOME_INPUT_DIM + 1) *
GENOME_HIDDEN_DIM); // [(GENOME_HIDDEN_DIM + 1) x GENOME_OUTPUT_DIM]
for (int g = 0; g < num_groups; ++g) { for (int g = 0; g < num_groups; ++g) {
// One-Hot Layer Type: Clamp to 5 to avoid overflow for new categories // One-Hot Layer Type: Clamp to 5 to avoid overflow for new categories
float layer_type_val = (layer_stats[g].size() >= 3) ? layer_stats[g][2] : 5.0f; float layer_type_val =
(layer_stats[g].size() >= 3) ? layer_stats[g][2] : 5.0f;
int type_idx = std::min(5, static_cast<int>(layer_type_val)); int type_idx = std::min(5, static_cast<int>(layer_type_val));
std::array<float, 5> type_onehot{0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; std::array<float, 5> type_onehot{0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
if (type_idx >= 0 && type_idx < 5) { if (type_idx >= 0 && type_idx < 5) {
@@ -87,19 +84,26 @@ torch::Tensor FuzzyController::decide_update(
float sp = (layer_stats[g].size() >= 2) ? layer_stats[g][1] : 0.0f; float sp = (layer_stats[g].size() >= 2) ? layer_stats[g][1] : 0.0f;
// Sanitization matching nan_to_num // Sanitization matching nan_to_num
if (!std::isfinite(gn) || std::isnan(gn)) gn = 0.0f; if (!std::isfinite(gn) || std::isnan(gn))
if (gn > 10.0f) gn = 10.0f; gn = 0.0f;
if (gn < 0.0f) gn = 0.0f; if (gn > 10.0f)
gn = 10.0f;
if (gn < 0.0f)
gn = 0.0f;
if (!std::isfinite(sp) || std::isnan(sp)) sp = 0.0f; if (!std::isfinite(sp) || std::isnan(sp))
if (sp > 1.0f) sp = 1.0f; sp = 0.0f;
if (sp < 0.0f) sp = 0.0f; if (sp > 1.0f)
sp = 1.0f;
if (sp < 0.0f)
sp = 0.0f;
input[0] = gn; input[0] = gn;
input[1] = sp; input[1] = sp;
input[2] = loss_trend; input[2] = loss_trend;
input[3] = step_pct; input[3] = step_pct;
input[4] = (num_groups > 1) ? static_cast<float>(g) / (num_groups - 1.0f) : 0.0f; input[4] =
(num_groups > 1) ? static_cast<float>(g) / (num_groups - 1.0f) : 0.0f;
input[5] = rollback_rate; input[5] = rollback_rate;
input[6] = grad_stability; input[6] = grad_stability;
input[7] = spectral_alpha; input[7] = spectral_alpha;
@@ -178,7 +182,8 @@ torch::Tensor FuzzyController::decide_update(
return actions; return actions;
} }
FuzzyController FuzzyController::mutate(float current_loss, float sigma_scale) const { FuzzyController FuzzyController::mutate(float current_loss,
float sigma_scale) const {
Genome child_genome = genome.clone(); Genome child_genome = genome.clone();
std::normal_distribution<float> std_normal(0.0f, 1.0f); std::normal_distribution<float> std_normal(0.0f, 1.0f);
@@ -207,7 +212,8 @@ FuzzyController FuzzyController::mutate(float current_loss, float sigma_scale) c
return child; return child;
} }
FuzzyController FuzzyController::crossover(const FuzzyController& partner, bool /*use_alignment*/) const { FuzzyController FuzzyController::crossover(const FuzzyController &partner,
bool /*use_alignment*/) const {
Genome child_genome; Genome child_genome;
std::uniform_real_distribution<float> u_dist(0.0f, 1.0f); std::uniform_real_distribution<float> u_dist(0.0f, 1.0f);
@@ -234,15 +240,18 @@ FuzzyController FuzzyController::crossover(const FuzzyController& partner, bool
} }
} }
child_genome.sigma_gene = (genome.sigma_gene + partner.genome.sigma_gene) * 0.5f; child_genome.sigma_gene =
child_genome.plasticity = (genome.plasticity + partner.genome.plasticity) * 0.5f; (genome.sigma_gene + partner.genome.sigma_gene) * 0.5f;
child_genome.plasticity =
(genome.plasticity + partner.genome.plasticity) * 0.5f;
FuzzyController child(child_genome); FuzzyController child(child_genome);
child.origin = "crossover"; child.origin = "crossover";
return child; return child;
} }
FuzzyController FuzzyController::create_orthogonal_child(float intensity) const { FuzzyController
FuzzyController::create_orthogonal_child(float intensity) const {
Genome child_genome; Genome child_genome;
std::normal_distribution<float> norm_dist(0.0f, 1.0f); std::normal_distribution<float> norm_dist(0.0f, 1.0f);
@@ -262,7 +271,8 @@ FuzzyController FuzzyController::create_orthogonal_child(float intensity) const
std::array<float, GENOME_SIZE> orthogonal_vec{}; std::array<float, GENOME_SIZE> orthogonal_vec{};
float norm_ortho = 0.0f; float norm_ortho = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) { for (size_t i = 0; i < GENOME_SIZE; ++i) {
float projection = (dot_product / (norm_elite * norm_elite)) * genome.weights[i]; float projection =
(dot_product / (norm_elite * norm_elite)) * genome.weights[i];
orthogonal_vec[i] = random_vec[i] - projection; orthogonal_vec[i] = random_vec[i] - projection;
norm_ortho += orthogonal_vec[i] * orthogonal_vec[i]; norm_ortho += orthogonal_vec[i] * orthogonal_vec[i];
} }
@@ -294,7 +304,8 @@ FuzzyController FuzzyController::create_orthogonal_child(float intensity) const
return child; return child;
} }
std::pair<FuzzyController, FuzzyController> FuzzyController::banach_tarski_fission(float intensity) const { std::pair<FuzzyController, FuzzyController>
FuzzyController::banach_tarski_fission(float intensity) const {
Genome plus_genome; Genome plus_genome;
Genome minus_genome; Genome minus_genome;
@@ -321,13 +332,15 @@ std::pair<FuzzyController, FuzzyController> FuzzyController::banach_tarski_fissi
std::array<float, GENOME_SIZE> fission_vec{}; std::array<float, GENOME_SIZE> fission_vec{};
float norm_fission = 0.0f; float norm_fission = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) { for (size_t i = 0; i < GENOME_SIZE; ++i) {
fission_vec[i] = noise[i] - (dot_product / (norm_parent * norm_parent)) * genome.weights[i]; fission_vec[i] = noise[i] - (dot_product / (norm_parent * norm_parent)) *
genome.weights[i];
norm_fission += fission_vec[i] * fission_vec[i]; norm_fission += fission_vec[i] * fission_vec[i];
} }
norm_fission = std::sqrt(norm_fission) + 1e-9f; norm_fission = std::sqrt(norm_fission) + 1e-9f;
for (size_t i = 0; i < GENOME_SIZE; ++i) { for (size_t i = 0; i < GENOME_SIZE; ++i) {
float scaled_fission = fission_vec[i] * (norm_parent / norm_fission) * 0.1f * intensity; float scaled_fission =
fission_vec[i] * (norm_parent / norm_fission) * 0.1f * intensity;
plus_genome.weights[i] = genome.weights[i] + scaled_fission; plus_genome.weights[i] = genome.weights[i] + scaled_fission;
minus_genome.weights[i] = genome.weights[i] - scaled_fission; minus_genome.weights[i] = genome.weights[i] - scaled_fission;

View File

@@ -2,12 +2,10 @@
namespace fces { namespace fces {
EvolutionManager::EvolutionManager( EvolutionManager::EvolutionManager(Population &population,
Population& population, int selection_interval, int selection_interval, bool auto_population,
bool auto_population, bool direct_construction bool direct_construction)
) : population_(population), selection_interval(selection_interval),
: population_(population),
selection_interval(selection_interval),
auto_population_(auto_population), auto_population_(auto_population),
direct_construction_(direct_construction) {} direct_construction_(direct_construction) {}
@@ -15,17 +13,14 @@ FuzzyController& EvolutionManager::get_active_controller() {
return population_.get_active_controller(); return population_.get_active_controller();
} }
void EvolutionManager::update_population_dynamics( void EvolutionManager::update_population_dynamics(float loss_velocity,
float loss_velocity, float ema_loss, int step_counter, int total_steps float ema_loss,
) { int step_counter,
int total_steps) {
float progress = static_cast<float>(step_counter) / std::max(1, total_steps); float progress = static_cast<float>(step_counter) / std::max(1, total_steps);
if (step_counter % 20 == 0) { if (step_counter % 20 == 0) {
population_.evolve( population_.evolve(std::abs(loss_velocity), loss_velocity, progress);
std::abs(loss_velocity),
loss_velocity,
progress
);
} }
if (!auto_population_ || step_counter % 50 != 0) { if (!auto_population_ || step_counter % 50 != 0) {

View File

@@ -1,7 +1,7 @@
#include "fces/fitness.hpp" #include "fces/fitness.hpp"
#include <algorithm>
#include <cmath> #include <cmath>
#include <numeric> #include <numeric>
#include <algorithm>
#include <string> #include <string>
namespace fces { namespace fces {
@@ -20,12 +20,14 @@ void RunningStats::update(float value) {
float RunningStats::z_score(float value) const { float RunningStats::z_score(float value) const {
float s = get_std(); float s = get_std();
if (s < 1e-8f) return 0.0f; if (s < 1e-8f)
return 0.0f;
return (value - mean_) / s; return (value - mean_) / s;
} }
float RunningStats::get_std() const { float RunningStats::get_std() const {
if (count_ < 2) return 1.0f; if (count_ < 2)
return 1.0f;
return std::sqrt(m2_ / static_cast<float>(count_ - 1)); return std::sqrt(m2_ / static_cast<float>(count_ - 1));
} }
@@ -42,8 +44,10 @@ void RunningStats::reset() {
FitnessEngine::FitnessEngine(float grokking_coefficient) FitnessEngine::FitnessEngine(float grokking_coefficient)
: grokking_coefficient_(grokking_coefficient) {} : grokking_coefficient_(grokking_coefficient) {}
float FitnessEngine::calculate_loss_signal(float current_loss, float ema_loss, const std::string& mode) const { float FitnessEngine::calculate_loss_signal(float current_loss, float ema_loss,
if (ema_loss < 1e-8f) return 0.0f; const std::string &mode) const {
if (ema_loss < 1e-8f)
return 0.0f;
if (mode == "relative") { if (mode == "relative") {
return (current_loss - ema_loss) / (ema_loss + 1e-8f); return (current_loss - ema_loss) / (ema_loss + 1e-8f);
@@ -68,7 +72,8 @@ FuzzyFitnessEvaluator::FuzzyFitnessEvaluator() noexcept
consistency_set_("Consistent", -1.0f, 0.0f, 0.02f, 0.1f), consistency_set_("Consistent", -1.0f, 0.0f, 0.02f, 0.1f),
rank_set_("LowRank", -1.0f, 0.0f, 5.0f, 20.0f) {} rank_set_("LowRank", -1.0f, 0.0f, 5.0f, 20.0f) {}
float FuzzyFitnessEvaluator::evaluate(const FitnessMetrics& metrics) const noexcept { float FuzzyFitnessEvaluator::evaluate(
const FitnessMetrics &metrics) const noexcept {
float m_stability = stability_set_.membership(metrics.grad_cv); float m_stability = stability_set_.membership(metrics.grad_cv);
float m_train = train_set_.membership(metrics.training_advantage); float m_train = train_set_.membership(metrics.training_advantage);
float m_val = val_set_.membership(metrics.validation_advantage); float m_val = val_set_.membership(metrics.validation_advantage);
@@ -76,15 +81,12 @@ float FuzzyFitnessEvaluator::evaluate(const FitnessMetrics& metrics) const noexc
float m_consistency = consistency_set_.membership(metrics.consistency_gap); float m_consistency = consistency_set_.membership(metrics.consistency_gap);
float m_rank = rank_set_.membership(metrics.stable_rank); float m_rank = rank_set_.membership(metrics.stable_rank);
float weighted_score = float weighted_score = m_stability * w_stability_ + m_train * w_train_ +
m_stability * w_stability_ + m_val * w_val_ + m_sparsity * w_sparsity_ +
m_train * w_train_ + m_consistency * w_consistency_ + m_rank * w_rank_;
m_val * w_val_ +
m_sparsity * w_sparsity_ +
m_consistency * w_consistency_ +
m_rank * w_rank_;
float total_weight = w_stability_ + w_train_ + w_val_ + w_sparsity_ + w_consistency_ + w_rank_; float total_weight =
w_stability_ + w_train_ + w_val_ + w_sparsity_ + w_consistency_ + w_rank_;
if (total_weight > 0.0f) { if (total_weight > 0.0f) {
weighted_score /= total_weight; weighted_score /= total_weight;
} }

View File

@@ -1,7 +1,7 @@
#include "fces/optimizer.hpp" #include "fces/optimizer.hpp"
#include <algorithm>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <algorithm>
namespace fces { namespace fces {
@@ -31,8 +31,10 @@ int classify_layer_by_shape(const torch::Tensor& p) {
return 5; // Other return 5; // Other
} }
torch::Tensor apply_trust_clipping(const torch::Tensor& p, torch::Tensor update, float trust_region_clip) { torch::Tensor apply_trust_clipping(const torch::Tensor &p, torch::Tensor update,
if (torch::isnan(update).any().item<bool>() || torch::isinf(update).any().item<bool>()) { float trust_region_clip) {
if (torch::isnan(update).any().item<bool>() ||
torch::isinf(update).any().item<bool>()) {
return torch::zeros_like(update); return torch::zeros_like(update);
} }
@@ -50,14 +52,16 @@ torch::Tensor apply_trust_clipping(const torch::Tensor& p, torch::Tensor update,
} }
} }
if (torch::isnan(update).any().item<bool>() || torch::isinf(update).any().item<bool>()) { if (torch::isnan(update).any().item<bool>() ||
torch::isinf(update).any().item<bool>()) {
return torch::zeros_like(update); return torch::zeros_like(update);
} }
return update; return update;
} }
float calculate_parasitic_reward(const torch::Tensor& p, float mult, const RunningStats& grad_norm_tracker) { float calculate_parasitic_reward(const torch::Tensor &p, float mult,
const RunningStats &grad_norm_tracker) {
if (!p.grad().defined()) { if (!p.grad().defined()) {
return 0.0f; return 0.0f;
} }
@@ -66,31 +70,26 @@ float calculate_parasitic_reward(const torch::Tensor& p, float mult, const Runni
return z_g * (mult - 1.0f); return z_g * (mult - 1.0f);
} }
std::unique_ptr<torch::optim::OptimizerOptions> make_optimizer_options(double lr) { std::unique_ptr<torch::optim::OptimizerOptions>
make_optimizer_options(double lr) {
return std::make_unique<FCESOptimizerOptions>(lr); return std::make_unique<FCESOptimizerOptions>(lr);
} }
} // namespace } // namespace
FCESOptimizer::FCESOptimizer( FCESOptimizer::FCESOptimizer(std::vector<torch::Tensor> params,
std::vector<torch::Tensor> params, FCESConfig config)
FCESConfig config
)
: torch::optim::Optimizer( : torch::optim::Optimizer(
{torch::optim::OptimizerParamGroup(std::move(params))}, {torch::optim::OptimizerParamGroup(std::move(params))},
make_optimizer_options(config.lr) make_optimizer_options(config.lr)),
),
config_(std::move(config)), config_(std::move(config)),
population_(config_.population_size, 10000, population_(config_.population_size, 10000, EliteStrategy::Cumulative,
EliteStrategy::Cumulative,
false, false, false, false, false, false, false, false, false, false,
config_.direct_construction, config_.direct_construction, config_.use_banach_fission),
config_.use_banach_fission),
fitness_engine_(config_.grokking_coefficient) { fitness_engine_(config_.grokking_coefficient) {
evolution_manager_ = std::make_unique<EvolutionManager>( evolution_manager_ = std::make_unique<EvolutionManager>(
population_, 50, config_.auto_population, config_.direct_construction population_, 50, config_.auto_population, config_.direct_construction);
);
spectral_sensor_ = std::make_unique<SpectralSensor>(); spectral_sensor_ = std::make_unique<SpectralSensor>();
@@ -98,7 +97,8 @@ FCESOptimizer::FCESOptimizer(
backup_to_ram(); backup_to_ram();
Telemetry::get().info("optimizer_initialized", Telemetry::get().info("optimizer_initialized",
"version=0.1.0 pop_size=" + std::to_string(config_.population_size)); "version=0.1.0 pop_size=" +
std::to_string(config_.population_size));
} }
torch::Tensor FCESOptimizer::step(LossClosure closure) { torch::Tensor FCESOptimizer::step(LossClosure closure) {
@@ -118,35 +118,45 @@ torch::Tensor FCESOptimizer::step(LossClosure closure) {
auto &active_controller = evolution_manager_->get_active_controller(); auto &active_controller = evolution_manager_->get_active_controller();
// 3. Decision: Neural Decisions from Controllers // 3. Decision: Neural Decisions from Controllers
float current_loss_val = (loss.defined()) ? loss.item<float>() : last_step_loss_; float current_loss_val =
(loss.defined()) ? loss.item<float>() : last_step_loss_;
// Emergency Brake - NaN/Inf Detection // Emergency Brake - NaN/Inf Detection
if (std::isnan(current_loss_val) || !std::isfinite(current_loss_val)) { if (std::isnan(current_loss_val) || !std::isfinite(current_loss_val)) {
Telemetry::get().error("emergency_brake_nan", "NaN/Inf loss detected in step " + std::to_string(step_counter_)); Telemetry::get().error("emergency_brake_nan",
"NaN/Inf loss detected in step " +
std::to_string(step_counter_));
handle_rollback(); handle_rollback();
return loss; return loss;
} }
float loss_velocity = fitness_engine_.calculate_loss_signal(current_loss_val, ema_loss_, config_.signal_mode); float loss_velocity = fitness_engine_.calculate_loss_signal(
current_loss_val, ema_loss_, config_.signal_mode);
last_loss_velocity_ = loss_velocity; last_loss_velocity_ = loss_velocity;
float progress = std::min(1.0f, static_cast<float>(step_counter_) / std::max(1, config_.total_steps)); float progress = std::min(1.0f, static_cast<float>(step_counter_) /
float grad_cv = grad_norm_tracker_.get_std() / (grad_norm_tracker_.get_mean() + 1e-8f); std::max(1, config_.total_steps));
float grad_cv =
grad_norm_tracker_.get_std() / (grad_norm_tracker_.get_mean() + 1e-8f);
float csr_factor = 1.0f; float csr_factor = 1.0f;
if (config_.csr_enabled) { if (config_.csr_enabled) {
if (step_counter_ < config_.csr_warmup_steps) { if (step_counter_ < config_.csr_warmup_steps) {
csr_factor = 0.0f; csr_factor = 0.0f;
} else { } else {
float steps_since_warmup = static_cast<float>(step_counter_ - config_.csr_warmup_steps); float steps_since_warmup =
csr_factor = std::min(1.0f, steps_since_warmup / std::max(1.0f, static_cast<float>(config_.csr_ramp_steps))); static_cast<float>(step_counter_ - config_.csr_warmup_steps);
csr_factor = std::min(
1.0f, steps_since_warmup /
std::max(1.0f, static_cast<float>(config_.csr_ramp_steps)));
} }
} }
// Update spectral sensing rank // Update spectral sensing rank
float spectral_alpha = 0.0f; float spectral_alpha = 0.0f;
if (config_.grokking_coefficient > 0.0f && spectral_sensor_) { if (config_.grokking_coefficient > 0.0f && spectral_sensor_) {
if (step_counter_ % config_.spectral_frequency == 0 || last_spectral_rank_ == 0.0f) { if (step_counter_ % config_.spectral_frequency == 0 ||
last_spectral_rank_ == 0.0f) {
int param_idx = 0; int param_idx = 0;
for (auto &group : param_groups()) { for (auto &group : param_groups()) {
for (auto &p : group.params()) { for (auto &p : group.params()) {
@@ -164,31 +174,28 @@ torch::Tensor FCESOptimizer::step(LossClosure closure) {
float effective_alpha = spectral_alpha * csr_factor; float effective_alpha = spectral_alpha * csr_factor;
float kzm_damping = fitness_engine_.compute_kzm_damping(effective_alpha); float kzm_damping = fitness_engine_.compute_kzm_damping(effective_alpha);
float stagnation_intensity = std::min(1.0f, static_cast<float>(stagnation_counter_) / 500.0f); float stagnation_intensity =
std::min(1.0f, static_cast<float>(stagnation_counter_) / 500.0f);
float log_spectral_alpha = std::log(effective_alpha + 1e-6f); float log_spectral_alpha = std::log(effective_alpha + 1e-6f);
// Call decide_update // Call decide_update
auto actions = active_controller.decide_update( auto actions = active_controller.decide_update(
layer_stats_, layer_stats_, loss_velocity, progress, rollback_ema_, grad_cv,
loss_velocity, log_spectral_alpha, stagnation_intensity, kzm_damping, loss_velocity);
progress,
rollback_ema_,
grad_cv,
log_spectral_alpha,
stagnation_intensity,
kzm_damping,
loss_velocity
);
// Bandit-style Early Stopping // Bandit-style Early Stopping
if (step_counter_ % 5 == 0 && loss_velocity > 0.05f) { if (step_counter_ % 5 == 0 && loss_velocity > 0.05f) {
Telemetry::get().warning("early_stopping_poor_controller", Telemetry::get().warning(
"controller_id=" + std::to_string(active_controller.id) + " velocity=" + std::to_string(loss_velocity)); "early_stopping_poor_controller",
"controller_id=" + std::to_string(active_controller.id) +
" velocity=" + std::to_string(loss_velocity));
evolution_manager_->steps_active = evolution_manager_->selection_interval; evolution_manager_->steps_active = evolution_manager_->selection_interval;
} }
if (torch::isnan(actions).any().item<bool>()) { if (torch::isnan(actions).any().item<bool>()) {
Telemetry::get().error("controller_nan_actions", "NaN actions returned by controller ID " + std::to_string(active_controller.id)); Telemetry::get().error("controller_nan_actions",
"NaN actions returned by controller ID " +
std::to_string(active_controller.id));
population_.kill(active_controller); population_.kill(active_controller);
auto &new_controller = evolution_manager_->get_active_controller(); auto &new_controller = evolution_manager_->get_active_controller();
actions = torch::zeros_like(actions); actions = torch::zeros_like(actions);
@@ -203,11 +210,7 @@ torch::Tensor FCESOptimizer::step(LossClosure closure) {
// 5. Evolution & Maintenance // 5. Evolution & Maintenance
if (current_loss_val > 0.0f) { if (current_loss_val > 0.0f) {
evolution_manager_->update_population_dynamics( evolution_manager_->update_population_dynamics(
loss_velocity, loss_velocity, ema_loss_, step_counter_, config_.total_steps);
ema_loss_,
step_counter_,
config_.total_steps
);
} }
if (step_counter_ % 50 == 0) { if (step_counter_ % 50 == 0) {
@@ -220,9 +223,13 @@ torch::Tensor FCESOptimizer::step(LossClosure closure) {
void FCESOptimizer::update_fitness(float loss) { void FCESOptimizer::update_fitness(float loss) {
// 1. Divergence Safety // 1. Divergence Safety
bool is_nan = std::isnan(loss) || !std::isfinite(loss); bool is_nan = std::isnan(loss) || !std::isfinite(loss);
bool is_spike = (step_counter_ > 1) && (ema_loss_ > 0.0f) && (loss > config_.rollback_threshold * ema_loss_) && (ema_loss_ > 0.1f); bool is_spike = (step_counter_ > 1) && (ema_loss_ > 0.0f) &&
(loss > config_.rollback_threshold * ema_loss_) &&
(ema_loss_ > 0.1f);
if (is_nan || is_spike) { if (is_nan || is_spike) {
Telemetry::get().warning("divergence_detected", "loss=" + std::to_string(loss) + " ema=" + std::to_string(ema_loss_)); Telemetry::get().warning("divergence_detected",
"loss=" + std::to_string(loss) +
" ema=" + std::to_string(ema_loss_));
handle_rollback(); handle_rollback();
return; return;
} }
@@ -245,14 +252,18 @@ void FCESOptimizer::update_fitness(float loss) {
float grad_mean = grad_norm_tracker_.get_mean(); float grad_mean = grad_norm_tracker_.get_mean();
float grad_cv = grad_std / (grad_mean + 1e-8f); float grad_cv = grad_std / (grad_mean + 1e-8f);
float raw_rank = (spectral_sensor_) ? spectral_sensor_->get_global_rank() : 0.0f; float raw_rank =
(spectral_sensor_) ? spectral_sensor_->get_global_rank() : 0.0f;
float csr_factor = 1.0f; float csr_factor = 1.0f;
if (config_.csr_enabled) { if (config_.csr_enabled) {
if (step_counter_ < config_.csr_warmup_steps) { if (step_counter_ < config_.csr_warmup_steps) {
csr_factor = 0.0f; csr_factor = 0.0f;
} else { } else {
float steps_since_warmup = static_cast<float>(step_counter_ - config_.csr_warmup_steps); float steps_since_warmup =
csr_factor = std::min(1.0f, steps_since_warmup / std::max(1.0f, static_cast<float>(config_.csr_ramp_steps))); static_cast<float>(step_counter_ - config_.csr_warmup_steps);
csr_factor = std::min(
1.0f, steps_since_warmup /
std::max(1.0f, static_cast<float>(config_.csr_ramp_steps)));
} }
} }
float effective_rank = config_.csr_enabled ? raw_rank * csr_factor : raw_rank; float effective_rank = config_.csr_enabled ? raw_rank * csr_factor : raw_rank;
@@ -339,7 +350,8 @@ void FCESOptimizer::gather_stats() {
} }
auto grad = p.grad(); auto grad = p.grad();
if (torch::isnan(grad).any().item<bool>() || torch::isinf(grad).any().item<bool>()) { if (torch::isnan(grad).any().item<bool>() ||
torch::isinf(grad).any().item<bool>()) {
has_nan_or_inf = true; has_nan_or_inf = true;
} }
@@ -355,11 +367,14 @@ void FCESOptimizer::gather_stats() {
int64_t total_elements = grad.numel(); int64_t total_elements = grad.numel();
int64_t zeros = (grad.abs() < 1e-5f).sum().item<int64_t>(); int64_t zeros = (grad.abs() < 1e-5f).sum().item<int64_t>();
float sparsity = (total_elements > 0) ? static_cast<float>(zeros) / total_elements : 0.0f; float sparsity = (total_elements > 0)
? static_cast<float>(zeros) / total_elements
: 0.0f;
int layer_type = classify_layer_by_shape(p); int layer_type = classify_layer_by_shape(p);
int group_idx = static_cast<int>(layer_stats_.size()); int group_idx = static_cast<int>(layer_stats_.size());
layer_stats_.push_back({grad_norm, sparsity, static_cast<float>(layer_type)}); layer_stats_.push_back(
{grad_norm, sparsity, static_cast<float>(layer_type)});
param_group_mapping_.push_back(group_idx); param_group_mapping_.push_back(group_idx);
if (spectral_sensor_ && p.dim() >= 2) { if (spectral_sensor_ && p.dim() >= 2) {
@@ -373,7 +388,8 @@ void FCESOptimizer::gather_stats() {
if (has_nan_or_inf) { if (has_nan_or_inf) {
Telemetry::get().error("poisoned_gradients_detected", Telemetry::get().error("poisoned_gradients_detected",
"NaN/Inf detected in gradients during step " + std::to_string(step_counter_)); "NaN/Inf detected in gradients during step " +
std::to_string(step_counter_));
handle_rollback(); handle_rollback();
return; return;
} }
@@ -382,8 +398,10 @@ void FCESOptimizer::gather_stats() {
float safe_lr = 0.01f / (max_grad_norm + 1e-8f); float safe_lr = 0.01f / (max_grad_norm + 1e-8f);
for (auto &group : param_groups()) { for (auto &group : param_groups()) {
if (group.options().get_lr() > safe_lr) { if (group.options().get_lr() > safe_lr) {
Telemetry::get().info("auto_calibration_throttled_lr", Telemetry::get().info(
"old=" + std::to_string(group.options().get_lr()) + " new=" + std::to_string(safe_lr)); "auto_calibration_throttled_lr",
"old=" + std::to_string(group.options().get_lr()) +
" new=" + std::to_string(safe_lr));
group.options().set_lr(safe_lr); group.options().set_lr(safe_lr);
config_.lr = safe_lr; config_.lr = safe_lr;
} }
@@ -421,7 +439,8 @@ void FCESOptimizer::apply_parameter_updates(const torch::Tensor& actions) {
float mult = actions[g_idx][0].item<float>(); float mult = actions[g_idx][0].item<float>();
float sign_gate = actions[g_idx][1].item<float>(); float sign_gate = actions[g_idx][1].item<float>();
float wd_mult = (actions.size(1) > 2) ? actions[g_idx][2].item<float>() : 1.0f; float wd_mult =
(actions.size(1) > 2) ? actions[g_idx][2].item<float>() : 1.0f;
bool use_sign = sign_gate > 0.0f; bool use_sign = sign_gate > 0.0f;
if (config_.ablation_mode == "force_sign") { if (config_.ablation_mode == "force_sign") {
@@ -445,7 +464,8 @@ void FCESOptimizer::apply_parameter_updates(const torch::Tensor& actions) {
p.data().add_(update); p.data().add_(update);
if (config_.parasitic_mode) { if (config_.parasitic_mode) {
parasitic_accum += calculate_parasitic_reward(p, mult, grad_norm_tracker_); parasitic_accum +=
calculate_parasitic_reward(p, mult, grad_norm_tracker_);
} }
param_idx++; param_idx++;
@@ -455,7 +475,8 @@ void FCESOptimizer::apply_parameter_updates(const torch::Tensor& actions) {
if (config_.parasitic_mode && count_updated > 0) { if (config_.parasitic_mode && count_updated > 0) {
float reward = parasitic_accum / static_cast<float>(count_updated); float reward = parasitic_accum / static_cast<float>(count_updated);
population_.update_controller_fitness(active_controller, reward * 10.0f, false); population_.update_controller_fitness(active_controller, reward * 10.0f,
false);
} }
} }

View File

@@ -1,7 +1,7 @@
#include "fces/oscillation.hpp" #include "fces/oscillation.hpp"
#include <algorithm>
#include <cmath> #include <cmath>
#include <numeric> #include <numeric>
#include <algorithm>
namespace fces { namespace fces {
@@ -17,7 +17,8 @@ bool OscillationDetector::detect() const {
} }
float OscillationDetector::get_score() const { float OscillationDetector::get_score() const {
if (static_cast<int>(loss_history_.size()) < WINDOW_SIZE) return 0.0f; if (static_cast<int>(loss_history_.size()) < WINDOW_SIZE)
return 0.0f;
auto detrended = detrend(loss_history_); auto detrended = detrend(loss_history_);
auto power = compute_power_spectrum(detrended); auto power = compute_power_spectrum(detrended);
@@ -34,12 +35,14 @@ float OscillationDetector::get_score() const {
} }
} }
if (total_power < 1e-8f) return 0.0f; if (total_power < 1e-8f)
return 0.0f;
return osc_power / total_power; return osc_power / total_power;
} }
float OscillationDetector::get_variance_50() const { float OscillationDetector::get_variance_50() const {
if (loss_history_.size() < 50) return 0.0f; if (loss_history_.size() < 50)
return 0.0f;
auto start = loss_history_.end() - 50; auto start = loss_history_.end() - 50;
float mean = std::accumulate(start, loss_history_.end(), 0.0f) / 50.0f; float mean = std::accumulate(start, loss_history_.end(), 0.0f) / 50.0f;
float var = 0.0f; float var = 0.0f;
@@ -50,13 +53,13 @@ float OscillationDetector::get_variance_50() const {
return var / 50.0f; return var / 50.0f;
} }
void OscillationDetector::reset() { void OscillationDetector::reset() { loss_history_.clear(); }
loss_history_.clear();
}
std::vector<float> OscillationDetector::detrend(const std::vector<float>& signal) { std::vector<float>
OscillationDetector::detrend(const std::vector<float> &signal) {
int n = static_cast<int>(signal.size()); int n = static_cast<int>(signal.size());
if (n < 2) return signal; if (n < 2)
return signal;
// Remove linear trend via least squares // Remove linear trend via least squares
float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0; float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
@@ -66,7 +69,8 @@ std::vector<float> OscillationDetector::detrend(const std::vector<float>& signal
sum_xy += i * signal[i]; sum_xy += i * signal[i];
sum_xx += i * i; sum_xx += i * i;
} }
float slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x + 1e-8f); float slope =
(n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x + 1e-8f);
float intercept = (sum_y - slope * sum_x) / n; float intercept = (sum_y - slope * sum_x) / n;
std::vector<float> result(n); std::vector<float> result(n);
@@ -76,8 +80,10 @@ std::vector<float> OscillationDetector::detrend(const std::vector<float>& signal
return result; return result;
} }
std::vector<float> OscillationDetector::compute_power_spectrum(const std::vector<float>& signal) { std::vector<float>
// Simple DFT (for WINDOW_SIZE=64, this is fast enough; upgrade to FFT if needed) OscillationDetector::compute_power_spectrum(const std::vector<float> &signal) {
// Simple DFT (for WINDOW_SIZE=64, this is fast enough; upgrade to FFT if
// needed)
int n = static_cast<int>(signal.size()); int n = static_cast<int>(signal.size());
int half = n / 2; int half = n / 2;
std::vector<float> power(half); std::vector<float> power(half);

View File

@@ -4,22 +4,20 @@
namespace fces { namespace fces {
Population::Population( Population::Population(int active_size, int repo_size,
int active_size, int repo_size, EliteStrategy elite_strategy, EliteStrategy elite_strategy, bool link_mutation,
bool link_mutation, bool link_elite, bool link_violator, bool link_elite, bool link_violator,
bool use_fuzzy_pacer, bool use_fuzzy_importance, bool use_fuzzy_pacer, bool use_fuzzy_importance,
bool direct_construction, bool use_banach_fission bool direct_construction, bool use_banach_fission)
) : elite_strategy_(elite_strategy), link_mutation_(link_mutation),
: elite_strategy_(elite_strategy), link_elite_(link_elite), link_violator_(link_violator),
link_mutation_(link_mutation),
link_elite_(link_elite),
link_violator_(link_violator),
use_fuzzy_pacer_(use_fuzzy_pacer), use_fuzzy_pacer_(use_fuzzy_pacer),
use_fuzzy_importance_(use_fuzzy_importance), use_fuzzy_importance_(use_fuzzy_importance),
direct_construction_(direct_construction), direct_construction_(direct_construction),
use_banach_fission_(use_banach_fission) { use_banach_fission_(use_banach_fission) {
if (direct_construction) active_size = 1; if (direct_construction)
active_size = 1;
gladiators_.reserve(active_size); gladiators_.reserve(active_size);
for (int i = 0; i < active_size; ++i) { for (int i = 0; i < active_size; ++i) {
@@ -48,12 +46,14 @@ FuzzyController& Population::select_weighted() {
sum_fit += std::max(0.0f, g.fitness); sum_fit += std::max(0.0f, g.fitness);
} }
if (sum_fit == 0.0f) { if (sum_fit == 0.0f) {
std::uniform_int_distribution<int> dist(0, static_cast<int>(gladiators_.size()) - 1); std::uniform_int_distribution<int> dist(
0, static_cast<int>(gladiators_.size()) - 1);
return gladiators_[dist(rng)]; return gladiators_[dist(rng)];
} }
// Select 3 random candidates for tournament // Select 3 random candidates for tournament
std::uniform_int_distribution<int> dist(0, static_cast<int>(gladiators_.size()) - 1); std::uniform_int_distribution<int> dist(
0, static_cast<int>(gladiators_.size()) - 1);
int idx1 = dist(rng); int idx1 = dist(rng);
int idx2 = dist(rng); int idx2 = dist(rng);
int idx3 = dist(rng); int idx3 = dist(rng);
@@ -64,7 +64,10 @@ FuzzyController& Population::select_weighted() {
if (behavioral_archive_.size() >= 5) { if (behavioral_archive_.size() >= 5) {
float novelty = 0.0f; float novelty = 0.0f;
// Get behavioral vector: first 20 weights // Get behavioral vector: first 20 weights
std::vector<float> behavior(c.genome.weights.begin(), c.genome.weights.begin() + std::min(20, static_cast<int>(c.genome.weights.size()))); std::vector<float> behavior(
c.genome.weights.begin(),
c.genome.weights.begin() +
std::min(20, static_cast<int>(c.genome.weights.size())));
std::vector<float> distances; std::vector<float> distances;
distances.reserve(behavioral_archive_.size()); distances.reserve(behavioral_archive_.size());
for (const auto &archived : behavioral_archive_) { for (const auto &archived : behavioral_archive_) {
@@ -81,7 +84,8 @@ FuzzyController& Population::select_weighted() {
for (int i = 0; i < k; ++i) { for (int i = 0; i < k; ++i) {
avg_dist += distances[i]; avg_dist += distances[i];
} }
if (k > 0) avg_dist /= static_cast<float>(k); if (k > 0)
avg_dist /= static_cast<float>(k);
base_score += NOVELTY_WEIGHT * avg_dist; base_score += NOVELTY_WEIGHT * avg_dist;
} }
return base_score; return base_score;
@@ -108,7 +112,8 @@ FuzzyController& Population::select_weighted() {
} }
FuzzyController &Population::get_best_active() { FuzzyController &Population::get_best_active() {
return *std::max_element(gladiators_.begin(), gladiators_.end(), return *std::max_element(
gladiators_.begin(), gladiators_.end(),
[](const FuzzyController &a, const FuzzyController &b) { [](const FuzzyController &a, const FuzzyController &b) {
return a.fitness < b.fitness; return a.fitness < b.fitness;
}); });
@@ -131,13 +136,17 @@ FuzzyController& Population::get_worst_active() {
} }
if (non_elites.empty()) { if (non_elites.empty()) {
return *std::min_element(gladiators_.begin(), gladiators_.end(), return *std::min_element(
gladiators_.begin(), gladiators_.end(),
[](const FuzzyController &a, const FuzzyController &b) { [](const FuzzyController &a, const FuzzyController &b) {
return a.fitness < b.fitness; return a.fitness < b.fitness;
}); });
} }
return **std::min_element(non_elites.begin(), non_elites.end(), // cppcheck-suppress returnReference; False Positive: elements of non_elites
// point to members of gladiators_
return **std::min_element(
non_elites.begin(), non_elites.end(),
[](const FuzzyController *a, const FuzzyController *b) { [](const FuzzyController *a, const FuzzyController *b) {
return a->fitness < b->fitness; return a->fitness < b->fitness;
}); });
@@ -151,7 +160,8 @@ void Population::kill(FuzzyController& controller) {
} }
} }
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), auto it = std::find_if(
gladiators_.begin(), gladiators_.end(),
[&](const FuzzyController &c) { return c.id == controller.id; }); [&](const FuzzyController &c) { return c.id == controller.id; });
if (it != gladiators_.end()) { if (it != gladiators_.end()) {
gladiators_.erase(it); gladiators_.erase(it);
@@ -161,7 +171,8 @@ void Population::kill(FuzzyController& controller) {
} }
} }
void Population::update_controller_fitness(FuzzyController& controller, float reward, bool increment_eval) { void Population::update_controller_fitness(FuzzyController &controller,
float reward, bool increment_eval) {
if (increment_eval) { if (increment_eval) {
controller.age++; controller.age++;
controller.evaluation_count++; controller.evaluation_count++;
@@ -177,7 +188,8 @@ void Population::update_controller_fitness(FuzzyController& controller, float re
if (elite_strategy_ == EliteStrategy::EMA) { if (elite_strategy_ == EliteStrategy::EMA) {
constexpr float EMA_ALPHA = 0.1f; constexpr float EMA_ALPHA = 0.1f;
controller.ema_fitness = (1.0f - EMA_ALPHA) * controller.ema_fitness + EMA_ALPHA * reward; controller.ema_fitness =
(1.0f - EMA_ALPHA) * controller.ema_fitness + EMA_ALPHA * reward;
controller.fitness = reward; controller.fitness = reward;
} else if (elite_strategy_ == EliteStrategy::Rolling) { } else if (elite_strategy_ == EliteStrategy::Rolling) {
controller.fitness = reward; controller.fitness = reward;
@@ -187,35 +199,41 @@ void Population::update_controller_fitness(FuzzyController& controller, float re
} }
void Population::mark_violated(FuzzyController &controller) { void Population::mark_violated(FuzzyController &controller) {
auto it = std::find_if(violated_controllers_.begin(), violated_controllers_.end(), auto it = std::find_if(
violated_controllers_.begin(), violated_controllers_.end(),
[&](const FuzzyController &c) { return c.id == controller.id; }); [&](const FuzzyController &c) { return c.id == controller.id; });
if (it == violated_controllers_.end()) { if (it == violated_controllers_.end()) {
violated_controllers_.push_back(controller); violated_controllers_.push_back(controller);
} }
} }
float Population::get_effective_fitness(const FuzzyController& controller, float training_progress) const { float Population::get_effective_fitness(const FuzzyController &controller,
float training_progress) const {
float recent_avg = 0.0f; float recent_avg = 0.0f;
if (!controller.fitness_history.empty()) { if (!controller.fitness_history.empty()) {
float sum = 0.0f; float sum = 0.0f;
for (float f : controller.fitness_history) sum += f; for (float f : controller.fitness_history)
sum += f;
recent_avg = sum / controller.fitness_history.size(); recent_avg = sum / controller.fitness_history.size();
} }
float lifetime_avg = 0.0f; float lifetime_avg = 0.0f;
if (controller.evaluation_count > 0) { if (controller.evaluation_count > 0) {
lifetime_avg = controller.lifetime_fitness / static_cast<float>(controller.evaluation_count); lifetime_avg = controller.lifetime_fitness /
static_cast<float>(controller.evaluation_count);
} }
float alpha = 0.2f + 0.6f * training_progress; float alpha = 0.2f + 0.6f * training_progress;
return alpha * recent_avg + (1.0f - alpha) * lifetime_avg; return alpha * recent_avg + (1.0f - alpha) * lifetime_avg;
} }
void Population::evolve(float current_loss, float velocity, float training_progress) { void Population::evolve(float current_loss, float velocity,
float training_progress) {
static thread_local std::mt19937 rng{std::random_device{}()}; static thread_local std::mt19937 rng{std::random_device{}()};
std::uniform_real_distribution<float> coin(0.0f, 1.0f); std::uniform_real_distribution<float> coin(0.0f, 1.0f);
if (gladiators_.empty()) return; if (gladiators_.empty())
return;
FuzzyController &worst = get_worst_active(); FuzzyController &worst = get_worst_active();
FuzzyController &best_active = get_best_active(); FuzzyController &best_active = get_best_active();
@@ -223,7 +241,10 @@ void Population::evolve(float current_loss, float velocity, float training_progr
// Update behavioral archive for novelty search // Update behavioral archive for novelty search
if (best_active.fitness > -999.0f) { if (best_active.fitness > -999.0f) {
std::vector<float> behavior(best_active.genome.weights.begin(), best_active.genome.weights.begin() + std::min(20, static_cast<int>(best_active.genome.weights.size()))); std::vector<float> behavior(
best_active.genome.weights.begin(),
best_active.genome.weights.begin() +
std::min(20, static_cast<int>(best_active.genome.weights.size())));
behavioral_archive_.push_back(behavior); behavioral_archive_.push_back(behavior);
if (behavioral_archive_.size() > BEHAVIORAL_ARCHIVE_SIZE) { if (behavioral_archive_.size() > BEHAVIORAL_ARCHIVE_SIZE) {
behavioral_archive_.erase(behavioral_archive_.begin()); behavioral_archive_.erase(behavioral_archive_.begin());
@@ -256,7 +277,8 @@ void Population::evolve(float current_loss, float velocity, float training_progr
} }
float violator_prob = 0.1f; float violator_prob = 0.1f;
if (link_violator_) { if (link_violator_) {
violator_prob = std::max(0.0f, std::min(0.5f, (current_loss - 1.0f) / 4.0f)); violator_prob =
std::max(0.0f, std::min(0.5f, (current_loss - 1.0f) / 4.0f));
} }
// Select parent // Select parent
@@ -265,10 +287,12 @@ void Population::evolve(float current_loss, float velocity, float training_progr
float roll = coin(rng); float roll = coin(rng);
if (roll < elite_prob && !elites.empty()) { if (roll < elite_prob && !elites.empty()) {
std::uniform_int_distribution<int> elite_dist(0, static_cast<int>(elites.size()) - 1); std::uniform_int_distribution<int> elite_dist(
0, static_cast<int>(elites.size()) - 1);
parent = elites[elite_dist(rng)]; parent = elites[elite_dist(rng)];
partner_pool = elites; partner_pool = elites;
} else if (roll < elite_prob + violator_prob && !violated_controllers_.empty()) { } else if (roll < elite_prob + violator_prob &&
!violated_controllers_.empty()) {
parent = &best_active; parent = &best_active;
// Filter living violators // Filter living violators
for (auto &v : violated_controllers_) { for (auto &v : violated_controllers_) {
@@ -281,13 +305,15 @@ void Population::evolve(float current_loss, float velocity, float training_progr
} }
if (partner_pool.empty()) { if (partner_pool.empty()) {
// Fallback // Fallback
for (size_t i = 0; i < std::min(static_cast<size_t>(10), gladiators_.size()); ++i) { for (size_t i = 0;
i < std::min(static_cast<size_t>(10), gladiators_.size()); ++i) {
partner_pool.push_back(&gladiators_[i]); partner_pool.push_back(&gladiators_[i]);
} }
} }
} else { } else {
parent = &best_active; parent = &best_active;
for (size_t i = 0; i < std::min(static_cast<size_t>(10), gladiators_.size()); ++i) { for (size_t i = 0;
i < std::min(static_cast<size_t>(10), gladiators_.size()); ++i) {
partner_pool.push_back(&gladiators_[i]); partner_pool.push_back(&gladiators_[i]);
} }
} }
@@ -295,7 +321,8 @@ void Population::evolve(float current_loss, float velocity, float training_progr
// Crossover or mutation // Crossover or mutation
FuzzyController child; FuzzyController child;
if (coin(rng) < 0.7f && partner_pool.size() > 1) { if (coin(rng) < 0.7f && partner_pool.size() > 1) {
std::uniform_int_distribution<int> pool_dist(0, static_cast<int>(partner_pool.size()) - 1); std::uniform_int_distribution<int> pool_dist(
0, static_cast<int>(partner_pool.size()) - 1);
FuzzyController *partner = partner_pool[pool_dist(rng)]; FuzzyController *partner = partner_pool[pool_dist(rng)];
if (partner->id == parent->id) { if (partner->id == parent->id) {
// Pick another if possible // Pick another if possible
@@ -346,7 +373,8 @@ void Population::evolve(float current_loss, float velocity, float training_progr
// Banach-Tarski Fission // Banach-Tarski Fission
if (use_banach_fission_ && coin(rng) < 0.2f && !elites.empty()) { if (use_banach_fission_ && coin(rng) < 0.2f && !elites.empty()) {
auto *prime_elite = elites[0]; auto *prime_elite = elites[0];
auto fission_pair = prime_elite->banach_tarski_fission(phase_phoenix_intensity); auto fission_pair =
prime_elite->banach_tarski_fission(phase_phoenix_intensity);
// Find second worst // Find second worst
FuzzyController *second_worst = nullptr; FuzzyController *second_worst = nullptr;
@@ -361,7 +389,9 @@ void Population::evolve(float current_loss, float velocity, float training_progr
// Replace worst and second_worst with plus and minus child // Replace worst and second_worst with plus and minus child
if (second_worst) { if (second_worst) {
uint64_t sw_id = second_worst->id; uint64_t sw_id = second_worst->id;
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), [&](const FuzzyController& c) { return c.id == sw_id; }); auto it =
std::find_if(gladiators_.begin(), gladiators_.end(),
[&](const FuzzyController &c) { return c.id == sw_id; });
if (it != gladiators_.end()) { if (it != gladiators_.end()) {
gladiators_.erase(it); gladiators_.erase(it);
} }
@@ -369,7 +399,9 @@ void Population::evolve(float current_loss, float velocity, float training_progr
} }
uint64_t w_id = worst.id; uint64_t w_id = worst.id;
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), [&](const FuzzyController& c) { return c.id == w_id; }); auto it =
std::find_if(gladiators_.begin(), gladiators_.end(),
[&](const FuzzyController &c) { return c.id == w_id; });
if (it != gladiators_.end()) { if (it != gladiators_.end()) {
gladiators_.erase(it); gladiators_.erase(it);
} }
@@ -377,14 +409,17 @@ void Population::evolve(float current_loss, float velocity, float training_progr
} else { } else {
// Phoenix Rebirth or Standard replacement // Phoenix Rebirth or Standard replacement
uint64_t w_id = worst.id; uint64_t w_id = worst.id;
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), [&](const FuzzyController& c) { return c.id == w_id; }); auto it =
std::find_if(gladiators_.begin(), gladiators_.end(),
[&](const FuzzyController &c) { return c.id == w_id; });
if (it != gladiators_.end()) { if (it != gladiators_.end()) {
gladiators_.erase(it); gladiators_.erase(it);
} }
if (coin(rng) < 0.1f && !elites.empty()) { if (coin(rng) < 0.1f && !elites.empty()) {
auto *prime_elite = elites[0]; auto *prime_elite = elites[0];
gladiators_.push_back(prime_elite->create_orthogonal_child(phase_phoenix_intensity)); gladiators_.push_back(
prime_elite->create_orthogonal_child(phase_phoenix_intensity));
} else { } else {
gladiators_.push_back(child); gladiators_.push_back(child);
} }
@@ -411,7 +446,8 @@ void Population::evolve(float current_loss, float velocity, float training_progr
void Population::resize(int target_size, float training_progress) { void Population::resize(int target_size, float training_progress) {
int current_size = static_cast<int>(gladiators_.size()); int current_size = static_cast<int>(gladiators_.size());
if (current_size == target_size) return; if (current_size == target_size)
return;
static thread_local std::mt19937 rng{std::random_device{}()}; static thread_local std::mt19937 rng{std::random_device{}()};
@@ -430,7 +466,8 @@ void Population::resize(int target_size, float training_progress) {
candidates.push_back({get_effective_fitness(g, training_progress), &g}); candidates.push_back({get_effective_fitness(g, training_progress), &g});
} }
std::sort(candidates.begin(), candidates.end(), std::sort(candidates.begin(), candidates.end(),
[](const std::pair<float, FuzzyController*>& a, const std::pair<float, FuzzyController*>& b) { [](const std::pair<float, FuzzyController *> &a,
const std::pair<float, FuzzyController *> &b) {
return a.first > b.first; return a.first > b.first;
}); });
@@ -465,17 +502,21 @@ void Population::resize(int target_size, float training_progress) {
} }
std::sort(evaluated.begin(), evaluated.end(), std::sort(evaluated.begin(), evaluated.end(),
[this, training_progress](const FuzzyController* a, const FuzzyController* b) { [this, training_progress](const FuzzyController *a,
return get_effective_fitness(*a, training_progress) > get_effective_fitness(*b, training_progress); const FuzzyController *b) {
return get_effective_fitness(*a, training_progress) >
get_effective_fitness(*b, training_progress);
}); });
std::vector<FuzzyController> new_pop; std::vector<FuzzyController> new_pop;
new_pop.reserve(target_size); new_pop.reserve(target_size);
for (int i = 0; i < std::min(target_size, static_cast<int>(evaluated.size())); ++i) { for (int i = 0;
i < std::min(target_size, static_cast<int>(evaluated.size())); ++i) {
new_pop.push_back(*evaluated[i]); new_pop.push_back(*evaluated[i]);
} }
int remaining = target_size - static_cast<int>(new_pop.size()); int remaining = target_size - static_cast<int>(new_pop.size());
for (int i = 0; i < std::min(remaining, static_cast<int>(unevaluated.size())); ++i) { for (int i = 0;
i < std::min(remaining, static_cast<int>(unevaluated.size())); ++i) {
new_pop.push_back(*unevaluated[i]); new_pop.push_back(*unevaluated[i]);
} }
@@ -489,14 +530,16 @@ void Population::calm_down() {
} }
float Population::get_diversity_index() const { float Population::get_diversity_index() const {
if (gladiators_.size() < 2) return 0.0f; if (gladiators_.size() < 2)
return 0.0f;
float sum_dist = 0.0f; float sum_dist = 0.0f;
int count = 0; int count = 0;
for (size_t i = 0; i < gladiators_.size(); ++i) { for (size_t i = 0; i < gladiators_.size(); ++i) {
for (size_t j = i + 1; j < gladiators_.size(); ++j) { for (size_t j = i + 1; j < gladiators_.size(); ++j) {
float dist_sq = 0.0f; float dist_sq = 0.0f;
for (size_t w = 0; w < GENOME_SIZE; ++w) { for (size_t w = 0; w < GENOME_SIZE; ++w) {
float diff = gladiators_[i].genome.weights[w] - gladiators_[j].genome.weights[w]; float diff =
gladiators_[i].genome.weights[w] - gladiators_[j].genome.weights[w];
dist_sq += diff * diff; dist_sq += diff * diff;
} }
sum_dist += std::sqrt(dist_sq); sum_dist += std::sqrt(dist_sq);
@@ -521,13 +564,15 @@ std::vector<FuzzyController*> Population::get_elites() {
for (auto &g : gladiators_) { for (auto &g : gladiators_) {
float effective_fitness = 0.0f; float effective_fitness = 0.0f;
if (elite_strategy_ == EliteStrategy::AgePenalty) { if (elite_strategy_ == EliteStrategy::AgePenalty) {
effective_fitness = g.fitness / std::log(static_cast<float>(g.age) + 2.0f); effective_fitness =
g.fitness / std::log(static_cast<float>(g.age) + 2.0f);
} else if (elite_strategy_ == EliteStrategy::EMA) { } else if (elite_strategy_ == EliteStrategy::EMA) {
effective_fitness = g.ema_fitness; effective_fitness = g.ema_fitness;
} else if (elite_strategy_ == EliteStrategy::Rolling) { } else if (elite_strategy_ == EliteStrategy::Rolling) {
if (!g.fitness_history.empty()) { if (!g.fitness_history.empty()) {
float sum = 0.0f; float sum = 0.0f;
for (float f : g.fitness_history) sum += f; for (float f : g.fitness_history)
sum += f;
effective_fitness = sum / g.fitness_history.size(); effective_fitness = sum / g.fitness_history.size();
} else { } else {
effective_fitness = g.fitness; effective_fitness = g.fitness;
@@ -539,7 +584,8 @@ std::vector<FuzzyController*> Population::get_elites() {
} }
std::sort(candidates.begin(), candidates.end(), std::sort(candidates.begin(), candidates.end(),
[](const std::pair<float, FuzzyController*>& a, const std::pair<float, FuzzyController*>& b) { [](const std::pair<float, FuzzyController *> &a,
const std::pair<float, FuzzyController *> &b) {
return a.first > b.first; return a.first > b.first;
}); });
@@ -552,7 +598,8 @@ std::vector<FuzzyController*> Population::get_elites() {
} }
void Population::add_to_repository(const FuzzyController &controller) { void Population::add_to_repository(const FuzzyController &controller) {
auto it = std::lower_bound(repository_.begin(), repository_.end(), controller, auto it =
std::lower_bound(repository_.begin(), repository_.end(), controller,
[](const FuzzyController &a, const FuzzyController &b) { [](const FuzzyController &a, const FuzzyController &b) {
return a.fitness > b.fitness; return a.fitness > b.fitness;
}); });

View File

@@ -5,14 +5,16 @@ namespace fces {
SpectralSensor::SpectralSensor(torch::nn::Module & /*model*/) {} SpectralSensor::SpectralSensor(torch::nn::Module & /*model*/) {}
void SpectralSensor::track_layer(const std::string& name, const torch::Tensor& weight) { void SpectralSensor::track_layer(const std::string &name,
const torch::Tensor &weight) {
if (weight.dim() >= 2) { if (weight.dim() >= 2) {
layer_ranks_[name] = compute_effective_rank(weight); layer_ranks_[name] = compute_effective_rank(weight);
} }
} }
float SpectralSensor::get_global_rank() const { float SpectralSensor::get_global_rank() const {
if (layer_ranks_.empty()) return 0.0f; if (layer_ranks_.empty())
return 0.0f;
float sum = 0.0f; float sum = 0.0f;
for (const auto &[_, rank] : layer_ranks_) { for (const auto &[_, rank] : layer_ranks_) {
sum += rank; sum += rank;
@@ -20,9 +22,7 @@ float SpectralSensor::get_global_rank() const {
return sum / static_cast<float>(layer_ranks_.size()); return sum / static_cast<float>(layer_ranks_.size());
} }
void SpectralSensor::reset() { void SpectralSensor::reset() { layer_ranks_.clear(); }
layer_ranks_.clear();
}
float SpectralSensor::compute_effective_rank(const torch::Tensor &weight) { float SpectralSensor::compute_effective_rank(const torch::Tensor &weight) {
// SVD-based effective rank (Shannon entropy of normalized singular values) // SVD-based effective rank (Shannon entropy of normalized singular values)
@@ -34,7 +34,8 @@ float SpectralSensor::compute_effective_rank(const torch::Tensor& weight) {
return std::exp(entropy); return std::exp(entropy);
} }
float SpectralController::compute_alpha(float global_rank, float grokking_coefficient) const { float SpectralController::compute_alpha(float global_rank,
float grokking_coefficient) const {
return global_rank * grokking_coefficient; return global_rank * grokking_coefficient;
} }

View File

@@ -1,6 +1,6 @@
#include "fces/telemetry.hpp" #include "fces/telemetry.hpp"
#include <iostream>
#include <chrono> #include <chrono>
#include <iostream>
namespace fces { namespace fces {
@@ -11,19 +11,22 @@ Telemetry& Telemetry::get() {
void Telemetry::info(const std::string &event, const std::string &detail) { void Telemetry::info(const std::string &event, const std::string &detail) {
std::cout << "[INFO] " << event; std::cout << "[INFO] " << event;
if (!detail.empty()) std::cout << " | " << detail; if (!detail.empty())
std::cout << " | " << detail;
std::cout << std::endl; std::cout << std::endl;
} }
void Telemetry::warning(const std::string &event, const std::string &detail) { void Telemetry::warning(const std::string &event, const std::string &detail) {
std::cerr << "[WARN] " << event; std::cerr << "[WARN] " << event;
if (!detail.empty()) std::cerr << " | " << detail; if (!detail.empty())
std::cerr << " | " << detail;
std::cerr << std::endl; std::cerr << std::endl;
} }
void Telemetry::error(const std::string &event, const std::string &detail) { void Telemetry::error(const std::string &event, const std::string &detail) {
std::cerr << "[ERROR] " << event; std::cerr << "[ERROR] " << event;
if (!detail.empty()) std::cerr << " | " << detail; if (!detail.empty())
std::cerr << " | " << detail;
std::cerr << std::endl; std::cerr << std::endl;
} }

View File

@@ -1,5 +1,5 @@
#include <gtest/gtest.h>
#include "fces/controller.hpp" #include "fces/controller.hpp"
#include <gtest/gtest.h>
using namespace fces; using namespace fces;
@@ -40,7 +40,8 @@ TEST(ControllerTest, Crossover) {
TEST(ControllerTest, DecideUpdate) { TEST(ControllerTest, DecideUpdate) {
FuzzyController ctrl; FuzzyController ctrl;
std::vector<std::vector<float>> stats = {{0.1f, 0.2f, 0.3f, 0.4f, 0.5f}}; std::vector<std::vector<float>> stats = {{0.1f, 0.2f, 0.3f, 0.4f, 0.5f}};
auto actions = ctrl.decide_update(stats, 0.0f, 0.5f, 0.0f, 0.1f, 0.0f, 0.0f, 1.0f, 0.0f); auto actions =
ctrl.decide_update(stats, 0.0f, 0.5f, 0.0f, 0.1f, 0.0f, 0.0f, 1.0f, 0.0f);
EXPECT_EQ(actions.size(0), 1); EXPECT_EQ(actions.size(0), 1);
EXPECT_EQ(actions.size(1), GENOME_OUTPUT_DIM); EXPECT_EQ(actions.size(1), GENOME_OUTPUT_DIM);
} }

View File

@@ -1,5 +1,5 @@
#include <gtest/gtest.h>
#include "fces/fitness.hpp" #include "fces/fitness.hpp"
#include <gtest/gtest.h>
using namespace fces; using namespace fces;
@@ -14,7 +14,8 @@ TEST(RunningStatsTest, BasicUpdate) {
TEST(RunningStatsTest, ZScore) { TEST(RunningStatsTest, ZScore) {
RunningStats stats; RunningStats stats;
for (int i = 0; i < 100; ++i) stats.update(static_cast<float>(i)); for (int i = 0; i < 100; ++i)
stats.update(static_cast<float>(i));
float z = stats.z_score(50.0f); float z = stats.z_score(50.0f);
EXPECT_NEAR(z, 0.0f, 0.1f); EXPECT_NEAR(z, 0.0f, 0.1f);
} }

View File

@@ -1,13 +1,14 @@
#include "fces/optimizer.hpp"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <torch/torch.h> #include <torch/torch.h>
#include "fces/optimizer.hpp"
using namespace fces; using namespace fces;
TEST(OptimizerTest, Construction) { TEST(OptimizerTest, Construction) {
auto model = torch::nn::Linear(10, 5); auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params; std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p); for (auto &p : model->parameters())
params.push_back(p);
FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f)); FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f));
EXPECT_EQ(opt.step_count(), 0); EXPECT_EQ(opt.step_count(), 0);
@@ -16,7 +17,8 @@ TEST(OptimizerTest, Construction) {
TEST(OptimizerTest, StepUpdatesCounter) { TEST(OptimizerTest, StepUpdatesCounter) {
auto model = torch::nn::Linear(10, 5); auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params; std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p); for (auto &p : model->parameters())
params.push_back(p);
FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f)); FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f));
@@ -33,7 +35,8 @@ TEST(OptimizerTest, StepUpdatesCounter) {
TEST(OptimizerTest, UpdateFitness) { TEST(OptimizerTest, UpdateFitness) {
auto model = torch::nn::Linear(10, 5); auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params; std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p); for (auto &p : model->parameters())
params.push_back(p);
FCESOptimizer opt(params); FCESOptimizer opt(params);
opt.update_fitness(3.0f); opt.update_fitness(3.0f);

View File

@@ -1,5 +1,5 @@
#include <gtest/gtest.h>
#include "fces/population.hpp" #include "fces/population.hpp"
#include <gtest/gtest.h>
using namespace fces; using namespace fces;
@@ -9,8 +9,8 @@ TEST(PopulationTest, Construction) {
} }
TEST(PopulationTest, DirectConstruction) { TEST(PopulationTest, DirectConstruction) {
Population pop(200, 10000, EliteStrategy::Cumulative, Population pop(200, 10000, EliteStrategy::Cumulative, false, false, false,
false, false, false, false, false, true); false, false, true);
EXPECT_EQ(pop.size(), 1); EXPECT_EQ(pop.size(), 1);
} }