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,45 +1,47 @@
#include <benchmark/benchmark.h>
#include "fces/population.hpp"
#include "fces/controller.hpp"
#include "fces/population.hpp"
#include <benchmark/benchmark.h>
using namespace fces;
static void BM_ControllerDecideUpdate(benchmark::State& state) {
FuzzyController ctrl;
std::vector<std::vector<float>> stats(state.range(0), {0.1f, 0.2f, 0.3f, 0.4f, 0.5f});
static void BM_ControllerDecideUpdate(benchmark::State &state) {
FuzzyController ctrl;
std::vector<std::vector<float>> stats(state.range(0),
{0.1f, 0.2f, 0.3f, 0.4f, 0.5f});
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);
benchmark::DoNotOptimize(actions);
}
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);
benchmark::DoNotOptimize(actions);
}
}
BENCHMARK(BM_ControllerDecideUpdate)->Arg(10)->Arg(50)->Arg(200);
static void BM_Evolve(benchmark::State& state) {
Population pop(state.range(0));
static void BM_Evolve(benchmark::State &state) {
Population pop(state.range(0));
for (auto _ : state) {
pop.evolve(2.0f, -0.01f, 0.5f);
}
for (auto _ : state) {
pop.evolve(2.0f, -0.01f, 0.5f);
}
}
BENCHMARK(BM_Evolve)->Arg(50)->Arg(100)->Arg(200);
static void BM_Mutation(benchmark::State& state) {
FuzzyController ctrl;
static void BM_Mutation(benchmark::State &state) {
FuzzyController ctrl;
for (auto _ : state) {
auto child = ctrl.mutate(2.0f, 1.0f);
benchmark::DoNotOptimize(child);
}
for (auto _ : state) {
auto child = ctrl.mutate(2.0f, 1.0f);
benchmark::DoNotOptimize(child);
}
}
BENCHMARK(BM_Mutation);
static void BM_Crossover(benchmark::State& state) {
FuzzyController a, b;
static void BM_Crossover(benchmark::State &state) {
FuzzyController a, b;
for (auto _ : state) {
auto child = a.crossover(b);
benchmark::DoNotOptimize(child);
}
for (auto _ : state) {
auto child = a.crossover(b);
benchmark::DoNotOptimize(child);
}
}
BENCHMARK(BM_Crossover);

View File

@@ -1,25 +1,26 @@
#include "fces/optimizer.hpp"
#include <benchmark/benchmark.h>
#include <torch/torch.h>
#include "fces/optimizer.hpp"
using namespace fces;
static void BM_OptimizerStep(benchmark::State& state) {
auto model = torch::nn::Linear(state.range(0), state.range(0) / 2);
std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p);
static void BM_OptimizerStep(benchmark::State &state) {
auto model = torch::nn::Linear(state.range(0), state.range(0) / 2);
std::vector<torch::Tensor> params;
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));
auto x = torch::randn({8, state.range(0)});
auto x = torch::randn({8, state.range(0)});
for (auto _ : state) {
auto y = model->forward(x);
auto loss = y.sum();
loss.backward();
opt.step();
opt.zero_grad();
benchmark::DoNotOptimize(loss);
}
for (auto _ : state) {
auto y = model->forward(x);
auto loss = y.sum();
loss.backward();
opt.step();
opt.zero_grad();
benchmark::DoNotOptimize(loss);
}
}
BENCHMARK(BM_OptimizerStep)->Arg(64)->Arg(256)->Arg(1024);

View File

@@ -3,59 +3,57 @@
* @brief Example: train a small neural network with FCES via libtorch.
*/
#include "fces/optimizer.hpp"
#include <iostream>
#include <torch/torch.h>
#include "fces/optimizer.hpp"
struct TinyNet : torch::nn::Module {
torch::nn::Linear fc1{nullptr}, fc2{nullptr};
torch::nn::Linear fc1{nullptr}, fc2{nullptr};
TinyNet() {
fc1 = register_module("fc1", torch::nn::Linear(10, 32));
fc2 = register_module("fc2", torch::nn::Linear(32, 1));
}
TinyNet() {
fc1 = register_module("fc1", torch::nn::Linear(10, 32));
fc2 = register_module("fc2", torch::nn::Linear(32, 1));
}
torch::Tensor forward(torch::Tensor x) {
x = torch::relu(fc1->forward(x));
return fc2->forward(x);
}
torch::Tensor forward(torch::Tensor x) {
x = torch::relu(fc1->forward(x));
return fc2->forward(x);
}
};
int main() {
auto model = std::make_shared<TinyNet>();
auto model = std::make_shared<TinyNet>();
std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p);
std::vector<torch::Tensor> params;
for (auto &p : model->parameters())
params.push_back(p);
fces::FCESOptimizer optimizer(
params,
fces::FCESConfig{}
.set_lr(1.6e-3f)
.set_population_size(200)
.set_total_steps(1000)
);
fces::FCESOptimizer optimizer(params, fces::FCESConfig{}
.set_lr(1.6e-3f)
.set_population_size(200)
.set_total_steps(1000));
// Generate synthetic regression data
auto x_train = torch::randn({100, 10});
auto y_train = torch::sin(x_train.sum(1, true));
// Generate synthetic regression data
auto x_train = torch::randn({100, 10});
auto y_train = torch::sin(x_train.sum(1, true));
for (int epoch = 0; epoch < 100; ++epoch) {
optimizer.zero_grad();
auto pred = model->forward(x_train);
auto loss = torch::mse_loss(pred, y_train);
loss.backward();
optimizer.step();
optimizer.update_fitness(loss.item<float>());
for (int epoch = 0; epoch < 100; ++epoch) {
optimizer.zero_grad();
auto pred = model->forward(x_train);
auto loss = torch::mse_loss(pred, y_train);
loss.backward();
optimizer.step();
optimizer.update_fitness(loss.item<float>());
if (epoch % 10 == 0) {
std::cout << "Epoch " << epoch
<< " | Loss: " << loss.item<float>() << std::endl;
}
if (epoch % 10 == 0) {
std::cout << "Epoch " << epoch << " | Loss: " << loss.item<float>()
<< std::endl;
}
}
std::cout << "\nTraining complete. Final loss: "
<< torch::mse_loss(model->forward(x_train), y_train).item<float>()
<< std::endl;
std::cout << "\nTraining complete. Final loss: "
<< torch::mse_loss(model->forward(x_train), y_train).item<float>()
<< std::endl;
return 0;
return 0;
}

View File

@@ -3,34 +3,33 @@
* @brief Minimal example: optimize a quadratic function with FCES.
*/
#include "fces/optimizer.hpp"
#include <iostream>
#include <torch/torch.h>
#include "fces/optimizer.hpp"
int main() {
// Target: minimize f(x) = ||x - target||^2
auto target = torch::tensor({1.0f, 2.0f, 3.0f, 4.0f, 5.0f});
auto x = torch::randn({5}, torch::requires_grad());
// Target: minimize f(x) = ||x - target||^2
auto target = torch::tensor({1.0f, 2.0f, 3.0f, 4.0f, 5.0f});
auto x = torch::randn({5}, torch::requires_grad());
std::vector<torch::Tensor> params = {x};
fces::FCESOptimizer optimizer(params, fces::FCESConfig{}.set_lr(1e-2f));
std::vector<torch::Tensor> params = {x};
fces::FCESOptimizer optimizer(params, fces::FCESConfig{}.set_lr(1e-2f));
for (int step = 0; step < 500; ++step) {
optimizer.zero_grad();
auto loss = (x - target).pow(2).sum();
loss.backward();
optimizer.step();
optimizer.update_fitness(loss.item<float>());
for (int step = 0; step < 500; ++step) {
optimizer.zero_grad();
auto loss = (x - target).pow(2).sum();
loss.backward();
optimizer.step();
optimizer.update_fitness(loss.item<float>());
if (step % 50 == 0) {
std::cout << "Step " << step
<< " | Loss: " << loss.item<float>()
<< " | x: " << x << std::endl;
}
if (step % 50 == 0) {
std::cout << "Step " << step << " | Loss: " << loss.item<float>()
<< " | x: " << x << std::endl;
}
}
std::cout << "\nFinal x: " << x << std::endl;
std::cout << "Target: " << target << std::endl;
std::cout << "\nFinal x: " << x << std::endl;
std::cout << "Target: " << target << std::endl;
return 0;
return 0;
}

View File

@@ -3,112 +3,124 @@
* @brief Example showcasing telemetry instrumentation and model inference.
*/
#include <iostream>
#include <chrono>
#include <torch/torch.h>
#include "fces/optimizer.hpp"
#include "fces/telemetry.hpp"
#include <chrono>
#include <iostream>
#include <torch/torch.h>
// Define a simple neural network for nonlinear regression: y = x^2
struct RegressionNet : torch::nn::Module {
torch::nn::Linear fc1{nullptr}, fc2{nullptr};
torch::nn::Linear fc1{nullptr}, fc2{nullptr};
RegressionNet() {
fc1 = register_module("fc1", torch::nn::Linear(1, 16));
fc2 = register_module("fc2", torch::nn::Linear(16, 1));
}
RegressionNet() {
fc1 = register_module("fc1", torch::nn::Linear(1, 16));
fc2 = register_module("fc2", torch::nn::Linear(16, 1));
}
torch::Tensor forward(torch::Tensor x) {
x = torch::tanh(fc1->forward(x));
return fc2->forward(x);
}
torch::Tensor forward(torch::Tensor x) {
x = torch::tanh(fc1->forward(x));
return fc2->forward(x);
}
};
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
auto model = std::make_shared<RegressionNet>();
// 1. Create Model and Data
auto model = std::make_shared<RegressionNet>();
// Generate training data: x in [-2, 2], y = x^2 + noise
auto x_train = torch::linspace(-2.0, 2.0, 100).unsqueeze(1);
auto y_train = x_train.pow(2) + 0.1 * torch::randn({100, 1});
// Generate training data: x in [-2, 2], y = x^2 + noise
auto x_train = torch::linspace(-2.0, 2.0, 100).unsqueeze(1);
auto y_train = x_train.pow(2) + 0.1 * torch::randn({100, 1});
// 2. Configure Optimizer
std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) {
params.push_back(p);
// 2. Configure Optimizer
std::vector<torch::Tensor> params;
for (auto &p : model->parameters()) {
params.push_back(p);
}
fces::FCESOptimizer optimizer(
params,
fces::FCESConfig{}.set_lr(2e-3f).set_population_size(150).set_total_steps(
100));
fces::Telemetry::get().info("training_start",
"Beginning neural net optimization with FCES.");
auto start_train = std::chrono::high_resolution_clock::now();
// 3. Optimization Loop
for (int epoch = 0; epoch <= 100; ++epoch) {
optimizer.zero_grad();
auto pred = model->forward(x_train);
auto loss = torch::mse_loss(pred, y_train);
loss.backward();
optimizer.step();
optimizer.update_fitness(loss.item<float>());
if (epoch % 20 == 0) {
fces::Telemetry::get().info(
"epoch_checkpoint", "Epoch " + std::to_string(epoch) + " | Loss: " +
std::to_string(loss.item<float>()));
}
}
fces::FCESOptimizer optimizer(
params,
fces::FCESConfig{}
.set_lr(2e-3f)
.set_population_size(150)
.set_total_steps(100)
);
auto end_train = std::chrono::high_resolution_clock::now();
double train_duration =
std::chrono::duration<double, std::milli>(end_train - start_train)
.count();
fces::Telemetry::get().info("training_start", "Beginning neural net optimization with FCES.");
fces::Telemetry::get().info("training_complete",
"Duration: " + std::to_string(train_duration) +
" ms");
auto start_train = std::chrono::high_resolution_clock::now();
// 4. Inference Phase
fces::Telemetry::get().info("inference_phase_start",
"Evaluating model on new test inputs.");
// 3. Optimization Loop
for (int epoch = 0; epoch <= 100; ++epoch) {
optimizer.zero_grad();
auto pred = model->forward(x_train);
auto loss = torch::mse_loss(pred, y_train);
loss.backward();
optimizer.step();
optimizer.update_fitness(loss.item<float>());
// Generate test inputs
auto x_test = torch::tensor({-1.5f, -0.5f, 0.0f, 0.5f, 1.5f}).unsqueeze(1);
auto y_expected = x_test.pow(2);
if (epoch % 20 == 0) {
fces::Telemetry::get().info("epoch_checkpoint",
"Epoch " + std::to_string(epoch) + " | Loss: " + std::to_string(loss.item<float>()));
}
}
// Switch model to evaluation mode
model->eval();
auto end_train = std::chrono::high_resolution_clock::now();
double train_duration = std::chrono::duration<double, std::milli>(end_train - start_train).count();
// Run inference and measure latency
auto start_inf = std::chrono::high_resolution_clock::now();
torch::Tensor y_pred;
{
torch::NoGradGuard no_grad;
y_pred = model->forward(x_test);
}
auto end_inf = std::chrono::high_resolution_clock::now();
double inf_duration =
std::chrono::duration<double, std::milli>(end_inf - start_inf).count();
fces::Telemetry::get().info("training_complete",
"Duration: " + std::to_string(train_duration) + " ms");
// Log telemetry for inference performance
fces::Telemetry::get().info(
"inference_perf", "Inputs: " + std::to_string(x_test.size(0)) +
" | Latency: " + std::to_string(inf_duration) +
" ms");
// 4. Inference Phase
fces::Telemetry::get().info("inference_phase_start", "Evaluating model on new test inputs.");
// Print predictions and expected values side-by-side
std::cout << "\n================ INFERENCE RESULTS ================"
<< 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) {
float x_val = x_test[i][0].item<float>();
float pred_val = y_pred[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::cout << "====================================================\n"
<< std::endl;
// Generate test inputs
auto x_test = torch::tensor({-1.5f, -0.5f, 0.0f, 0.5f, 1.5f}).unsqueeze(1);
auto y_expected = x_test.pow(2);
// Switch model to evaluation mode
model->eval();
// Run inference and measure latency
auto start_inf = std::chrono::high_resolution_clock::now();
torch::Tensor y_pred;
{
torch::NoGradGuard no_grad;
y_pred = model->forward(x_test);
}
auto end_inf = std::chrono::high_resolution_clock::now();
double inf_duration = std::chrono::duration<double, std::milli>(end_inf - start_inf).count();
// Log telemetry for inference performance
fces::Telemetry::get().info("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
std::cout << "\n================ INFERENCE RESULTS ================" << 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) {
float x_val = x_test[i][0].item<float>();
float pred_val = y_pred[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::cout << "====================================================\n" << std::endl;
fces::Telemetry::get().info("app_finish", "Exiting demo successfully.");
return 0;
fces::Telemetry::get().info("app_finish", "Exiting demo successfully.");
return 0;
}

View File

@@ -18,65 +18,80 @@ namespace fces {
* All fields have sensible defaults matching the Python V49.0 implementation.
*/
struct FCESConfig {
// Learning rate (V49 optimal default)
float lr = 1.6e-3f;
// Learning rate (V49 optimal default)
float lr = 1.6e-3f;
// Weight decay coefficient
float weight_decay = 0.0f;
// Weight decay coefficient
float weight_decay = 0.0f;
// Population size for evolutionary search
int population_size = 200;
// Population size for evolutionary search
int population_size = 200;
// Total training steps (for progress-aware scheduling)
int total_steps = 5000;
// Total training steps (for progress-aware scheduling)
int total_steps = 5000;
// Signal mode for loss velocity calculation
std::string signal_mode = "relative";
// Signal mode for loss velocity calculation
std::string signal_mode = "relative";
// Grokking awareness coefficient (0.0 = disabled)
float grokking_coefficient = 0.1f;
// Grokking awareness coefficient (0.0 = disabled)
float grokking_coefficient = 0.1f;
// Spectral sensing frequency (every N steps)
int spectral_frequency = 10;
// 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;
// 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;
// Trust region clipping
float trust_region_clip = 0.01f;
// Rollback threshold
float rollback_threshold = 1.5f;
// Rollback threshold
float rollback_threshold = 1.5f;
// Adaptive weight decay
bool adaptive_wd = false;
// Adaptive weight decay
bool adaptive_wd = false;
// Parasitic mode (gradient alignment reward)
bool parasitic_mode = false;
// Parasitic mode (gradient alignment reward)
bool parasitic_mode = false;
// Ablation mode: "", "force_sign", "force_grad"
std::string ablation_mode = "";
// Ablation mode: "", "force_sign", "force_grad"
std::string ablation_mode = "";
// Fractional factorial scoring (CRO trick)
bool use_fractional_scoring = false;
// Fractional factorial scoring (CRO trick)
bool use_fractional_scoring = false;
// Direct construction mode (pop_size=1)
bool direct_construction = false;
// Direct construction mode (pop_size=1)
bool direct_construction = false;
// Banach-Tarski fission
bool use_banach_fission = false;
// Banach-Tarski fission
bool use_banach_fission = false;
// Auto-population (stabilize on divergence)
bool auto_population = 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; }
// 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
} // namespace fces

View File

@@ -27,28 +27,29 @@ constexpr int GENOME_INPUT_DIM = 14;
constexpr int GENOME_HIDDEN_DIM = 8;
// 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
// 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_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;
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);
/// Initialize with random weights from a normal distribution
void randomize(std::mt19937 &rng);
/// Deep copy
Genome clone() const;
/// Deep copy
Genome clone() const;
};
/**
@@ -62,84 +63,81 @@ struct Genome {
*/
class FuzzyController {
public:
/// Unique identifier
uint64_t id;
/// Unique identifier
uint64_t id;
/// The neural genome
Genome genome;
/// 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;
/// 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";
/// Origin tracking
std::string origin = "random";
/// Trust region violation counter
int trust_violations = 0;
/// Trust region violation counter
int trust_violations = 0;
/// Rolling fitness history (for Phase 23 strategies)
std::vector<float> fitness_history;
/// Rolling fitness history (for Phase 23 strategies)
std::vector<float> fitness_history;
// ---------------------------------------------------------------
// Construction
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// Construction
// ---------------------------------------------------------------
FuzzyController();
explicit FuzzyController(Genome genome);
FuzzyController();
explicit FuzzyController(Genome genome);
// ---------------------------------------------------------------
// Core Operations
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// 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
);
/**
* 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
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// Evolutionary Operators
// ---------------------------------------------------------------
/// Create a mutated child
FuzzyController mutate(float current_loss, float sigma_scale = 1.0f) const;
/// 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;
/// 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;
/// 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;
/// 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_;
static std::atomic<uint64_t> next_id_;
static thread_local std::mt19937 rng_;
};
} // namespace fces
} // namespace fces

View File

@@ -21,34 +21,27 @@ namespace fces {
*/
class EvolutionManager {
public:
explicit EvolutionManager(
Population& population,
int selection_interval = 50,
bool auto_population = false,
bool direct_construction = false
);
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();
/// 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
);
/// 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;
/// Steps the active controller has been in control
int steps_active = 0;
/// Selection interval (how long a controller stays active)
int selection_interval;
/// Selection interval (how long a controller stays active)
int selection_interval;
private:
Population& population_;
bool auto_population_;
bool direct_construction_;
Population &population_;
bool auto_population_;
bool direct_construction_;
};
} // namespace fces
} // namespace fces

View File

@@ -2,14 +2,15 @@
/**
* @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
*/
#include <cmath>
#include <vector>
#include <string>
#include <vector>
namespace fces {
@@ -19,18 +20,18 @@ namespace fces {
*/
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 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();
void reset();
private:
int count_ = 0;
float mean_ = 0.0f;
float m2_ = 0.0f;
int count_ = 0;
float mean_ = 0.0f;
float m2_ = 0.0f;
};
/**
@@ -38,26 +39,27 @@ private:
*/
class FitnessEngine {
public:
explicit FitnessEngine(float grokking_coefficient = 0.1f);
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;
/**
* 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;
/**
* Compute Kibble-Zurek Mechanism damping factor.
* Prevents topological defects during phase transitions.
*/
float compute_kzm_damping(float spectral_alpha) const;
private:
float grokking_coefficient_;
float grokking_coefficient_;
};
/**
@@ -65,75 +67,76 @@ private:
*/
class FuzzySet {
public:
FuzzySet(std::string name, float a, float b, float c, float d) noexcept
: name_(std::move(name)), a_(a), b_(b), c_(c), d_(d) {}
FuzzySet(std::string name, float a, float b, float c, float d) noexcept
: name_(std::move(name)), a_(a), b_(b), c_(c), d_(d) {}
float membership(float x) const noexcept {
if (!std::isfinite(x)) {
return 0.0f;
}
if (x <= a_ || x >= d_) {
return 0.0f;
}
if (x >= b_ && x <= c_) {
return 1.0f;
}
if (x > a_ && x < b_) {
float range = b_ - a_;
return (x - a_) / (range > 0.0f ? range : 1e-9f);
}
if (x > c_ && x < d_) {
float range = d_ - c_;
return (d_ - x) / (range > 0.0f ? range : 1e-9f);
}
return 0.0f;
float membership(float x) const noexcept {
if (!std::isfinite(x)) {
return 0.0f;
}
if (x <= a_ || x >= d_) {
return 0.0f;
}
if (x >= b_ && x <= c_) {
return 1.0f;
}
if (x > a_ && x < b_) {
float range = b_ - a_;
return (x - a_) / (range > 0.0f ? range : 1e-9f);
}
if (x > c_ && x < d_) {
float range = d_ - c_;
return (d_ - x) / (range > 0.0f ? range : 1e-9f);
}
return 0.0f;
}
const std::string& name() const noexcept { return name_; }
const std::string &name() const noexcept { return name_; }
private:
std::string name_;
float a_;
float b_;
float c_;
float d_;
std::string name_;
float a_;
float b_;
float c_;
float d_;
};
/**
* Fitness metrics for multi-objective evaluation.
*/
struct FitnessMetrics {
float training_advantage = 0.0f;
float validation_advantage = 0.0f;
float grad_cv = 0.0f;
float sparsity_delta = 0.0f;
float consistency_gap = 0.0f;
float stable_rank = 0.0f;
float training_advantage = 0.0f;
float validation_advantage = 0.0f;
float grad_cv = 0.0f;
float sparsity_delta = 0.0f;
float consistency_gap = 0.0f;
float stable_rank = 0.0f;
};
/**
* FuzzyFitnessEvaluator — multi-objective fitness evaluation with fuzzy weighting.
* FuzzyFitnessEvaluator — multi-objective fitness evaluation with fuzzy
* weighting.
*/
class FuzzyFitnessEvaluator {
public:
FuzzyFitnessEvaluator() noexcept;
FuzzyFitnessEvaluator() noexcept;
float evaluate(const FitnessMetrics& metrics) const noexcept;
float evaluate(const FitnessMetrics &metrics) const noexcept;
private:
FuzzySet stability_set_;
FuzzySet train_set_;
FuzzySet val_set_;
FuzzySet sparsity_set_;
FuzzySet consistency_set_;
FuzzySet rank_set_;
FuzzySet stability_set_;
FuzzySet train_set_;
FuzzySet val_set_;
FuzzySet sparsity_set_;
FuzzySet consistency_set_;
FuzzySet rank_set_;
float w_stability_ = 0.2f;
float w_train_ = 0.2f;
float w_val_ = 0.3f;
float w_sparsity_ = 0.1f;
float w_consistency_ = 0.2f;
float w_rank_ = 0.1f;
float w_stability_ = 0.2f;
float w_train_ = 0.2f;
float w_val_ = 0.3f;
float w_sparsity_ = 0.1f;
float w_consistency_ = 0.2f;
float w_rank_ = 0.1f;
};
} // namespace fces
} // namespace fces

View File

@@ -5,17 +5,17 @@
* @brief FCESOptimizer — the main entry point. libtorch-compatible optimizer.
*/
#include <torch/torch.h>
#include <memory>
#include <vector>
#include <string>
#include <torch/torch.h>
#include <vector>
#include "config.hpp"
#include "population.hpp"
#include "fitness.hpp"
#include "evolution.hpp"
#include "spectral.hpp"
#include "fitness.hpp"
#include "oscillation.hpp"
#include "population.hpp"
#include "spectral.hpp"
#include "telemetry.hpp"
namespace fces {
@@ -24,7 +24,8 @@ namespace fces {
* FCESOptimizer — Fuzzy Controlled Evolutionary Search V49.0 (C++ Port).
*
* 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:
* optimizer.zero_grad();
* auto loss = model->forward(input);
@@ -32,73 +33,72 @@ namespace fces {
* optimizer.step();
* optimizer.update_fitness(loss.item<float>());
*/
struct FCESOptimizerOptions : public torch::optim::OptimizerCloneableOptions<FCESOptimizerOptions> {
explicit FCESOptimizerOptions(double lr = 0.01) : lr_(lr) {}
struct FCESOptimizerOptions
: public torch::optim::OptimizerCloneableOptions<FCESOptimizerOptions> {
explicit FCESOptimizerOptions(double lr = 0.01) : lr_(lr) {}
double get_lr() const override { return lr_; }
void set_lr(const double lr) override { lr_ = lr; }
double get_lr() const override { return lr_; }
void set_lr(const double lr) override { lr_ = lr; }
double lr_;
double lr_;
};
class FCESOptimizer : public torch::optim::Optimizer {
public:
explicit FCESOptimizer(
std::vector<torch::Tensor> params,
FCESConfig config = FCESConfig{}
);
explicit FCESOptimizer(std::vector<torch::Tensor> params,
FCESConfig config = FCESConfig{});
/// Perform a single optimization step
torch::Tensor step(LossClosure closure = nullptr) override;
/// Perform a single optimization step
torch::Tensor step(LossClosure closure = nullptr) override;
/// Update evolutionary fitness with current loss
void update_fitness(float loss);
/// Update evolutionary fitness with current loss
void update_fitness(float loss);
/// Backup model weights to CPU RAM
void backup_to_ram();
/// Backup model weights to CPU RAM
void backup_to_ram();
/// Restore model weights from CPU RAM backup
void restore_from_ram();
/// Restore model weights from CPU RAM backup
void restore_from_ram();
/// Get current step count
int step_count() const { return step_counter_; }
/// Get current step count
int step_count() const { return step_counter_; }
/// Calculate model sparsity
float calculate_sparsity() const;
/// 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_;
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;
float last_sparsity_ = 0.0f;
// 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;
float last_sparsity_ = 0.0f;
// RAM backup
std::vector<torch::Tensor> ram_backup_;
// RAM backup
std::vector<torch::Tensor> ram_backup_;
// Layer stats and group mappings
std::vector<std::vector<float>> layer_stats_;
std::vector<int> param_group_mapping_;
std::unique_ptr<SpectralSensor> spectral_sensor_;
SpectralController spectral_controller_;
float last_spectral_rank_ = 0.0f;
// Layer stats and group mappings
std::vector<std::vector<float>> layer_stats_;
std::vector<int> param_group_mapping_;
std::unique_ptr<SpectralSensor> spectral_sensor_;
SpectralController spectral_controller_;
float last_spectral_rank_ = 0.0f;
// Internal methods
void gather_stats();
void apply_parameter_updates(const torch::Tensor& actions);
void handle_rollback();
// Internal methods
void gather_stats();
void apply_parameter_updates(const torch::Tensor &actions);
void handle_rollback();
};
} // namespace fces
} // namespace fces

View File

@@ -11,21 +11,22 @@ namespace fces {
class OscillationDetector {
public:
static constexpr int WINDOW_SIZE = 64;
static constexpr float POWER_THRESHOLD = 0.5f;
static constexpr int MIN_PERIOD = 4;
static constexpr int MAX_PERIOD = 16;
static constexpr int WINDOW_SIZE = 64;
static constexpr float POWER_THRESHOLD = 0.5f;
static constexpr int MIN_PERIOD = 4;
static constexpr int MAX_PERIOD = 16;
void update(float loss);
bool detect() const;
float get_score() const;
float get_variance_50() const;
void reset();
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);
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
} // namespace fces

View File

@@ -16,9 +16,9 @@
* Port of: packages/fces/core/population.py (~1260 LOC)
*/
#include <optional>
#include <string>
#include <vector>
#include <optional>
#include "controller.hpp"
@@ -28,11 +28,11 @@ 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)
Cumulative, // Raw cumulative fitness
EMA, // Exponential moving average
Rolling, // Rolling window average
Reset, // Periodic reset every 500 steps
AgePenalty // fitness / log(age + 2)
};
/**
@@ -40,126 +40,124 @@ enum class EliteStrategy {
*/
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;
// 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
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// 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
);
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
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// Core API
// ---------------------------------------------------------------
/// Get the currently active controller (sticky selection)
FuzzyController& get_active_controller();
/// Get the currently active controller (sticky selection)
FuzzyController &get_active_controller();
/// Select a controller via fitness-weighted tournament
FuzzyController& select_weighted();
/// Select a controller via fitness-weighted tournament
FuzzyController &select_weighted();
/// Get the best controller in the active population
FuzzyController& get_best_active();
/// Get the best controller in the active population
FuzzyController &get_best_active();
/// Get the worst non-elite controller
FuzzyController& get_worst_active();
/// Get the worst non-elite controller
FuzzyController &get_worst_active();
/// Remove a specific controller (unless elite)
void kill(FuzzyController& controller);
/// 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);
/// 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);
/// 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;
/// Get the effective fitness considering elite strategy and training progress
float get_effective_fitness(const FuzzyController &controller,
float training_progress) const;
// ---------------------------------------------------------------
// Evolution
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// 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);
/**
* 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);
/// Resize the population (dynamic expansion/contraction)
void resize(int target_size, float training_progress = 0.5f);
/// Reduce mutation variance after rollback
void calm_down();
/// Reduce mutation variance after rollback
void calm_down();
// ---------------------------------------------------------------
// Accessors
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// Accessors
// ---------------------------------------------------------------
int size() const { return static_cast<int>(gladiators_.size()); }
float global_sigma_modifier() const { return global_sigma_modifier_; }
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;
/// Compute diversity index (behavioral spread)
float get_diversity_index() const;
/// Serialization
// TODO: state_dict / load_state_dict
/// Serialization
// TODO: state_dict / load_state_dict
private:
std::vector<FuzzyController> gladiators_;
std::vector<FuzzyController> repository_;
std::vector<FuzzyController> violated_controllers_;
std::vector<FuzzyController> gladiators_;
std::vector<FuzzyController> repository_;
std::vector<FuzzyController> violated_controllers_;
float global_sigma_modifier_ = 1.0f;
float global_sigma_modifier_ = 1.0f;
// Sticky controller selection
FuzzyController* active_controller_ = nullptr;
int steps_active_ = 0;
int selection_interval_ = 20;
// 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_;
// 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_;
// Novelty search
std::vector<std::vector<float>> behavioral_archive_;
// Fitness history for fuzzy pacer
std::vector<float> fitness_history_;
// Fitness history for fuzzy pacer
std::vector<float> fitness_history_;
// Phase 23: periodic reset counter
int reset_step_counter_ = 0;
// Phase 23: periodic reset counter
int reset_step_counter_ = 0;
// ---------------------------------------------------------------
// Internal
// ---------------------------------------------------------------
// ---------------------------------------------------------------
// Internal
// ---------------------------------------------------------------
std::vector<FuzzyController*> get_elites();
void add_to_repository(const FuzzyController& controller);
std::vector<FuzzyController *> get_elites();
void add_to_repository(const FuzzyController &controller);
};
} // namespace fces
} // namespace fces

View File

@@ -23,23 +23,23 @@ namespace fces {
*/
class SpectralSensor {
public:
SpectralSensor() = default;
explicit SpectralSensor(torch::nn::Module& model);
SpectralSensor() = default;
explicit SpectralSensor(torch::nn::Module &model);
/// Track a layer's weight tensor
void track_layer(const std::string& name, const torch::Tensor& weight);
/// 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;
/// Get the global (average) effective rank
float get_global_rank() const;
/// Reset all tracked layers
void reset();
/// Reset all tracked layers
void reset();
private:
std::unordered_map<std::string, float> layer_ranks_;
std::unordered_map<std::string, float> layer_ranks_;
/// Compute effective rank via SVD
static float compute_effective_rank(const torch::Tensor& weight);
/// Compute effective rank via SVD
static float compute_effective_rank(const torch::Tensor &weight);
};
/**
@@ -47,8 +47,8 @@ private:
*/
class SpectralController {
public:
/// Compute the spectral alpha (gating factor for rank-aware updates)
float compute_alpha(float global_rank, float grokking_coefficient) const;
/// Compute the spectral alpha (gating factor for rank-aware updates)
float compute_alpha(float global_rank, float grokking_coefficient) const;
};
} // namespace fces
} // namespace fces

View File

@@ -11,16 +11,16 @@ namespace fces {
class Telemetry {
public:
static Telemetry& get();
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 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();
void push_to_remote();
private:
Telemetry() = default;
Telemetry() = default;
};
} // namespace fces
} // namespace fces

View File

@@ -13,39 +13,40 @@
#include <pybind11/stl.h>
#include <torch/extension.h>
#include "fces/optimizer.hpp"
#include "fces/config.hpp"
#include "fces/optimizer.hpp"
namespace py = pybind11;
PYBIND11_MODULE(fces_native, m) {
m.doc() = "FCES-native: High-performance C++ FCES optimizer";
m.doc() = "FCES-native: High-performance C++ FCES optimizer";
py::class_<fces::FCESConfig>(m, "FCESConfig")
.def(py::init<>())
.def_readwrite("lr", &fces::FCESConfig::lr)
.def_readwrite("population_size", &fces::FCESConfig::population_size)
.def_readwrite("total_steps", &fces::FCESConfig::total_steps)
.def_readwrite("grokking_coefficient", &fces::FCESConfig::grokking_coefficient)
.def_readwrite("direct_construction", &fces::FCESConfig::direct_construction);
py::class_<fces::FCESConfig>(m, "FCESConfig")
.def(py::init<>())
.def_readwrite("lr", &fces::FCESConfig::lr)
.def_readwrite("population_size", &fces::FCESConfig::population_size)
.def_readwrite("total_steps", &fces::FCESConfig::total_steps)
.def_readwrite("grokking_coefficient",
&fces::FCESConfig::grokking_coefficient)
.def_readwrite("direct_construction",
&fces::FCESConfig::direct_construction);
py::class_<fces::FCESOptimizer>(m, "FCESOptimizer")
.def(py::init<std::vector<torch::Tensor>, fces::FCESConfig>(),
py::arg("params"),
py::arg("config") = fces::FCESConfig{})
.def("step", &fces::FCESOptimizer::step)
.def("update_fitness", &fces::FCESOptimizer::update_fitness)
.def("backup_to_ram", &fces::FCESOptimizer::backup_to_ram)
.def("restore_from_ram", &fces::FCESOptimizer::restore_from_ram)
.def("step_count", &fces::FCESOptimizer::step_count)
.def("calculate_sparsity", &fces::FCESOptimizer::calculate_sparsity)
.def("zero_grad", [](fces::FCESOptimizer& self) {
for (auto& group : self.param_groups()) {
for (auto& p : group.params()) {
if (p.grad().defined()) {
p.grad().zero_();
}
}
py::class_<fces::FCESOptimizer>(m, "FCESOptimizer")
.def(py::init<std::vector<torch::Tensor>, fces::FCESConfig>(),
py::arg("params"), py::arg("config") = fces::FCESConfig{})
.def("step", &fces::FCESOptimizer::step)
.def("update_fitness", &fces::FCESOptimizer::update_fitness)
.def("backup_to_ram", &fces::FCESOptimizer::backup_to_ram)
.def("restore_from_ram", &fces::FCESOptimizer::restore_from_ram)
.def("step_count", &fces::FCESOptimizer::step_count)
.def("calculate_sparsity", &fces::FCESOptimizer::calculate_sparsity)
.def("zero_grad", [](fces::FCESOptimizer &self) {
for (auto &group : self.param_groups()) {
for (auto &p : group.params()) {
if (p.grad().defined()) {
p.grad().zero_();
}
});
}
}
});
}

View File

@@ -13,341 +13,354 @@ thread_local std::mt19937 FuzzyController::rng_{std::random_device{}()};
// Genome
// ---------------------------------------------------------------
void Genome::randomize(std::mt19937& rng) {
std::normal_distribution<float> dist(0.0f, 0.5f);
for (auto& w : weights) {
w = dist(rng);
}
gene_success.fill(0.0f);
void Genome::randomize(std::mt19937 &rng) {
std::normal_distribution<float> dist(0.0f, 0.5f);
for (auto &w : weights) {
w = dist(rng);
}
gene_success.fill(0.0f);
}
Genome Genome::clone() const {
return *this; // Copy all fields
return *this; // Copy all fields
}
// ---------------------------------------------------------------
// FuzzyController
// ---------------------------------------------------------------
FuzzyController::FuzzyController()
: id(next_id_++), origin("random") {
genome.randomize(rng_);
// Bias output toward acceleration (V2.1 insight)
// Set output biases (last GENOME_OUTPUT_DIM elements) to +2.0, -1.0, 0.0 with noise
constexpr int bias_start = GENOME_SIZE - GENOME_OUTPUT_DIM;
std::normal_distribution<float> bias_noise(0.0f, 0.5f);
genome.weights[bias_start] = 2.0f + bias_noise(rng_);
genome.weights[bias_start + 1] = -1.0f + bias_noise(rng_);
genome.weights[bias_start + 2] = 0.0f + bias_noise(rng_);
FuzzyController::FuzzyController() : id(next_id_++), origin("random") {
genome.randomize(rng_);
// Bias output toward acceleration (V2.1 insight)
// Set output biases (last GENOME_OUTPUT_DIM elements) to +2.0, -1.0, 0.0 with
// noise
constexpr int bias_start = GENOME_SIZE - GENOME_OUTPUT_DIM;
std::normal_distribution<float> bias_noise(0.0f, 0.5f);
genome.weights[bias_start] = 2.0f + bias_noise(rng_);
genome.weights[bias_start + 1] = -1.0f + bias_noise(rng_);
genome.weights[bias_start + 2] = 0.0f + bias_noise(rng_);
// Initialize plasticity with variance to seed evolution
std::normal_distribution<float> plast_noise(0.0f, 0.05f);
genome.plasticity = std::max(0.01f, 0.1f + plast_noise(rng_));
genome.sigma_gene = 0.1f;
genome.gene_success.fill(1.0f);
// Initialize plasticity with variance to seed evolution
std::normal_distribution<float> plast_noise(0.0f, 0.05f);
genome.plasticity = std::max(0.01f, 0.1f + plast_noise(rng_));
genome.sigma_gene = 0.1f;
genome.gene_success.fill(1.0f);
}
FuzzyController::FuzzyController(Genome genome)
: id(next_id_++), genome(std::move(genome)), origin("constructed") {}
torch::Tensor FuzzyController::decide_update(
const std::vector<std::vector<float>>& layer_stats,
float loss_trend,
float step_pct,
float rollback_rate,
float grad_stability,
float spectral_alpha,
float stagnation_intensity,
float kzm_damping,
float projected_drift
) {
const int num_groups = static_cast<int>(layer_stats.size());
auto actions = torch::zeros({num_groups, GENOME_OUTPUT_DIM});
const std::vector<std::vector<float>> &layer_stats, float loss_trend,
float step_pct, float rollback_rate, float grad_stability,
float spectral_alpha, float stagnation_intensity, float kzm_damping,
float projected_drift) {
const int num_groups = static_cast<int>(layer_stats.size());
auto actions = torch::zeros({num_groups, GENOME_OUTPUT_DIM});
// Extract weight views for the micro-MLP
const float* w = genome.weights.data();
// Extract weight views for the micro-MLP
const float *w = genome.weights.data();
// Layer 1: input -> hidden
const float* W1 = w; // [(GENOME_INPUT_DIM + 1) x GENOME_HIDDEN_DIM]
// Layer 2: hidden -> output
const float* W2 = w + ((GENOME_INPUT_DIM + 1) * GENOME_HIDDEN_DIM); // [(GENOME_HIDDEN_DIM + 1) x GENOME_OUTPUT_DIM]
// Layer 1: input -> hidden
const float *W1 = w; // [(GENOME_INPUT_DIM + 1) x GENOME_HIDDEN_DIM]
// Layer 2: hidden -> output
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) {
// 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;
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};
if (type_idx >= 0 && type_idx < 5) {
type_onehot[type_idx] = 1.0f;
}
// Build input vector
std::array<float, GENOME_INPUT_DIM> input{};
float gn = (layer_stats[g].size() >= 1) ? layer_stats[g][0] : 0.0f;
float sp = (layer_stats[g].size() >= 2) ? layer_stats[g][1] : 0.0f;
// Sanitization matching nan_to_num
if (!std::isfinite(gn) || std::isnan(gn)) 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 (sp > 1.0f) sp = 1.0f;
if (sp < 0.0f) sp = 0.0f;
input[0] = gn;
input[1] = sp;
input[2] = loss_trend;
input[3] = step_pct;
input[4] = (num_groups > 1) ? static_cast<float>(g) / (num_groups - 1.0f) : 0.0f;
input[5] = rollback_rate;
input[6] = grad_stability;
input[7] = spectral_alpha;
input[8] = type_onehot[0];
input[9] = type_onehot[1];
input[10] = type_onehot[2];
input[11] = type_onehot[3];
input[12] = type_onehot[4];
input[13] = projected_drift;
// Forward pass: hidden = tanh(W1 * [input, 1])
std::array<float, GENOME_HIDDEN_DIM> hidden{};
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
float sum = W1[GENOME_INPUT_DIM * GENOME_HIDDEN_DIM + h]; // Bias weight
for (int i = 0; i < GENOME_INPUT_DIM; ++i) {
sum += input[i] * W1[i * GENOME_HIDDEN_DIM + h];
}
hidden[h] = std::tanh(sum);
}
// Output = W2 * [hidden, 1]
std::array<float, GENOME_OUTPUT_DIM> out_layer{};
for (int o = 0; o < GENOME_OUTPUT_DIM; ++o) {
float sum = W2[GENOME_HIDDEN_DIM * GENOME_OUTPUT_DIM + o]; // Bias weight
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
sum += hidden[h] * W2[h * GENOME_OUTPUT_DIM + o];
}
out_layer[o] = sum;
}
// Parse Output
float log_mult_raw = out_layer[0];
float log_wd_raw = out_layer[2];
float sign_logit = out_layer[1];
if (!std::isfinite(sign_logit) || std::isnan(sign_logit)) {
sign_logit = 0.0f;
}
float noise_std = 0.0f;
if (genome.plasticity > 0.01f) {
noise_std += genome.plasticity;
}
if (stagnation_intensity > 0.0f) {
noise_std += stagnation_intensity * 0.5f;
}
if (kzm_damping > 0.0f) {
noise_std *= (1.0f - kzm_damping);
log_mult_raw *= (1.0f - kzm_damping);
}
if (noise_std > 0.0f) {
std::normal_distribution<float> noise_dist(0.0f, noise_std);
log_mult_raw += noise_dist(rng_);
log_wd_raw += noise_dist(rng_);
}
if (!std::isfinite(log_mult_raw) || std::isnan(log_mult_raw)) {
log_mult_raw = 0.0f;
}
log_mult_raw = std::max(-6.0f, std::min(6.0f, log_mult_raw));
float mult = std::pow(2.0f, log_mult_raw);
if (!std::isfinite(log_wd_raw) || std::isnan(log_wd_raw)) {
log_wd_raw = 0.0f;
}
log_wd_raw = std::max(-6.0f, std::min(6.0f, log_wd_raw));
float wd_mult = std::pow(2.0f, log_wd_raw);
actions[g][0] = mult;
actions[g][1] = sign_logit;
actions[g][2] = wd_mult;
for (int g = 0; g < num_groups; ++g) {
// 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;
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};
if (type_idx >= 0 && type_idx < 5) {
type_onehot[type_idx] = 1.0f;
}
return actions;
// Build input vector
std::array<float, GENOME_INPUT_DIM> input{};
float gn = (layer_stats[g].size() >= 1) ? layer_stats[g][0] : 0.0f;
float sp = (layer_stats[g].size() >= 2) ? layer_stats[g][1] : 0.0f;
// Sanitization matching nan_to_num
if (!std::isfinite(gn) || std::isnan(gn))
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 (sp > 1.0f)
sp = 1.0f;
if (sp < 0.0f)
sp = 0.0f;
input[0] = gn;
input[1] = sp;
input[2] = loss_trend;
input[3] = step_pct;
input[4] =
(num_groups > 1) ? static_cast<float>(g) / (num_groups - 1.0f) : 0.0f;
input[5] = rollback_rate;
input[6] = grad_stability;
input[7] = spectral_alpha;
input[8] = type_onehot[0];
input[9] = type_onehot[1];
input[10] = type_onehot[2];
input[11] = type_onehot[3];
input[12] = type_onehot[4];
input[13] = projected_drift;
// Forward pass: hidden = tanh(W1 * [input, 1])
std::array<float, GENOME_HIDDEN_DIM> hidden{};
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
float sum = W1[GENOME_INPUT_DIM * GENOME_HIDDEN_DIM + h]; // Bias weight
for (int i = 0; i < GENOME_INPUT_DIM; ++i) {
sum += input[i] * W1[i * GENOME_HIDDEN_DIM + h];
}
hidden[h] = std::tanh(sum);
}
// Output = W2 * [hidden, 1]
std::array<float, GENOME_OUTPUT_DIM> out_layer{};
for (int o = 0; o < GENOME_OUTPUT_DIM; ++o) {
float sum = W2[GENOME_HIDDEN_DIM * GENOME_OUTPUT_DIM + o]; // Bias weight
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
sum += hidden[h] * W2[h * GENOME_OUTPUT_DIM + o];
}
out_layer[o] = sum;
}
// Parse Output
float log_mult_raw = out_layer[0];
float log_wd_raw = out_layer[2];
float sign_logit = out_layer[1];
if (!std::isfinite(sign_logit) || std::isnan(sign_logit)) {
sign_logit = 0.0f;
}
float noise_std = 0.0f;
if (genome.plasticity > 0.01f) {
noise_std += genome.plasticity;
}
if (stagnation_intensity > 0.0f) {
noise_std += stagnation_intensity * 0.5f;
}
if (kzm_damping > 0.0f) {
noise_std *= (1.0f - kzm_damping);
log_mult_raw *= (1.0f - kzm_damping);
}
if (noise_std > 0.0f) {
std::normal_distribution<float> noise_dist(0.0f, noise_std);
log_mult_raw += noise_dist(rng_);
log_wd_raw += noise_dist(rng_);
}
if (!std::isfinite(log_mult_raw) || std::isnan(log_mult_raw)) {
log_mult_raw = 0.0f;
}
log_mult_raw = std::max(-6.0f, std::min(6.0f, log_mult_raw));
float mult = std::pow(2.0f, log_mult_raw);
if (!std::isfinite(log_wd_raw) || std::isnan(log_wd_raw)) {
log_wd_raw = 0.0f;
}
log_wd_raw = std::max(-6.0f, std::min(6.0f, log_wd_raw));
float wd_mult = std::pow(2.0f, log_wd_raw);
actions[g][0] = mult;
actions[g][1] = sign_logit;
actions[g][2] = wd_mult;
}
return actions;
}
FuzzyController FuzzyController::mutate(float current_loss, float sigma_scale) const {
Genome child_genome = genome.clone();
std::normal_distribution<float> std_normal(0.0f, 1.0f);
FuzzyController FuzzyController::mutate(float current_loss,
float sigma_scale) const {
Genome child_genome = genome.clone();
std::normal_distribution<float> std_normal(0.0f, 1.0f);
float tau = 0.2f;
float new_sigma = genome.sigma_gene * std::exp(tau * std_normal(rng_));
new_sigma = std::max(0.001f, std::min(0.8f, new_sigma));
float tau = 0.2f;
float new_sigma = genome.sigma_gene * std::exp(tau * std_normal(rng_));
new_sigma = std::max(0.001f, std::min(0.8f, new_sigma));
float new_plast = genome.plasticity * std::exp(tau * std_normal(rng_));
new_plast = std::max(0.0f, std::min(0.5f, new_plast));
float new_plast = genome.plasticity * std::exp(tau * std_normal(rng_));
new_plast = std::max(0.0f, std::min(0.5f, new_plast));
float loss_val = std::max(0.0f, current_loss);
float annealing_factor = std::sqrt(loss_val + 0.1f);
float effective_sigma = new_sigma * sigma_scale * annealing_factor;
float loss_val = std::max(0.0f, current_loss);
float annealing_factor = std::sqrt(loss_val + 0.1f);
float effective_sigma = new_sigma * sigma_scale * annealing_factor;
std::normal_distribution<float> noise(0.0f, effective_sigma);
for (size_t i = 0; i < child_genome.weights.size(); ++i) {
child_genome.weights[i] += noise(rng_);
child_genome.gene_success[i] = genome.gene_success[i] * 0.95f;
}
std::normal_distribution<float> noise(0.0f, effective_sigma);
for (size_t i = 0; i < child_genome.weights.size(); ++i) {
child_genome.weights[i] += noise(rng_);
child_genome.gene_success[i] = genome.gene_success[i] * 0.95f;
}
child_genome.sigma_gene = new_sigma;
child_genome.plasticity = new_plast;
child_genome.sigma_gene = new_sigma;
child_genome.plasticity = new_plast;
FuzzyController child(child_genome);
child.origin = "mutation";
return child;
FuzzyController child(child_genome);
child.origin = "mutation";
return child;
}
FuzzyController FuzzyController::crossover(const FuzzyController& partner, bool /*use_alignment*/) const {
Genome child_genome;
std::uniform_real_distribution<float> u_dist(0.0f, 1.0f);
FuzzyController FuzzyController::crossover(const FuzzyController &partner,
bool /*use_alignment*/) const {
Genome child_genome;
std::uniform_real_distribution<float> u_dist(0.0f, 1.0f);
for (size_t i = 0; i < child_genome.weights.size(); ++i) {
float success_self = genome.gene_success[i];
float success_partner = partner.genome.gene_success[i];
float prob_a = success_self / (success_self + success_partner + 1e-9f);
for (size_t i = 0; i < child_genome.weights.size(); ++i) {
float success_self = genome.gene_success[i];
float success_partner = partner.genome.gene_success[i];
float prob_a = success_self / (success_self + success_partner + 1e-9f);
bool choose_self = false;
if (u_dist(rng_) < 0.1f) {
// 10% Random injection
choose_self = (u_dist(rng_) < 0.5f);
} else {
// 90% Meritocratic
choose_self = (u_dist(rng_) < prob_a);
}
if (choose_self) {
child_genome.weights[i] = genome.weights[i];
child_genome.gene_success[i] = success_self;
} else {
child_genome.weights[i] = partner.genome.weights[i];
child_genome.gene_success[i] = success_partner;
}
bool choose_self = false;
if (u_dist(rng_) < 0.1f) {
// 10% Random injection
choose_self = (u_dist(rng_) < 0.5f);
} else {
// 90% Meritocratic
choose_self = (u_dist(rng_) < prob_a);
}
child_genome.sigma_gene = (genome.sigma_gene + partner.genome.sigma_gene) * 0.5f;
child_genome.plasticity = (genome.plasticity + partner.genome.plasticity) * 0.5f;
if (choose_self) {
child_genome.weights[i] = genome.weights[i];
child_genome.gene_success[i] = success_self;
} else {
child_genome.weights[i] = partner.genome.weights[i];
child_genome.gene_success[i] = success_partner;
}
}
FuzzyController child(child_genome);
child.origin = "crossover";
return child;
child_genome.sigma_gene =
(genome.sigma_gene + partner.genome.sigma_gene) * 0.5f;
child_genome.plasticity =
(genome.plasticity + partner.genome.plasticity) * 0.5f;
FuzzyController child(child_genome);
child.origin = "crossover";
return child;
}
FuzzyController FuzzyController::create_orthogonal_child(float intensity) const {
Genome child_genome;
std::normal_distribution<float> norm_dist(0.0f, 1.0f);
FuzzyController
FuzzyController::create_orthogonal_child(float intensity) const {
Genome child_genome;
std::normal_distribution<float> norm_dist(0.0f, 1.0f);
float norm_elite = 0.0f;
for (float w : genome.weights) {
norm_elite += w * w;
}
norm_elite = std::sqrt(norm_elite) + 1e-9f;
float norm_elite = 0.0f;
for (float w : genome.weights) {
norm_elite += w * w;
}
norm_elite = std::sqrt(norm_elite) + 1e-9f;
std::array<float, GENOME_SIZE> random_vec{};
float dot_product = 0.0f;
std::array<float, GENOME_SIZE> random_vec{};
float dot_product = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
random_vec[i] = norm_dist(rng_);
dot_product += random_vec[i] * genome.weights[i];
}
std::array<float, GENOME_SIZE> orthogonal_vec{};
float norm_ortho = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
float projection =
(dot_product / (norm_elite * norm_elite)) * genome.weights[i];
orthogonal_vec[i] = random_vec[i] - projection;
norm_ortho += orthogonal_vec[i] * orthogonal_vec[i];
}
norm_ortho = std::sqrt(norm_ortho) + 1e-9f;
std::array<float, GENOME_SIZE> scaled_vec{};
float final_norm = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
scaled_vec[i] = orthogonal_vec[i] * (norm_elite / norm_ortho) * intensity;
final_norm += scaled_vec[i] * scaled_vec[i];
}
final_norm = std::sqrt(final_norm);
float max_allowed = std::max(norm_elite, 10.0f);
if (final_norm > max_allowed) {
float scale = max_allowed / (final_norm + 1e-9f);
for (size_t i = 0; i < GENOME_SIZE; ++i) {
random_vec[i] = norm_dist(rng_);
dot_product += random_vec[i] * genome.weights[i];
scaled_vec[i] *= scale;
}
}
std::array<float, GENOME_SIZE> orthogonal_vec{};
float norm_ortho = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
float projection = (dot_product / (norm_elite * norm_elite)) * genome.weights[i];
orthogonal_vec[i] = random_vec[i] - projection;
norm_ortho += orthogonal_vec[i] * orthogonal_vec[i];
}
norm_ortho = std::sqrt(norm_ortho) + 1e-9f;
child_genome.weights = scaled_vec;
child_genome.gene_success.fill(1.0f);
child_genome.sigma_gene = 0.2f;
child_genome.plasticity = 0.2f;
std::array<float, GENOME_SIZE> scaled_vec{};
float final_norm = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
scaled_vec[i] = orthogonal_vec[i] * (norm_elite / norm_ortho) * intensity;
final_norm += scaled_vec[i] * scaled_vec[i];
}
final_norm = std::sqrt(final_norm);
float max_allowed = std::max(norm_elite, 10.0f);
if (final_norm > max_allowed) {
float scale = max_allowed / (final_norm + 1e-9f);
for (size_t i = 0; i < GENOME_SIZE; ++i) {
scaled_vec[i] *= scale;
}
}
child_genome.weights = scaled_vec;
child_genome.gene_success.fill(1.0f);
child_genome.sigma_gene = 0.2f;
child_genome.plasticity = 0.2f;
FuzzyController child(child_genome);
child.origin = "phoenix_rebirth";
return child;
FuzzyController child(child_genome);
child.origin = "phoenix_rebirth";
return child;
}
std::pair<FuzzyController, FuzzyController> FuzzyController::banach_tarski_fission(float intensity) const {
Genome plus_genome;
Genome minus_genome;
std::pair<FuzzyController, FuzzyController>
FuzzyController::banach_tarski_fission(float intensity) const {
Genome plus_genome;
Genome minus_genome;
float norm_parent = 0.0f;
float max_success = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
norm_parent += genome.weights[i] * genome.weights[i];
if (genome.gene_success[i] > max_success) {
max_success = genome.gene_success[i];
}
float norm_parent = 0.0f;
float max_success = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
norm_parent += genome.weights[i] * genome.weights[i];
if (genome.gene_success[i] > max_success) {
max_success = genome.gene_success[i];
}
norm_parent = std::sqrt(norm_parent) + 1e-9f;
max_success += 1e-9f;
}
norm_parent = std::sqrt(norm_parent) + 1e-9f;
max_success += 1e-9f;
std::normal_distribution<float> norm_dist(0.0f, 1.0f);
std::array<float, GENOME_SIZE> noise{};
float dot_product = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
float saliency = genome.gene_success[i] / max_success;
noise[i] = norm_dist(rng_) * saliency;
dot_product += noise[i] * genome.weights[i];
}
std::normal_distribution<float> norm_dist(0.0f, 1.0f);
std::array<float, GENOME_SIZE> noise{};
float dot_product = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
float saliency = genome.gene_success[i] / max_success;
noise[i] = norm_dist(rng_) * saliency;
dot_product += noise[i] * genome.weights[i];
}
std::array<float, GENOME_SIZE> fission_vec{};
float norm_fission = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++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 = std::sqrt(norm_fission) + 1e-9f;
std::array<float, GENOME_SIZE> fission_vec{};
float norm_fission = 0.0f;
for (size_t i = 0; i < GENOME_SIZE; ++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 = std::sqrt(norm_fission) + 1e-9f;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
float scaled_fission = fission_vec[i] * (norm_parent / norm_fission) * 0.1f * intensity;
plus_genome.weights[i] = genome.weights[i] + scaled_fission;
minus_genome.weights[i] = genome.weights[i] - scaled_fission;
for (size_t i = 0; i < GENOME_SIZE; ++i) {
float scaled_fission =
fission_vec[i] * (norm_parent / norm_fission) * 0.1f * intensity;
plus_genome.weights[i] = genome.weights[i] + scaled_fission;
minus_genome.weights[i] = genome.weights[i] - scaled_fission;
plus_genome.gene_success[i] = 1.0f;
minus_genome.gene_success[i] = 1.0f;
}
plus_genome.gene_success[i] = 1.0f;
minus_genome.gene_success[i] = 1.0f;
}
plus_genome.sigma_gene = genome.sigma_gene * 0.9f;
minus_genome.sigma_gene = genome.sigma_gene * 0.9f;
plus_genome.sigma_gene = genome.sigma_gene * 0.9f;
minus_genome.sigma_gene = genome.sigma_gene * 0.9f;
plus_genome.plasticity = genome.plasticity;
minus_genome.plasticity = genome.plasticity;
plus_genome.plasticity = genome.plasticity;
minus_genome.plasticity = genome.plasticity;
FuzzyController child_plus(plus_genome);
child_plus.origin = "fission_plus";
FuzzyController child_plus(plus_genome);
child_plus.origin = "fission_plus";
FuzzyController child_minus(minus_genome);
child_minus.origin = "fission_minus";
FuzzyController child_minus(minus_genome);
child_minus.origin = "fission_minus";
return {child_plus, child_minus};
return {child_plus, child_minus};
}
} // namespace fces
} // namespace fces

View File

@@ -2,51 +2,46 @@
namespace fces {
EvolutionManager::EvolutionManager(
Population& population, int selection_interval,
bool auto_population, bool direct_construction
)
: population_(population),
selection_interval(selection_interval),
EvolutionManager::EvolutionManager(Population &population,
int selection_interval, bool auto_population,
bool direct_construction)
: population_(population), selection_interval(selection_interval),
auto_population_(auto_population),
direct_construction_(direct_construction) {}
FuzzyController& EvolutionManager::get_active_controller() {
return population_.get_active_controller();
FuzzyController &EvolutionManager::get_active_controller() {
return population_.get_active_controller();
}
void EvolutionManager::update_population_dynamics(
float loss_velocity, float ema_loss, int step_counter, int total_steps
) {
float progress = static_cast<float>(step_counter) / std::max(1, total_steps);
void EvolutionManager::update_population_dynamics(float loss_velocity,
float ema_loss,
int step_counter,
int total_steps) {
float progress = static_cast<float>(step_counter) / std::max(1, total_steps);
if (step_counter % 20 == 0) {
population_.evolve(
std::abs(loss_velocity),
loss_velocity,
progress
);
if (step_counter % 20 == 0) {
population_.evolve(std::abs(loss_velocity), loss_velocity, progress);
}
if (!auto_population_ || step_counter % 50 != 0) {
return;
}
int current_pop = population_.size();
float adaptive_threshold = 0.05f * (1.0f + ema_loss);
adaptive_threshold = std::min(0.5f, adaptive_threshold);
if (std::abs(loss_velocity) < adaptive_threshold) {
int target_pop = 200;
if (target_pop > current_pop) {
population_.resize(target_pop, progress);
}
if (!auto_population_ || step_counter % 50 != 0) {
return;
}
int current_pop = population_.size();
float adaptive_threshold = 0.05f * (1.0f + ema_loss);
adaptive_threshold = std::min(0.5f, adaptive_threshold);
if (std::abs(loss_velocity) < adaptive_threshold) {
int target_pop = 200;
if (target_pop > current_pop) {
population_.resize(target_pop, progress);
}
} else {
int target_pop = 40;
if (target_pop < current_pop) {
population_.resize(target_pop, progress);
}
} else {
int target_pop = 40;
if (target_pop < current_pop) {
population_.resize(target_pop, progress);
}
}
}
} // namespace fces
} // namespace fces

View File

@@ -1,7 +1,7 @@
#include "fces/fitness.hpp"
#include <algorithm>
#include <cmath>
#include <numeric>
#include <algorithm>
#include <string>
namespace fces {
@@ -11,28 +11,30 @@ namespace fces {
// ---------------------------------------------------------------
void RunningStats::update(float value) {
count_++;
float delta = value - mean_;
mean_ += delta / static_cast<float>(count_);
float delta2 = value - mean_;
m2_ += delta * delta2;
count_++;
float delta = value - mean_;
mean_ += delta / static_cast<float>(count_);
float delta2 = value - mean_;
m2_ += delta * delta2;
}
float RunningStats::z_score(float value) const {
float s = get_std();
if (s < 1e-8f) return 0.0f;
return (value - mean_) / s;
float s = get_std();
if (s < 1e-8f)
return 0.0f;
return (value - mean_) / s;
}
float RunningStats::get_std() const {
if (count_ < 2) return 1.0f;
return std::sqrt(m2_ / static_cast<float>(count_ - 1));
if (count_ < 2)
return 1.0f;
return std::sqrt(m2_ / static_cast<float>(count_ - 1));
}
void RunningStats::reset() {
count_ = 0;
mean_ = 0.0f;
m2_ = 0.0f;
count_ = 0;
mean_ = 0.0f;
m2_ = 0.0f;
}
// ---------------------------------------------------------------
@@ -42,18 +44,20 @@ void RunningStats::reset() {
FitnessEngine::FitnessEngine(float grokking_coefficient)
: grokking_coefficient_(grokking_coefficient) {}
float FitnessEngine::calculate_loss_signal(float current_loss, float ema_loss, const std::string& mode) const {
if (ema_loss < 1e-8f) return 0.0f;
float FitnessEngine::calculate_loss_signal(float current_loss, float ema_loss,
const std::string &mode) const {
if (ema_loss < 1e-8f)
return 0.0f;
if (mode == "relative") {
return (current_loss - ema_loss) / (ema_loss + 1e-8f);
}
return current_loss - ema_loss;
if (mode == "relative") {
return (current_loss - ema_loss) / (ema_loss + 1e-8f);
}
return current_loss - ema_loss;
}
float FitnessEngine::compute_kzm_damping(float spectral_alpha) const {
// Kibble-Zurek damping: high spectral rank = more damping
return 1.0f / (1.0f + grokking_coefficient_ * spectral_alpha);
// Kibble-Zurek damping: high spectral rank = more damping
return 1.0f / (1.0f + grokking_coefficient_ * spectral_alpha);
}
// ---------------------------------------------------------------
@@ -68,30 +72,28 @@ FuzzyFitnessEvaluator::FuzzyFitnessEvaluator() noexcept
consistency_set_("Consistent", -1.0f, 0.0f, 0.02f, 0.1f),
rank_set_("LowRank", -1.0f, 0.0f, 5.0f, 20.0f) {}
float FuzzyFitnessEvaluator::evaluate(const FitnessMetrics& metrics) const noexcept {
float m_stability = stability_set_.membership(metrics.grad_cv);
float m_train = train_set_.membership(metrics.training_advantage);
float m_val = val_set_.membership(metrics.validation_advantage);
float m_sparsity = sparsity_set_.membership(metrics.sparsity_delta);
float m_consistency = consistency_set_.membership(metrics.consistency_gap);
float m_rank = rank_set_.membership(metrics.stable_rank);
float FuzzyFitnessEvaluator::evaluate(
const FitnessMetrics &metrics) const noexcept {
float m_stability = stability_set_.membership(metrics.grad_cv);
float m_train = train_set_.membership(metrics.training_advantage);
float m_val = val_set_.membership(metrics.validation_advantage);
float m_sparsity = sparsity_set_.membership(metrics.sparsity_delta);
float m_consistency = consistency_set_.membership(metrics.consistency_gap);
float m_rank = rank_set_.membership(metrics.stable_rank);
float weighted_score =
m_stability * w_stability_ +
m_train * w_train_ +
m_val * w_val_ +
m_sparsity * w_sparsity_ +
m_consistency * w_consistency_ +
m_rank * w_rank_;
float weighted_score = m_stability * w_stability_ + m_train * w_train_ +
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_;
if (total_weight > 0.0f) {
weighted_score /= total_weight;
}
float total_weight =
w_stability_ + w_train_ + w_val_ + w_sparsity_ + w_consistency_ + w_rank_;
if (total_weight > 0.0f) {
weighted_score /= total_weight;
}
// V153: Generalization-Aware Gate (Non-Linear)
float gate_efficiency = 0.5f + 0.5f * m_consistency;
return weighted_score * gate_efficiency;
// V153: Generalization-Aware Gate (Non-Linear)
float gate_efficiency = 0.5f + 0.5f * m_consistency;
return weighted_score * gate_efficiency;
}
} // namespace fces
} // namespace fces

View File

@@ -1,475 +1,496 @@
#include "fces/optimizer.hpp"
#include <algorithm>
#include <cmath>
#include <iostream>
#include <algorithm>
namespace fces {
namespace {
int classify_layer_by_shape(const torch::Tensor& p) {
auto dims = p.sizes();
if (dims.size() == 2) {
int64_t d0 = dims[0];
int64_t d1 = dims[1];
if (d0 > 10000 || d1 > 10000) {
return 0; // Embedding
} else if (d0 * 3 == d1 || d0 == d1 * 3) {
return 1; // Attention QKV
} else if (d0 == d1) {
return 3; // MLP/FFN
} else {
return 2; // Attention Proj
}
} else if (dims.size() == 1) {
if (dims[0] < 128) {
return 4; // LayerNorm
} else {
return 5; // Other / bias
}
int classify_layer_by_shape(const torch::Tensor &p) {
auto dims = p.sizes();
if (dims.size() == 2) {
int64_t d0 = dims[0];
int64_t d1 = dims[1];
if (d0 > 10000 || d1 > 10000) {
return 0; // Embedding
} else if (d0 * 3 == d1 || d0 == d1 * 3) {
return 1; // Attention QKV
} else if (d0 == d1) {
return 3; // MLP/FFN
} else {
return 2; // Attention Proj
}
return 5; // Other
} else if (dims.size() == 1) {
if (dims[0] < 128) {
return 4; // LayerNorm
} else {
return 5; // Other / bias
}
}
return 5; // Other
}
torch::Tensor apply_trust_clipping(const torch::Tensor& p, torch::Tensor update, float trust_region_clip) {
if (torch::isnan(update).any().item<bool>() || torch::isinf(update).any().item<bool>()) {
return torch::zeros_like(update);
torch::Tensor apply_trust_clipping(const torch::Tensor &p, torch::Tensor update,
float trust_region_clip) {
if (torch::isnan(update).any().item<bool>() ||
torch::isinf(update).any().item<bool>()) {
return torch::zeros_like(update);
}
float p_norm = p.norm().item<float>();
if (p_norm > 1e-6f) {
float update_mag = update.norm().item<float>();
if (!std::isfinite(update_mag)) {
return torch::zeros_like(update);
}
float p_norm = p.norm().item<float>();
if (p_norm > 1e-6f) {
float update_mag = update.norm().item<float>();
if (!std::isfinite(update_mag)) {
return torch::zeros_like(update);
}
float max_update = trust_region_clip * p_norm;
if (update_mag > max_update) {
float correction = max_update / (update_mag + 1e-8f);
update.mul_(correction);
}
float max_update = trust_region_clip * p_norm;
if (update_mag > max_update) {
float correction = max_update / (update_mag + 1e-8f);
update.mul_(correction);
}
}
if (torch::isnan(update).any().item<bool>() || torch::isinf(update).any().item<bool>()) {
return torch::zeros_like(update);
}
if (torch::isnan(update).any().item<bool>() ||
torch::isinf(update).any().item<bool>()) {
return torch::zeros_like(update);
}
return update;
return update;
}
float calculate_parasitic_reward(const torch::Tensor& p, float mult, const RunningStats& grad_norm_tracker) {
if (!p.grad().defined()) {
return 0.0f;
}
float g_norm = p.grad().abs().mean().item<float>();
float z_g = grad_norm_tracker.z_score(g_norm);
return z_g * (mult - 1.0f);
float calculate_parasitic_reward(const torch::Tensor &p, float mult,
const RunningStats &grad_norm_tracker) {
if (!p.grad().defined()) {
return 0.0f;
}
float g_norm = p.grad().abs().mean().item<float>();
float z_g = grad_norm_tracker.z_score(g_norm);
return z_g * (mult - 1.0f);
}
std::unique_ptr<torch::optim::OptimizerOptions> make_optimizer_options(double lr) {
return std::make_unique<FCESOptimizerOptions>(lr);
std::unique_ptr<torch::optim::OptimizerOptions>
make_optimizer_options(double lr) {
return std::make_unique<FCESOptimizerOptions>(lr);
}
} // namespace
FCESOptimizer::FCESOptimizer(
std::vector<torch::Tensor> params,
FCESConfig config
)
FCESOptimizer::FCESOptimizer(std::vector<torch::Tensor> params,
FCESConfig config)
: torch::optim::Optimizer(
{torch::optim::OptimizerParamGroup(std::move(params))},
make_optimizer_options(config.lr)
),
make_optimizer_options(config.lr)),
config_(std::move(config)),
population_(config_.population_size, 10000,
EliteStrategy::Cumulative,
population_(config_.population_size, 10000, EliteStrategy::Cumulative,
false, false, false, false, false,
config_.direct_construction,
config_.use_banach_fission),
config_.direct_construction, config_.use_banach_fission),
fitness_engine_(config_.grokking_coefficient) {
evolution_manager_ = std::make_unique<EvolutionManager>(
population_, 50, config_.auto_population, config_.direct_construction
);
evolution_manager_ = std::make_unique<EvolutionManager>(
population_, 50, config_.auto_population, config_.direct_construction);
spectral_sensor_ = std::make_unique<SpectralSensor>();
spectral_sensor_ = std::make_unique<SpectralSensor>();
// Initial RAM backup
backup_to_ram();
// Initial RAM backup
backup_to_ram();
Telemetry::get().info("optimizer_initialized",
"version=0.1.0 pop_size=" + std::to_string(config_.population_size));
Telemetry::get().info("optimizer_initialized",
"version=0.1.0 pop_size=" +
std::to_string(config_.population_size));
}
torch::Tensor FCESOptimizer::step(LossClosure closure) {
torch::NoGradGuard no_grad;
step_counter_++;
torch::NoGradGuard no_grad;
step_counter_++;
torch::Tensor loss = {};
if (closure) {
torch::AutoGradMode grad_mode(true);
loss = closure();
}
torch::Tensor loss = {};
if (closure) {
torch::AutoGradMode grad_mode(true);
loss = closure();
}
// 1. Gather Statistics
gather_stats();
// 1. Gather Statistics
gather_stats();
// 2. Strategy: Population Selection & Dynamics
auto& active_controller = evolution_manager_->get_active_controller();
// 2. Strategy: Population Selection & Dynamics
auto &active_controller = evolution_manager_->get_active_controller();
// 3. Decision: Neural Decisions from Controllers
float current_loss_val = (loss.defined()) ? loss.item<float>() : last_step_loss_;
// Emergency Brake - NaN/Inf Detection
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_));
handle_rollback();
return loss;
}
float loss_velocity = fitness_engine_.calculate_loss_signal(current_loss_val, ema_loss_, config_.signal_mode);
last_loss_velocity_ = loss_velocity;
float progress = std::min(1.0f, static_cast<float>(step_counter_) / 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;
if (config_.csr_enabled) {
if (step_counter_ < config_.csr_warmup_steps) {
csr_factor = 0.0f;
} else {
float steps_since_warmup = 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
float spectral_alpha = 0.0f;
if (config_.grokking_coefficient > 0.0f && spectral_sensor_) {
if (step_counter_ % config_.spectral_frequency == 0 || last_spectral_rank_ == 0.0f) {
int param_idx = 0;
for (auto& group : param_groups()) {
for (auto& p : group.params()) {
if (p.dim() >= 2) {
std::string name = "layer_" + std::to_string(param_idx);
spectral_sensor_->track_layer(name, p);
}
param_idx++;
}
}
last_spectral_rank_ = spectral_sensor_->get_global_rank();
}
spectral_alpha = last_spectral_rank_;
}
float effective_alpha = spectral_alpha * csr_factor;
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 log_spectral_alpha = std::log(effective_alpha + 1e-6f);
// Call decide_update
auto actions = active_controller.decide_update(
layer_stats_,
loss_velocity,
progress,
rollback_ema_,
grad_cv,
log_spectral_alpha,
stagnation_intensity,
kzm_damping,
loss_velocity
);
// Bandit-style Early Stopping
if (step_counter_ % 5 == 0 && loss_velocity > 0.05f) {
Telemetry::get().warning("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;
}
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));
population_.kill(active_controller);
auto& new_controller = evolution_manager_->get_active_controller();
actions = torch::zeros_like(actions);
for (int i = 0; i < actions.size(0); ++i) {
actions[i][0] = 0.5f; // log_mult default
}
}
// 4. Action: Apply Updates
apply_parameter_updates(actions);
// 5. Evolution & Maintenance
if (current_loss_val > 0.0f) {
evolution_manager_->update_population_dynamics(
loss_velocity,
ema_loss_,
step_counter_,
config_.total_steps
);
}
if (step_counter_ % 50 == 0) {
backup_to_ram();
}
// 3. Decision: Neural Decisions from Controllers
float current_loss_val =
(loss.defined()) ? loss.item<float>() : last_step_loss_;
// Emergency Brake - NaN/Inf Detection
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_));
handle_rollback();
return loss;
}
float loss_velocity = fitness_engine_.calculate_loss_signal(
current_loss_val, ema_loss_, config_.signal_mode);
last_loss_velocity_ = loss_velocity;
float progress = std::min(1.0f, static_cast<float>(step_counter_) /
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;
if (config_.csr_enabled) {
if (step_counter_ < config_.csr_warmup_steps) {
csr_factor = 0.0f;
} else {
float steps_since_warmup =
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
float spectral_alpha = 0.0f;
if (config_.grokking_coefficient > 0.0f && spectral_sensor_) {
if (step_counter_ % config_.spectral_frequency == 0 ||
last_spectral_rank_ == 0.0f) {
int param_idx = 0;
for (auto &group : param_groups()) {
for (auto &p : group.params()) {
if (p.dim() >= 2) {
std::string name = "layer_" + std::to_string(param_idx);
spectral_sensor_->track_layer(name, p);
}
param_idx++;
}
}
last_spectral_rank_ = spectral_sensor_->get_global_rank();
}
spectral_alpha = last_spectral_rank_;
}
float effective_alpha = spectral_alpha * csr_factor;
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 log_spectral_alpha = std::log(effective_alpha + 1e-6f);
// Call decide_update
auto actions = active_controller.decide_update(
layer_stats_, loss_velocity, progress, rollback_ema_, grad_cv,
log_spectral_alpha, stagnation_intensity, kzm_damping, loss_velocity);
// Bandit-style Early Stopping
if (step_counter_ % 5 == 0 && loss_velocity > 0.05f) {
Telemetry::get().warning(
"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;
}
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));
population_.kill(active_controller);
auto &new_controller = evolution_manager_->get_active_controller();
actions = torch::zeros_like(actions);
for (int i = 0; i < actions.size(0); ++i) {
actions[i][0] = 0.5f; // log_mult default
}
}
// 4. Action: Apply Updates
apply_parameter_updates(actions);
// 5. Evolution & Maintenance
if (current_loss_val > 0.0f) {
evolution_manager_->update_population_dynamics(
loss_velocity, ema_loss_, step_counter_, config_.total_steps);
}
if (step_counter_ % 50 == 0) {
backup_to_ram();
}
return loss;
}
void FCESOptimizer::update_fitness(float loss) {
// 1. Divergence Safety
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);
if (is_nan || is_spike) {
Telemetry::get().warning("divergence_detected", "loss=" + std::to_string(loss) + " ema=" + std::to_string(ema_loss_));
handle_rollback();
return;
}
// 1. Divergence Safety
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);
if (is_nan || is_spike) {
Telemetry::get().warning("divergence_detected",
"loss=" + std::to_string(loss) +
" ema=" + std::to_string(ema_loss_));
handle_rollback();
return;
}
if (step_counter_ == 1 || ema_loss_ == 0.0f) {
ema_loss_ = loss;
last_step_loss_ = loss;
last_sparsity_ = calculate_sparsity();
return;
}
// 2. Metric Calculation
float train_adv = ema_loss_ - loss;
float val_adv = 0.0f;
float current_sparsity = calculate_sparsity();
float sparsity_delta = current_sparsity - last_sparsity_;
float consistency_gap = std::max(0.0f, train_adv - val_adv);
float grad_std = grad_norm_tracker_.get_std();
float grad_mean = grad_norm_tracker_.get_mean();
float grad_cv = grad_std / (grad_mean + 1e-8f);
float raw_rank = (spectral_sensor_) ? spectral_sensor_->get_global_rank() : 0.0f;
float csr_factor = 1.0f;
if (config_.csr_enabled) {
if (step_counter_ < config_.csr_warmup_steps) {
csr_factor = 0.0f;
} else {
float steps_since_warmup = 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;
FitnessMetrics metrics;
metrics.training_advantage = train_adv;
metrics.validation_advantage = val_adv;
metrics.grad_cv = grad_cv;
metrics.sparsity_delta = sparsity_delta;
metrics.consistency_gap = consistency_gap;
metrics.stable_rank = effective_rank;
// 3. Fuzzy Evaluation
float final_fitness = fitness_evaluator_.evaluate(metrics);
// 4. State Update
ema_loss_ = 0.95f * ema_loss_ + 0.05f * loss;
if (step_counter_ == 1 || ema_loss_ == 0.0f) {
ema_loss_ = loss;
last_step_loss_ = loss;
last_sparsity_ = current_sparsity;
last_sparsity_ = calculate_sparsity();
return;
}
// Stagnation logic
if (loss < best_loss_window_ * 0.995f) {
best_loss_window_ = loss;
stagnation_counter_ = 0;
// 2. Metric Calculation
float train_adv = ema_loss_ - loss;
float val_adv = 0.0f;
float current_sparsity = calculate_sparsity();
float sparsity_delta = current_sparsity - last_sparsity_;
float consistency_gap = std::max(0.0f, train_adv - val_adv);
float grad_std = grad_norm_tracker_.get_std();
float grad_mean = grad_norm_tracker_.get_mean();
float grad_cv = grad_std / (grad_mean + 1e-8f);
float raw_rank =
(spectral_sensor_) ? spectral_sensor_->get_global_rank() : 0.0f;
float csr_factor = 1.0f;
if (config_.csr_enabled) {
if (step_counter_ < config_.csr_warmup_steps) {
csr_factor = 0.0f;
} else {
stagnation_counter_++;
float steps_since_warmup =
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;
// 5. Apply to Population
auto& active_controller = evolution_manager_->get_active_controller();
population_.update_controller_fitness(active_controller, final_fitness);
FitnessMetrics metrics;
metrics.training_advantage = train_adv;
metrics.validation_advantage = val_adv;
metrics.grad_cv = grad_cv;
metrics.sparsity_delta = sparsity_delta;
metrics.consistency_gap = consistency_gap;
metrics.stable_rank = effective_rank;
Telemetry::get().info("fitness_calculated",
"loss=" + std::to_string(loss) +
" ema_loss=" + std::to_string(ema_loss_) +
" fitness=" + std::to_string(final_fitness));
// 3. Fuzzy Evaluation
float final_fitness = fitness_evaluator_.evaluate(metrics);
// 4. State Update
ema_loss_ = 0.95f * ema_loss_ + 0.05f * loss;
last_step_loss_ = loss;
last_sparsity_ = current_sparsity;
// Stagnation logic
if (loss < best_loss_window_ * 0.995f) {
best_loss_window_ = loss;
stagnation_counter_ = 0;
} else {
stagnation_counter_++;
}
// 5. Apply to Population
auto &active_controller = evolution_manager_->get_active_controller();
population_.update_controller_fitness(active_controller, final_fitness);
Telemetry::get().info("fitness_calculated",
"loss=" + std::to_string(loss) +
" ema_loss=" + std::to_string(ema_loss_) +
" fitness=" + std::to_string(final_fitness));
}
void FCESOptimizer::backup_to_ram() {
ram_backup_.clear();
for (auto& group : param_groups()) {
for (auto& p : group.params()) {
ram_backup_.push_back(p.data().clone().cpu());
}
ram_backup_.clear();
for (auto &group : param_groups()) {
for (auto &p : group.params()) {
ram_backup_.push_back(p.data().clone().cpu());
}
}
}
void FCESOptimizer::restore_from_ram() {
int idx = 0;
for (auto& group : param_groups()) {
for (auto& p : group.params()) {
if (idx < static_cast<int>(ram_backup_.size())) {
p.data().copy_(ram_backup_[idx].to(p.device()));
idx++;
}
}
int idx = 0;
for (auto &group : param_groups()) {
for (auto &p : group.params()) {
if (idx < static_cast<int>(ram_backup_.size())) {
p.data().copy_(ram_backup_[idx].to(p.device()));
idx++;
}
}
}
}
float FCESOptimizer::calculate_sparsity() const {
int64_t total = 0, zeros = 0;
for (const auto& group : param_groups()) {
for (const auto& p : group.params()) {
total += p.numel();
zeros += (p.data().abs() < 1e-5f).sum().item<int64_t>();
}
int64_t total = 0, zeros = 0;
for (const auto &group : param_groups()) {
for (const auto &p : group.params()) {
total += p.numel();
zeros += (p.data().abs() < 1e-5f).sum().item<int64_t>();
}
return (total > 0) ? static_cast<float>(zeros) / total : 0.0f;
}
return (total > 0) ? static_cast<float>(zeros) / total : 0.0f;
}
void FCESOptimizer::gather_stats() {
layer_stats_.clear();
param_group_mapping_.clear();
layer_stats_.clear();
param_group_mapping_.clear();
int param_idx = 0;
bool has_nan_or_inf = false;
float max_grad_norm = 0.0f;
int param_idx = 0;
bool has_nan_or_inf = false;
float max_grad_norm = 0.0f;
for (auto& group : param_groups()) {
for (auto& p : group.params()) {
if (!p.grad().defined()) {
param_group_mapping_.push_back(-1);
continue;
}
for (auto &group : param_groups()) {
for (auto &p : group.params()) {
if (!p.grad().defined()) {
param_group_mapping_.push_back(-1);
continue;
}
auto grad = p.grad();
if (torch::isnan(grad).any().item<bool>() || torch::isinf(grad).any().item<bool>()) {
has_nan_or_inf = true;
}
auto grad = p.grad();
if (torch::isnan(grad).any().item<bool>() ||
torch::isinf(grad).any().item<bool>()) {
has_nan_or_inf = true;
}
float grad_norm = grad.norm().item<float>();
if (std::isnan(grad_norm) || !std::isfinite(grad_norm)) {
has_nan_or_inf = true;
grad_norm = 0.0f;
}
float grad_norm = grad.norm().item<float>();
if (std::isnan(grad_norm) || !std::isfinite(grad_norm)) {
has_nan_or_inf = true;
grad_norm = 0.0f;
}
if (grad_norm > max_grad_norm) {
max_grad_norm = grad_norm;
}
if (grad_norm > max_grad_norm) {
max_grad_norm = grad_norm;
}
int64_t total_elements = grad.numel();
int64_t zeros = (grad.abs() < 1e-5f).sum().item<int64_t>();
float sparsity = (total_elements > 0) ? static_cast<float>(zeros) / total_elements : 0.0f;
int64_t total_elements = grad.numel();
int64_t zeros = (grad.abs() < 1e-5f).sum().item<int64_t>();
float sparsity = (total_elements > 0)
? static_cast<float>(zeros) / total_elements
: 0.0f;
int layer_type = classify_layer_by_shape(p);
int group_idx = static_cast<int>(layer_stats_.size());
layer_stats_.push_back({grad_norm, sparsity, static_cast<float>(layer_type)});
param_group_mapping_.push_back(group_idx);
int layer_type = classify_layer_by_shape(p);
int group_idx = static_cast<int>(layer_stats_.size());
layer_stats_.push_back(
{grad_norm, sparsity, static_cast<float>(layer_type)});
param_group_mapping_.push_back(group_idx);
if (spectral_sensor_ && p.dim() >= 2) {
std::string name = "layer_" + std::to_string(param_idx);
spectral_sensor_->track_layer(name, p);
}
if (spectral_sensor_ && p.dim() >= 2) {
std::string name = "layer_" + std::to_string(param_idx);
spectral_sensor_->track_layer(name, p);
}
param_idx++;
}
param_idx++;
}
}
if (has_nan_or_inf) {
Telemetry::get().error("poisoned_gradients_detected",
"NaN/Inf detected in gradients during step " + std::to_string(step_counter_));
handle_rollback();
return;
}
if (has_nan_or_inf) {
Telemetry::get().error("poisoned_gradients_detected",
"NaN/Inf detected in gradients during step " +
std::to_string(step_counter_));
handle_rollback();
return;
}
if (step_counter_ == 1 && max_grad_norm > 1.0f) {
float safe_lr = 0.01f / (max_grad_norm + 1e-8f);
for (auto& group : param_groups()) {
if (group.options().get_lr() > safe_lr) {
Telemetry::get().info("auto_calibration_throttled_lr",
"old=" + std::to_string(group.options().get_lr()) + " new=" + std::to_string(safe_lr));
group.options().set_lr(safe_lr);
config_.lr = safe_lr;
}
}
if (step_counter_ == 1 && max_grad_norm > 1.0f) {
float safe_lr = 0.01f / (max_grad_norm + 1e-8f);
for (auto &group : param_groups()) {
if (group.options().get_lr() > safe_lr) {
Telemetry::get().info(
"auto_calibration_throttled_lr",
"old=" + std::to_string(group.options().get_lr()) +
" new=" + std::to_string(safe_lr));
group.options().set_lr(safe_lr);
config_.lr = safe_lr;
}
}
}
if (!layer_stats_.empty()) {
float first_grad_norm = layer_stats_[0][0];
grad_norm_tracker_.update(first_grad_norm);
}
if (!layer_stats_.empty()) {
float first_grad_norm = layer_stats_[0][0];
grad_norm_tracker_.update(first_grad_norm);
}
}
void FCESOptimizer::apply_parameter_updates(const torch::Tensor& actions) {
int param_idx = 0;
float parasitic_accum = 0.0f;
int count_updated = 0;
void FCESOptimizer::apply_parameter_updates(const torch::Tensor &actions) {
int param_idx = 0;
float parasitic_accum = 0.0f;
int count_updated = 0;
auto& active_controller = evolution_manager_->get_active_controller();
auto &active_controller = evolution_manager_->get_active_controller();
for (auto& group : param_groups()) {
float lr = static_cast<float>(group.options().get_lr());
float wd = config_.weight_decay;
for (auto &group : param_groups()) {
float lr = static_cast<float>(group.options().get_lr());
float wd = config_.weight_decay;
for (auto& p : group.params()) {
if (!p.grad().defined()) {
param_idx++;
continue;
}
for (auto &p : group.params()) {
if (!p.grad().defined()) {
param_idx++;
continue;
}
int g_idx = param_group_mapping_[param_idx];
if (g_idx < 0 || g_idx >= actions.size(0)) {
param_idx++;
continue;
}
int g_idx = param_group_mapping_[param_idx];
if (g_idx < 0 || g_idx >= actions.size(0)) {
param_idx++;
continue;
}
float mult = actions[g_idx][0].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 mult = actions[g_idx][0].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;
bool use_sign = sign_gate > 0.0f;
if (config_.ablation_mode == "force_sign") {
use_sign = true;
} else if (config_.ablation_mode == "force_grad") {
use_sign = false;
}
bool use_sign = sign_gate > 0.0f;
if (config_.ablation_mode == "force_sign") {
use_sign = true;
} else if (config_.ablation_mode == "force_grad") {
use_sign = false;
}
if (wd > 0.0f) {
float effective_wd = wd;
if (config_.adaptive_wd) {
effective_wd *= wd_mult;
}
p.data().mul_(1.0f - lr * effective_wd);
}
torch::Tensor update_vec = use_sign ? torch::sign(p.grad()) : p.grad();
torch::Tensor update = -lr * mult * update_vec;
update = apply_trust_clipping(p, update, config_.trust_region_clip);
p.data().add_(update);
if (config_.parasitic_mode) {
parasitic_accum += calculate_parasitic_reward(p, mult, grad_norm_tracker_);
}
param_idx++;
count_updated++;
if (wd > 0.0f) {
float effective_wd = wd;
if (config_.adaptive_wd) {
effective_wd *= wd_mult;
}
}
p.data().mul_(1.0f - lr * effective_wd);
}
if (config_.parasitic_mode && count_updated > 0) {
float reward = parasitic_accum / static_cast<float>(count_updated);
population_.update_controller_fitness(active_controller, reward * 10.0f, false);
torch::Tensor update_vec = use_sign ? torch::sign(p.grad()) : p.grad();
torch::Tensor update = -lr * mult * update_vec;
update = apply_trust_clipping(p, update, config_.trust_region_clip);
p.data().add_(update);
if (config_.parasitic_mode) {
parasitic_accum +=
calculate_parasitic_reward(p, mult, grad_norm_tracker_);
}
param_idx++;
count_updated++;
}
}
if (config_.parasitic_mode && count_updated > 0) {
float reward = parasitic_accum / static_cast<float>(count_updated);
population_.update_controller_fitness(active_controller, reward * 10.0f,
false);
}
}
void FCESOptimizer::handle_rollback() {
restore_from_ram();
population_.calm_down();
rollback_ema_ = 0.9f * rollback_ema_ + 0.1f;
restore_from_ram();
population_.calm_down();
rollback_ema_ = 0.9f * rollback_ema_ + 0.1f;
ema_loss_ = 0.0f;
last_step_loss_ = 0.0f;
grad_norm_tracker_.reset();
zero_grad();
ema_loss_ = 0.0f;
last_step_loss_ = 0.0f;
grad_norm_tracker_.reset();
zero_grad();
Telemetry::get().warning("hard_reset_executed", "rollback_sanitization");
Telemetry::get().warning("hard_reset_executed", "rollback_sanitization");
}
} // namespace fces

View File

@@ -1,97 +1,103 @@
#include "fces/oscillation.hpp"
#include <algorithm>
#include <cmath>
#include <numeric>
#include <algorithm>
namespace fces {
void OscillationDetector::update(float loss) {
loss_history_.push_back(loss);
if (static_cast<int>(loss_history_.size()) > WINDOW_SIZE) {
loss_history_.erase(loss_history_.begin());
}
loss_history_.push_back(loss);
if (static_cast<int>(loss_history_.size()) > WINDOW_SIZE) {
loss_history_.erase(loss_history_.begin());
}
}
bool OscillationDetector::detect() const {
return get_score() > POWER_THRESHOLD;
return get_score() > POWER_THRESHOLD;
}
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 power = compute_power_spectrum(detrended);
auto detrended = detrend(loss_history_);
auto power = compute_power_spectrum(detrended);
// Sum power in oscillation bands (periods 4-16)
float osc_power = 0.0f;
float total_power = 0.0f;
int n = static_cast<int>(power.size());
for (int i = 1; i < n; ++i) {
total_power += power[i];
int period = n / i;
if (period >= MIN_PERIOD && period <= MAX_PERIOD) {
osc_power += power[i];
}
// Sum power in oscillation bands (periods 4-16)
float osc_power = 0.0f;
float total_power = 0.0f;
int n = static_cast<int>(power.size());
for (int i = 1; i < n; ++i) {
total_power += power[i];
int period = n / i;
if (period >= MIN_PERIOD && period <= MAX_PERIOD) {
osc_power += power[i];
}
}
if (total_power < 1e-8f) return 0.0f;
return osc_power / total_power;
if (total_power < 1e-8f)
return 0.0f;
return osc_power / total_power;
}
float OscillationDetector::get_variance_50() const {
if (loss_history_.size() < 50) return 0.0f;
auto start = loss_history_.end() - 50;
float mean = std::accumulate(start, loss_history_.end(), 0.0f) / 50.0f;
float var = 0.0f;
for (auto it = start; it != loss_history_.end(); ++it) {
float d = *it - mean;
var += d * d;
}
return var / 50.0f;
if (loss_history_.size() < 50)
return 0.0f;
auto start = loss_history_.end() - 50;
float mean = std::accumulate(start, loss_history_.end(), 0.0f) / 50.0f;
float var = 0.0f;
for (auto it = start; it != loss_history_.end(); ++it) {
float d = *it - mean;
var += d * d;
}
return var / 50.0f;
}
void OscillationDetector::reset() {
loss_history_.clear();
void OscillationDetector::reset() { loss_history_.clear(); }
std::vector<float>
OscillationDetector::detrend(const std::vector<float> &signal) {
int n = static_cast<int>(signal.size());
if (n < 2)
return signal;
// Remove linear trend via least squares
float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
for (int i = 0; i < n; ++i) {
sum_x += i;
sum_y += signal[i];
sum_xy += i * signal[i];
sum_xx += i * i;
}
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;
std::vector<float> result(n);
for (int i = 0; i < n; ++i) {
result[i] = signal[i] - (slope * i + intercept);
}
return result;
}
std::vector<float> OscillationDetector::detrend(const std::vector<float>& signal) {
int n = static_cast<int>(signal.size());
if (n < 2) return signal;
std::vector<float>
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 half = n / 2;
std::vector<float> power(half);
// Remove linear trend via least squares
float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
for (int i = 0; i < n; ++i) {
sum_x += i;
sum_y += signal[i];
sum_xy += i * signal[i];
sum_xx += i * i;
for (int k = 0; k < half; ++k) {
float re = 0.0f, im = 0.0f;
for (int t = 0; t < n; ++t) {
float angle = 2.0f * 3.14159265358979f * k * t / n;
re += signal[t] * std::cos(angle);
im -= signal[t] * std::sin(angle);
}
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;
std::vector<float> result(n);
for (int i = 0; i < n; ++i) {
result[i] = signal[i] - (slope * i + intercept);
}
return result;
power[k] = re * re + im * im;
}
return power;
}
std::vector<float> 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 half = n / 2;
std::vector<float> power(half);
for (int k = 0; k < half; ++k) {
float re = 0.0f, im = 0.0f;
for (int t = 0; t < n; ++t) {
float angle = 2.0f * 3.14159265358979f * k * t / n;
re += signal[t] * std::cos(angle);
im -= signal[t] * std::sin(angle);
}
power[k] = re * re + im * im;
}
return power;
}
} // namespace fces
} // namespace fces

File diff suppressed because it is too large Load Diff

View File

@@ -3,39 +3,40 @@
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) {
if (weight.dim() >= 2) {
layer_ranks_[name] = compute_effective_rank(weight);
}
void SpectralSensor::track_layer(const std::string &name,
const torch::Tensor &weight) {
if (weight.dim() >= 2) {
layer_ranks_[name] = compute_effective_rank(weight);
}
}
float SpectralSensor::get_global_rank() const {
if (layer_ranks_.empty()) return 0.0f;
float sum = 0.0f;
for (const auto& [_, rank] : layer_ranks_) {
sum += rank;
}
return sum / static_cast<float>(layer_ranks_.size());
if (layer_ranks_.empty())
return 0.0f;
float sum = 0.0f;
for (const auto &[_, rank] : layer_ranks_) {
sum += rank;
}
return sum / static_cast<float>(layer_ranks_.size());
}
void SpectralSensor::reset() {
layer_ranks_.clear();
void SpectralSensor::reset() { layer_ranks_.clear(); }
float SpectralSensor::compute_effective_rank(const torch::Tensor &weight) {
// SVD-based effective rank (Shannon entropy of normalized singular values)
auto svd_result = torch::svd(weight.to(torch::kFloat32));
auto svd = std::get<1>(svd_result);
auto s = svd / svd.sum();
auto log_s = (s + 1e-10f).log();
float entropy = -s.mul(log_s).sum().item<float>();
return std::exp(entropy);
}
float SpectralSensor::compute_effective_rank(const torch::Tensor& weight) {
// SVD-based effective rank (Shannon entropy of normalized singular values)
auto svd_result = torch::svd(weight.to(torch::kFloat32));
auto svd = std::get<1>(svd_result);
auto s = svd / svd.sum();
auto log_s = (s + 1e-10f).log();
float entropy = -s.mul(log_s).sum().item<float>();
return std::exp(entropy);
float SpectralController::compute_alpha(float global_rank,
float grokking_coefficient) const {
return global_rank * grokking_coefficient;
}
float SpectralController::compute_alpha(float global_rank, float grokking_coefficient) const {
return global_rank * grokking_coefficient;
}
} // namespace fces
} // namespace fces

View File

@@ -1,34 +1,37 @@
#include "fces/telemetry.hpp"
#include <iostream>
#include <chrono>
#include <iostream>
namespace fces {
Telemetry& Telemetry::get() {
static Telemetry instance;
return instance;
Telemetry &Telemetry::get() {
static Telemetry instance;
return instance;
}
void Telemetry::info(const std::string& event, const std::string& detail) {
std::cout << "[INFO] " << event;
if (!detail.empty()) std::cout << " | " << detail;
std::cout << std::endl;
void Telemetry::info(const std::string &event, const std::string &detail) {
std::cout << "[INFO] " << event;
if (!detail.empty())
std::cout << " | " << detail;
std::cout << std::endl;
}
void Telemetry::warning(const std::string& event, const std::string& detail) {
std::cerr << "[WARN] " << event;
if (!detail.empty()) std::cerr << " | " << detail;
std::cerr << std::endl;
void Telemetry::warning(const std::string &event, const std::string &detail) {
std::cerr << "[WARN] " << event;
if (!detail.empty())
std::cerr << " | " << detail;
std::cerr << std::endl;
}
void Telemetry::error(const std::string& event, const std::string& detail) {
std::cerr << "[ERROR] " << event;
if (!detail.empty()) std::cerr << " | " << detail;
std::cerr << std::endl;
void Telemetry::error(const std::string &event, const std::string &detail) {
std::cerr << "[ERROR] " << event;
if (!detail.empty())
std::cerr << " | " << detail;
std::cerr << std::endl;
}
void Telemetry::push_to_remote() {
// TODO: Implement telemetry push (Git sync, file export, etc.)
// TODO: Implement telemetry push (Git sync, file export, etc.)
}
} // namespace fces
} // namespace fces

View File

@@ -1,58 +1,59 @@
#include <gtest/gtest.h>
#include "fces/controller.hpp"
#include <gtest/gtest.h>
using namespace fces;
TEST(ControllerTest, Construction) {
FuzzyController ctrl;
EXPECT_GT(ctrl.id, 0u);
EXPECT_EQ(ctrl.fitness, 0.0f);
EXPECT_EQ(ctrl.origin, "random");
FuzzyController ctrl;
EXPECT_GT(ctrl.id, 0u);
EXPECT_EQ(ctrl.fitness, 0.0f);
EXPECT_EQ(ctrl.origin, "random");
}
TEST(ControllerTest, GenomeSize) {
FuzzyController ctrl;
EXPECT_EQ(ctrl.genome.weights.size(), static_cast<size_t>(GENOME_SIZE));
FuzzyController ctrl;
EXPECT_EQ(ctrl.genome.weights.size(), static_cast<size_t>(GENOME_SIZE));
}
TEST(ControllerTest, Mutation) {
FuzzyController parent;
auto child = parent.mutate(1.0f);
EXPECT_NE(child.id, parent.id);
EXPECT_EQ(child.origin, "mutation");
// Child should differ from parent
bool differs = false;
for (size_t i = 0; i < parent.genome.weights.size(); ++i) {
if (parent.genome.weights[i] != child.genome.weights[i]) {
differs = true;
break;
}
FuzzyController parent;
auto child = parent.mutate(1.0f);
EXPECT_NE(child.id, parent.id);
EXPECT_EQ(child.origin, "mutation");
// Child should differ from parent
bool differs = false;
for (size_t i = 0; i < parent.genome.weights.size(); ++i) {
if (parent.genome.weights[i] != child.genome.weights[i]) {
differs = true;
break;
}
EXPECT_TRUE(differs);
}
EXPECT_TRUE(differs);
}
TEST(ControllerTest, Crossover) {
FuzzyController a, b;
auto child = a.crossover(b);
EXPECT_EQ(child.origin, "crossover");
FuzzyController a, b;
auto child = a.crossover(b);
EXPECT_EQ(child.origin, "crossover");
}
TEST(ControllerTest, DecideUpdate) {
FuzzyController ctrl;
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);
EXPECT_EQ(actions.size(0), 1);
EXPECT_EQ(actions.size(1), GENOME_OUTPUT_DIM);
FuzzyController ctrl;
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);
EXPECT_EQ(actions.size(0), 1);
EXPECT_EQ(actions.size(1), GENOME_OUTPUT_DIM);
}
TEST(ControllerTest, OrthogonalChild) {
FuzzyController parent;
auto child = parent.create_orthogonal_child(1.0f);
EXPECT_EQ(child.origin, "phoenix_rebirth");
FuzzyController parent;
auto child = parent.create_orthogonal_child(1.0f);
EXPECT_EQ(child.origin, "phoenix_rebirth");
}
TEST(ControllerTest, BanachFission) {
FuzzyController parent;
auto [plus, minus] = parent.banach_tarski_fission(1.0f);
EXPECT_NE(plus.id, minus.id);
FuzzyController parent;
auto [plus, minus] = parent.banach_tarski_fission(1.0f);
EXPECT_NE(plus.id, minus.id);
}

View File

@@ -1,33 +1,34 @@
#include <gtest/gtest.h>
#include "fces/fitness.hpp"
#include <gtest/gtest.h>
using namespace fces;
TEST(RunningStatsTest, BasicUpdate) {
RunningStats stats;
stats.update(1.0f);
stats.update(2.0f);
stats.update(3.0f);
EXPECT_NEAR(stats.get_mean(), 2.0f, 1e-5f);
EXPECT_GT(stats.get_std(), 0.0f);
RunningStats stats;
stats.update(1.0f);
stats.update(2.0f);
stats.update(3.0f);
EXPECT_NEAR(stats.get_mean(), 2.0f, 1e-5f);
EXPECT_GT(stats.get_std(), 0.0f);
}
TEST(RunningStatsTest, ZScore) {
RunningStats stats;
for (int i = 0; i < 100; ++i) stats.update(static_cast<float>(i));
float z = stats.z_score(50.0f);
EXPECT_NEAR(z, 0.0f, 0.1f);
RunningStats stats;
for (int i = 0; i < 100; ++i)
stats.update(static_cast<float>(i));
float z = stats.z_score(50.0f);
EXPECT_NEAR(z, 0.0f, 0.1f);
}
TEST(FitnessEngineTest, LossSignal) {
FitnessEngine engine;
float sig = engine.calculate_loss_signal(1.0f, 2.0f, "relative");
EXPECT_LT(sig, 0.0f); // Improving
FitnessEngine engine;
float sig = engine.calculate_loss_signal(1.0f, 2.0f, "relative");
EXPECT_LT(sig, 0.0f); // Improving
}
TEST(FitnessEngineTest, KZMDamping) {
FitnessEngine engine(0.1f);
float d = engine.compute_kzm_damping(5.0f);
EXPECT_GT(d, 0.0f);
EXPECT_LT(d, 1.0f);
FitnessEngine engine(0.1f);
float d = engine.compute_kzm_damping(5.0f);
EXPECT_GT(d, 0.0f);
EXPECT_LT(d, 1.0f);
}

View File

@@ -1,42 +1,45 @@
#include "fces/optimizer.hpp"
#include <gtest/gtest.h>
#include <torch/torch.h>
#include "fces/optimizer.hpp"
using namespace fces;
TEST(OptimizerTest, Construction) {
auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p);
auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params;
for (auto &p : model->parameters())
params.push_back(p);
FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f));
EXPECT_EQ(opt.step_count(), 0);
FCESOptimizer opt(params, FCESConfig{}.set_lr(1e-3f));
EXPECT_EQ(opt.step_count(), 0);
}
TEST(OptimizerTest, StepUpdatesCounter) {
auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p);
auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params;
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));
// Simulate a training step
auto x = torch::randn({2, 10});
auto y = model->forward(x);
auto loss = y.sum();
loss.backward();
opt.step();
// Simulate a training step
auto x = torch::randn({2, 10});
auto y = model->forward(x);
auto loss = y.sum();
loss.backward();
opt.step();
EXPECT_EQ(opt.step_count(), 1);
EXPECT_EQ(opt.step_count(), 1);
}
TEST(OptimizerTest, UpdateFitness) {
auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params;
for (auto& p : model->parameters()) params.push_back(p);
auto model = torch::nn::Linear(10, 5);
std::vector<torch::Tensor> params;
for (auto &p : model->parameters())
params.push_back(p);
FCESOptimizer opt(params);
opt.update_fitness(3.0f);
opt.update_fitness(2.5f);
// Should not crash
FCESOptimizer opt(params);
opt.update_fitness(3.0f);
opt.update_fitness(2.5f);
// Should not crash
}

View File

@@ -1,28 +1,28 @@
#include <gtest/gtest.h>
#include "fces/population.hpp"
#include <gtest/gtest.h>
using namespace fces;
TEST(PopulationTest, Construction) {
Population pop(50);
EXPECT_EQ(pop.size(), 50);
Population pop(50);
EXPECT_EQ(pop.size(), 50);
}
TEST(PopulationTest, DirectConstruction) {
Population pop(200, 10000, EliteStrategy::Cumulative,
false, false, false, false, false, true);
EXPECT_EQ(pop.size(), 1);
Population pop(200, 10000, EliteStrategy::Cumulative, false, false, false,
false, false, true);
EXPECT_EQ(pop.size(), 1);
}
TEST(PopulationTest, GetBestActive) {
Population pop(10);
auto& best = pop.get_best_active();
// Should not crash
EXPECT_GE(best.id, 0u);
Population pop(10);
auto &best = pop.get_best_active();
// Should not crash
EXPECT_GE(best.id, 0u);
}
TEST(PopulationTest, CalmDown) {
Population pop(10);
pop.calm_down();
EXPECT_LT(pop.global_sigma_modifier(), 1.0f);
Population pop(10);
pop.calm_down();
EXPECT_LT(pop.global_sigma_modifier(), 1.0f);
}