checkpoint: port evolutionary and population dynamics

This commit is contained in:
AI-anonymous
2026-05-19 21:48:41 +02:00
parent 9bbe253810
commit 3ac230d16e
8 changed files with 832 additions and 99 deletions

View File

@@ -22,9 +22,9 @@
namespace fces { namespace fces {
// Controller input dimension (layer stats features) // Controller input dimension (layer stats features)
constexpr int GENOME_INPUT_DIM = 9; constexpr int GENOME_INPUT_DIM = 14;
// Controller hidden dimension // Controller hidden dimension
constexpr int GENOME_HIDDEN_DIM = 16; constexpr int GENOME_HIDDEN_DIM = 8;
// Controller output dimension: [multiplier, sign_gate, wd_mult] // Controller output dimension: [multiplier, sign_gate, wd_mult]
constexpr int GENOME_OUTPUT_DIM = 3; constexpr int GENOME_OUTPUT_DIM = 3;
// Total genome size: input->hidden weights + hidden biases + hidden->output weights + output biases // Total genome size: input->hidden weights + hidden biases + hidden->output weights + output biases

View File

@@ -59,19 +59,55 @@ private:
float grokking_coefficient_; float grokking_coefficient_;
}; };
/**
* FuzzySet represents a fuzzy set with a trapezoidal membership function.
*/
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) {}
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_; }
private:
std::string name_;
float a_;
float b_;
float c_;
float d_;
};
/** /**
* Fitness metrics for multi-objective evaluation. * Fitness metrics for multi-objective evaluation.
*/ */
struct FitnessMetrics { struct FitnessMetrics {
float loss_improvement = 0.0f; float training_advantage = 0.0f;
float sparsity_score = 0.0f; float validation_advantage = 0.0f;
float stability_score = 0.0f; float grad_cv = 0.0f;
float novelty_score = 0.0f; float sparsity_delta = 0.0f;
float consistency_gap = 0.0f;
/// Weighted combination float stable_rank = 0.0f;
float total(float alpha = 0.7f, float beta = 0.3f) const {
return alpha * loss_improvement + beta * sparsity_score;
}
}; };
/** /**
@@ -79,12 +115,24 @@ struct FitnessMetrics {
*/ */
class FuzzyFitnessEvaluator { class FuzzyFitnessEvaluator {
public: public:
FitnessMetrics evaluate( FuzzyFitnessEvaluator() noexcept;
float loss_before,
float loss_after, float evaluate(const FitnessMetrics& metrics) const noexcept;
float sparsity = 0.0f,
float val_loss = -1.0f private:
) const; 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;
}; };
} // namespace fces } // namespace fces

View File

@@ -74,10 +74,18 @@ private:
float rollback_ema_ = 0.0f; float rollback_ema_ = 0.0f;
int stagnation_counter_ = 0; int stagnation_counter_ = 0;
float last_loss_velocity_ = 0.0f; float last_loss_velocity_ = 0.0f;
float last_sparsity_ = 0.0f;
// RAM backup // RAM backup
std::vector<torch::Tensor> 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;
// Internal methods // Internal methods
void gather_stats(); void gather_stats();
void apply_parameter_updates(const torch::Tensor& actions); void apply_parameter_updates(const torch::Tensor& actions);

View File

@@ -23,6 +23,7 @@ namespace fces {
*/ */
class SpectralSensor { class SpectralSensor {
public: public:
SpectralSensor() = default;
explicit SpectralSensor(torch::nn::Module& model); explicit SpectralSensor(torch::nn::Module& model);
/// Track a layer's weight tensor /// Track a layer's weight tensor

View File

@@ -30,14 +30,21 @@ Genome Genome::clone() const {
// --------------------------------------------------------------- // ---------------------------------------------------------------
FuzzyController::FuzzyController() FuzzyController::FuzzyController()
: id(next_id_++), origin("random") { : id(next_id_++), origin("genesis") {
genome.randomize(rng_); genome.randomize(rng_);
// Bias output toward acceleration (V2.1 insight) // Bias output toward acceleration (V2.1 insight)
// Set output biases (last GENOME_OUTPUT_DIM elements) to +2.0 // Set output biases (last GENOME_OUTPUT_DIM elements) to +2.0, -1.0, 0.0 with noise
constexpr int bias_start = GENOME_SIZE - GENOME_OUTPUT_DIM; constexpr int bias_start = GENOME_SIZE - GENOME_OUTPUT_DIM;
for (int i = bias_start; i < GENOME_SIZE; ++i) { std::normal_distribution<float> bias_noise(0.0f, 0.5f);
genome.weights[i] = 2.0f; 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);
} }
FuzzyController::FuzzyController(Genome genome) FuzzyController::FuzzyController(Genome genome)
@@ -61,46 +68,111 @@ torch::Tensor FuzzyController::decide_update(
const float* w = genome.weights.data(); const float* w = genome.weights.data();
// Layer 1: input -> hidden // Layer 1: input -> hidden
const float* W1 = w; // [GENOME_INPUT_DIM x GENOME_HIDDEN_DIM] const float* W1 = w; // [(GENOME_INPUT_DIM + 1) x GENOME_HIDDEN_DIM]
const float* b1 = w + (GENOME_INPUT_DIM * GENOME_HIDDEN_DIM); // [GENOME_HIDDEN_DIM]
// Layer 2: hidden -> output // Layer 2: hidden -> output
const float* W2 = b1 + GENOME_HIDDEN_DIM; // [GENOME_HIDDEN_DIM x GENOME_OUTPUT_DIM] const float* W2 = w + ((GENOME_INPUT_DIM + 1) * GENOME_HIDDEN_DIM); // [(GENOME_HIDDEN_DIM + 1) x GENOME_OUTPUT_DIM]
const float* b2 = W2 + (GENOME_HIDDEN_DIM * GENOME_OUTPUT_DIM); // [GENOME_OUTPUT_DIM]
for (int g = 0; g < num_groups; ++g) { 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 // Build input vector
std::array<float, GENOME_INPUT_DIM> input{}; std::array<float, GENOME_INPUT_DIM> input{};
if (!layer_stats[g].empty()) { float gn = (layer_stats[g].size() >= 1) ? layer_stats[g][0] : 0.0f;
// Copy available stats, pad with context float sp = (layer_stats[g].size() >= 2) ? layer_stats[g][1] : 0.0f;
const int n = std::min(static_cast<int>(layer_stats[g].size()), GENOME_INPUT_DIM - 4);
for (int i = 0; i < n; ++i) {
input[i] = layer_stats[g][i];
}
}
// Append global context
input[GENOME_INPUT_DIM - 4] = loss_trend;
input[GENOME_INPUT_DIM - 3] = step_pct;
input[GENOME_INPUT_DIM - 2] = grad_stability;
input[GENOME_INPUT_DIM - 1] = stagnation_intensity;
// Forward pass: hidden = tanh(W1 * input + b1) // 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{}; std::array<float, GENOME_HIDDEN_DIM> hidden{};
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) { for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
float sum = b1[h]; float sum = W1[GENOME_INPUT_DIM * GENOME_HIDDEN_DIM + h]; // Bias weight
for (int i = 0; i < GENOME_INPUT_DIM; ++i) { for (int i = 0; i < GENOME_INPUT_DIM; ++i) {
sum += W1[h * GENOME_INPUT_DIM + i] * input[i]; sum += input[i] * W1[i * GENOME_HIDDEN_DIM + h];
} }
hidden[h] = std::tanh(sum); hidden[h] = std::tanh(sum);
} }
// Output = W2 * hidden + b2 // Output = W2 * [hidden, 1]
std::array<float, GENOME_OUTPUT_DIM> out_layer{};
for (int o = 0; o < GENOME_OUTPUT_DIM; ++o) { for (int o = 0; o < GENOME_OUTPUT_DIM; ++o) {
float sum = b2[o]; float sum = W2[GENOME_HIDDEN_DIM * GENOME_OUTPUT_DIM + o]; // Bias weight
for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) { for (int h = 0; h < GENOME_HIDDEN_DIM; ++h) {
sum += W2[o * GENOME_HIDDEN_DIM + h] * hidden[h]; sum += hidden[h] * W2[h * GENOME_OUTPUT_DIM + o];
} }
actions[g][o] = sum; 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; return actions;
@@ -108,67 +180,174 @@ torch::Tensor FuzzyController::decide_update(
FuzzyController FuzzyController::mutate(float current_loss, float sigma_scale) const { FuzzyController FuzzyController::mutate(float current_loss, float sigma_scale) const {
Genome child_genome = genome.clone(); Genome child_genome = genome.clone();
std::normal_distribution<float> noise(0.0f, genome.sigma_gene * sigma_scale); 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 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;
std::normal_distribution<float> noise(0.0f, effective_sigma);
for (size_t i = 0; i < child_genome.weights.size(); ++i) { for (size_t i = 0; i < child_genome.weights.size(); ++i) {
child_genome.weights[i] += noise(rng_); 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;
FuzzyController child(child_genome); FuzzyController child(child_genome);
child.origin = "mutation"; child.origin = "mutation";
return child; return child;
} }
FuzzyController FuzzyController::crossover(const FuzzyController& partner, bool use_alignment) const { FuzzyController FuzzyController::crossover(const FuzzyController& partner, bool /*use_alignment*/) const {
Genome child_genome; Genome child_genome;
std::uniform_real_distribution<float> coin(0.0f, 1.0f); std::uniform_real_distribution<float> u_dist(0.0f, 1.0f);
for (size_t i = 0; i < child_genome.weights.size(); ++i) { for (size_t i = 0; i < child_genome.weights.size(); ++i) {
if (use_alignment && genome.gene_success[i] > partner.genome.gene_success[i]) { float success_self = genome.gene_success[i];
child_genome.weights[i] = genome.weights[i]; float success_partner = partner.genome.gene_success[i];
} else if (use_alignment && partner.genome.gene_success[i] > genome.gene_success[i]) { float prob_a = success_self / (success_self + success_partner + 1e-9f);
child_genome.weights[i] = partner.genome.weights[i];
bool choose_self = false;
if (u_dist(rng_) < 0.1f) {
// 10% Random injection
choose_self = (u_dist(rng_) < 0.5f);
} else { } else {
// Uniform crossover // 90% Meritocratic
child_genome.weights[i] = (coin(rng_) < 0.5f) choose_self = (u_dist(rng_) < prob_a);
? genome.weights[i] }
: partner.genome.weights[i];
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;
} }
child_genome.gene_success[i] = 0.0f;
} }
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); FuzzyController child(child_genome);
child.origin = "crossover"; child.origin = "crossover";
return child; return child;
} }
FuzzyController FuzzyController::create_orthogonal_child(float intensity) const { FuzzyController FuzzyController::create_orthogonal_child(float intensity) const {
Genome child_genome = genome.clone(); Genome child_genome;
// Negate a random subset of weights std::normal_distribution<float> norm_dist(0.0f, 1.0f);
std::uniform_real_distribution<float> coin(0.0f, 1.0f);
for (size_t i = 0; i < child_genome.weights.size(); ++i) { float norm_elite = 0.0f;
if (coin(rng_) < 0.3f * intensity) { for (float w : genome.weights) {
child_genome.weights[i] = -child_genome.weights[i]; norm_elite += w * w;
}
norm_elite = std::sqrt(norm_elite) + 1e-9f;
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) {
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); FuzzyController child(child_genome);
child.origin = "phoenix_rebirth"; child.origin = "phoenix_rebirth";
return child; return child;
} }
std::pair<FuzzyController, FuzzyController> FuzzyController::banach_tarski_fission(float intensity) const { std::pair<FuzzyController, FuzzyController> FuzzyController::banach_tarski_fission(float intensity) const {
Genome plus_genome = genome.clone(); Genome plus_genome;
Genome minus_genome = genome.clone(); Genome minus_genome;
std::normal_distribution<float> noise(0.0f, 0.1f * intensity);
for (size_t i = 0; i < genome.weights.size(); ++i) { float norm_parent = 0.0f;
float delta = noise(rng_); float max_success = 0.0f;
plus_genome.weights[i] += delta; for (size_t i = 0; i < GENOME_SIZE; ++i) {
minus_genome.weights[i] -= delta; 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;
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];
} }
return {FuzzyController(plus_genome), FuzzyController(minus_genome)}; 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;
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.plasticity = genome.plasticity;
minus_genome.plasticity = genome.plasticity;
FuzzyController child_plus(plus_genome);
child_plus.origin = "fission_plus";
FuzzyController child_minus(minus_genome);
child_minus.origin = "fission_minus";
return {child_plus, child_minus};
} }
} // namespace fces } // namespace fces

View File

@@ -18,7 +18,35 @@ FuzzyController& EvolutionManager::get_active_controller() {
void EvolutionManager::update_population_dynamics( void EvolutionManager::update_population_dynamics(
float loss_velocity, float ema_loss, int step_counter, int total_steps float loss_velocity, float ema_loss, int step_counter, int total_steps
) { ) {
// TODO: Port full dynamics (auto-sizing, lockdown, evolution triggers) 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 (!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);
}
}
} }
} // namespace fces } // namespace fces

View File

@@ -59,13 +59,38 @@ float FitnessEngine::compute_kzm_damping(float spectral_alpha) const {
// FuzzyFitnessEvaluator // FuzzyFitnessEvaluator
// --------------------------------------------------------------- // ---------------------------------------------------------------
FitnessMetrics FuzzyFitnessEvaluator::evaluate( FuzzyFitnessEvaluator::FuzzyFitnessEvaluator() noexcept
float loss_before, float loss_after, float sparsity, float val_loss : stability_set_("Stable", -1.0f, 0.0f, 0.1f, 0.5f),
) const { train_set_("Effective", 0.0f, 0.05f, 1.0f, 10.0f),
FitnessMetrics metrics; val_set_("Generalizing", 0.0f, 0.05f, 1.0f, 10.0f),
metrics.loss_improvement = loss_before - loss_after; sparsity_set_("Sparse", 0.0f, 0.001f, 1.0f, 1.0f),
metrics.sparsity_score = sparsity * sparsity; // Quadratic reward consistency_set_("Consistent", -1.0f, 0.0f, 0.02f, 0.1f),
return metrics; 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 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;
}
// 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

@@ -29,7 +29,6 @@ Population::Population(
} }
FuzzyController& Population::get_active_controller() { FuzzyController& Population::get_active_controller() {
// TODO: Implement sticky selection with interval
if (active_controller_ == nullptr || steps_active_ >= selection_interval_) { if (active_controller_ == nullptr || steps_active_ >= selection_interval_) {
active_controller_ = &select_weighted(); active_controller_ = &select_weighted();
steps_active_ = 0; steps_active_ = 0;
@@ -39,10 +38,73 @@ FuzzyController& Population::get_active_controller() {
} }
FuzzyController& Population::select_weighted() { FuzzyController& Population::select_weighted() {
// TODO: Implement tournament selection with age weighting
static thread_local std::mt19937 rng{std::random_device{}()}; static thread_local std::mt19937 rng{std::random_device{}()};
if (gladiators_.empty()) {
throw std::runtime_error("Empty gladiators population");
}
float sum_fit = 0.0f;
for (const auto& g : gladiators_) {
sum_fit += std::max(0.0f, g.fitness);
}
if (sum_fit == 0.0f) {
std::uniform_int_distribution<int> dist(0, static_cast<int>(gladiators_.size()) - 1);
return gladiators_[dist(rng)];
}
// Select 3 random candidates for tournament
std::uniform_int_distribution<int> dist(0, static_cast<int>(gladiators_.size()) - 1); std::uniform_int_distribution<int> dist(0, static_cast<int>(gladiators_.size()) - 1);
return gladiators_[dist(rng)]; int idx1 = dist(rng);
int idx2 = dist(rng);
int idx3 = dist(rng);
auto get_score = [this](const FuzzyController& c) {
float base_score = c.fitness + (0.01f * static_cast<float>(c.age));
// Add novelty score if archive has enough entries
if (behavioral_archive_.size() >= 5) {
float novelty = 0.0f;
// Get behavioral vector: first 20 weights
std::vector<float> behavior(c.genome.weights.begin(), c.genome.weights.begin() + std::min(20, static_cast<int>(c.genome.weights.size())));
std::vector<float> distances;
distances.reserve(behavioral_archive_.size());
for (const auto& archived : behavioral_archive_) {
float dist_sum = 0.0f;
for (size_t i = 0; i < behavior.size() && i < archived.size(); ++i) {
float diff = behavior[i] - archived[i];
dist_sum += diff * diff;
}
distances.push_back(std::sqrt(dist_sum));
}
std::sort(distances.begin(), distances.end());
int k = std::min(5, static_cast<int>(distances.size()));
float avg_dist = 0.0f;
for (int i = 0; i < k; ++i) {
avg_dist += distances[i];
}
if (k > 0) avg_dist /= static_cast<float>(k);
base_score += NOVELTY_WEIGHT * avg_dist;
}
return base_score;
};
FuzzyController* best = &gladiators_[idx1];
float best_score = get_score(*best);
FuzzyController* cand2 = &gladiators_[idx2];
float score2 = get_score(*cand2);
if (score2 > best_score) {
best = cand2;
best_score = score2;
}
FuzzyController* cand3 = &gladiators_[idx3];
float score3 = get_score(*cand3);
if (score3 > best_score) {
best = cand3;
best_score = score3;
}
return *best;
} }
FuzzyController& Population::get_best_active() { FuzzyController& Population::get_best_active() {
@@ -53,14 +115,42 @@ FuzzyController& Population::get_best_active() {
} }
FuzzyController& Population::get_worst_active() { FuzzyController& Population::get_worst_active() {
return *std::min_element(gladiators_.begin(), gladiators_.end(), auto elites = get_elites();
[](const FuzzyController& a, const FuzzyController& b) { std::vector<FuzzyController*> non_elites;
return a.fitness < b.fitness; for (auto& g : gladiators_) {
bool is_elite = false;
for (auto* e : elites) {
if (e->id == g.id) {
is_elite = true;
break;
}
}
if (!is_elite) {
non_elites.push_back(&g);
}
}
if (non_elites.empty()) {
return *std::min_element(gladiators_.begin(), gladiators_.end(),
[](const FuzzyController& a, const FuzzyController& b) {
return a.fitness < b.fitness;
});
}
return **std::min_element(non_elites.begin(), non_elites.end(),
[](const FuzzyController* a, const FuzzyController* b) {
return a->fitness < b->fitness;
}); });
} }
void Population::kill(FuzzyController& controller) { void Population::kill(FuzzyController& controller) {
// TODO: Elite protection auto elites = get_elites();
for (auto* e : elites) {
if (e->id == controller.id) {
return; // Elite protection
}
}
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), auto it = std::find_if(gladiators_.begin(), gladiators_.end(),
[&](const FuzzyController& c) { return c.id == controller.id; }); [&](const FuzzyController& c) { return c.id == controller.id; });
if (it != gladiators_.end()) { if (it != gladiators_.end()) {
@@ -72,14 +162,31 @@ void Population::kill(FuzzyController& controller) {
} }
void Population::update_controller_fitness(FuzzyController& controller, float reward, bool increment_eval) { void Population::update_controller_fitness(FuzzyController& controller, float reward, bool increment_eval) {
controller.fitness += reward; if (increment_eval) {
controller.age++;
controller.evaluation_count++;
}
controller.lifetime_fitness += reward; controller.lifetime_fitness += reward;
if (increment_eval) controller.evaluation_count++;
controller.age++; // Track in rolling history
constexpr size_t RECENT_WINDOW = 20;
controller.fitness_history.push_back(reward);
if (controller.fitness_history.size() > RECENT_WINDOW) {
controller.fitness_history.erase(controller.fitness_history.begin());
}
if (elite_strategy_ == EliteStrategy::EMA) {
constexpr float EMA_ALPHA = 0.1f;
controller.ema_fitness = (1.0f - EMA_ALPHA) * controller.ema_fitness + EMA_ALPHA * reward;
controller.fitness = reward;
} else if (elite_strategy_ == EliteStrategy::Rolling) {
controller.fitness = reward;
} else {
controller.fitness = reward;
}
} }
void Population::mark_violated(FuzzyController& controller) { void Population::mark_violated(FuzzyController& controller) {
// Deduplicate
auto it = std::find_if(violated_controllers_.begin(), violated_controllers_.end(), auto it = std::find_if(violated_controllers_.begin(), violated_controllers_.end(),
[&](const FuzzyController& c) { return c.id == controller.id; }); [&](const FuzzyController& c) { return c.id == controller.id; });
if (it == violated_controllers_.end()) { if (it == violated_controllers_.end()) {
@@ -88,16 +195,292 @@ void Population::mark_violated(FuzzyController& controller) {
} }
float Population::get_effective_fitness(const FuzzyController& controller, float training_progress) const { float Population::get_effective_fitness(const FuzzyController& controller, float training_progress) const {
// TODO: Implement recency-weighted effective fitness (V42.5) float recent_avg = 0.0f;
return controller.fitness; if (!controller.fitness_history.empty()) {
float sum = 0.0f;
for (float f : controller.fitness_history) sum += f;
recent_avg = sum / controller.fitness_history.size();
}
float lifetime_avg = 0.0f;
if (controller.evaluation_count > 0) {
lifetime_avg = controller.lifetime_fitness / static_cast<float>(controller.evaluation_count);
}
float alpha = 0.2f + 0.6f * training_progress;
return alpha * recent_avg + (1.0f - alpha) * lifetime_avg;
} }
void Population::evolve(float current_loss, float velocity, float training_progress) { void Population::evolve(float current_loss, float velocity, float training_progress) {
// TODO: Port full evolution logic from Python static thread_local std::mt19937 rng{std::random_device{}()};
std::uniform_real_distribution<float> coin(0.0f, 1.0f);
if (gladiators_.empty()) return;
FuzzyController& worst = get_worst_active();
FuzzyController& best_active = get_best_active();
auto elites = get_elites();
// Update behavioral archive for novelty search
if (best_active.fitness > -999.0f) {
std::vector<float> behavior(best_active.genome.weights.begin(), best_active.genome.weights.begin() + std::min(20, static_cast<int>(best_active.genome.weights.size())));
behavioral_archive_.push_back(behavior);
if (behavioral_archive_.size() > BEHAVIORAL_ARCHIVE_SIZE) {
behavioral_archive_.erase(behavioral_archive_.begin());
}
}
// Phase-dependent scheduling
float phase_sigma_mult = 1.0f;
float phase_phoenix_intensity = 1.0f;
if (training_progress < 0.1f) {
phase_sigma_mult = 2.0f;
phase_phoenix_intensity = 1.5f;
} else if (training_progress > 0.7f) {
phase_sigma_mult = 0.5f;
phase_phoenix_intensity = 0.5f;
}
// Loss-linked mutation rate
float mutation_rate = 0.5f;
if (link_mutation_) {
mutation_rate = std::max(0.05f, std::min(1.0f, current_loss / 5.0f));
}
mutation_rate *= phase_sigma_mult;
mutation_rate = std::min(1.0f, mutation_rate);
// Pairing probabilities
float elite_prob = 0.3f;
if (link_elite_) {
elite_prob = std::max(0.2f, std::min(0.8f, 1.0f - current_loss / 5.0f));
}
float violator_prob = 0.1f;
if (link_violator_) {
violator_prob = std::max(0.0f, std::min(0.5f, (current_loss - 1.0f) / 4.0f));
}
// Select parent
FuzzyController* parent = &best_active;
std::vector<FuzzyController*> partner_pool;
float roll = coin(rng);
if (roll < elite_prob && !elites.empty()) {
std::uniform_int_distribution<int> elite_dist(0, static_cast<int>(elites.size()) - 1);
parent = elites[elite_dist(rng)];
partner_pool = elites;
} else if (roll < elite_prob + violator_prob && !violated_controllers_.empty()) {
parent = &best_active;
// Filter living violators
for (auto& v : violated_controllers_) {
for (auto& g : gladiators_) {
if (g.id == v.id) {
partner_pool.push_back(&g);
break;
}
}
}
if (partner_pool.empty()) {
// Fallback
for (size_t i = 0; i < std::min(static_cast<size_t>(10), gladiators_.size()); ++i) {
partner_pool.push_back(&gladiators_[i]);
}
}
} else {
parent = &best_active;
for (size_t i = 0; i < std::min(static_cast<size_t>(10), gladiators_.size()); ++i) {
partner_pool.push_back(&gladiators_[i]);
}
}
// Crossover or mutation
FuzzyController child;
if (coin(rng) < 0.7f && partner_pool.size() > 1) {
std::uniform_int_distribution<int> pool_dist(0, static_cast<int>(partner_pool.size()) - 1);
FuzzyController* partner = partner_pool[pool_dist(rng)];
if (partner->id == parent->id) {
// Pick another if possible
for (auto* p : partner_pool) {
if (p->id != parent->id) {
partner = p;
break;
}
}
}
child = parent->crossover(*partner, false);
} else {
float sigma_mod = global_sigma_modifier_ * mutation_rate;
if (velocity < -0.05f) {
sigma_mod *= 1.0f / (1.0f + std::abs(velocity) * 10.0f);
}
// Epigenetic lock
if (parent->fitness > 0.5f) {
sigma_mod *= 0.1f;
}
child = parent->mutate(current_loss, sigma_mod);
}
// Recover temperature
global_sigma_modifier_ = std::min(1.0f, global_sigma_modifier_ * 1.01f);
// Fuzzy Pacer
if (use_fuzzy_pacer_) {
fitness_history_.push_back(best_active.fitness);
if (fitness_history_.size() > 20) {
fitness_history_.erase(fitness_history_.begin());
}
if (fitness_history_.size() >= 10) {
float trend = 0.0f;
for (size_t i = 1; i < fitness_history_.size(); ++i) {
trend += (fitness_history_[i] - fitness_history_[i - 1]);
}
trend /= (fitness_history_.size() - 1);
float diversity = get_diversity_index();
if (trend < 0.001f && diversity < 0.2f) {
global_sigma_modifier_ = std::min(5.0f, global_sigma_modifier_ * 1.2f);
} else if (trend > 0.01f) {
global_sigma_modifier_ = std::max(0.1f, global_sigma_modifier_ * 0.95f);
}
}
}
// Banach-Tarski Fission
if (use_banach_fission_ && coin(rng) < 0.2f && !elites.empty()) {
auto* prime_elite = elites[0];
auto fission_pair = prime_elite->banach_tarski_fission(phase_phoenix_intensity);
// Find second worst
FuzzyController* second_worst = nullptr;
for (auto& g : gladiators_) {
if (g.id != worst.id) {
if (second_worst == nullptr || g.fitness < second_worst->fitness) {
second_worst = &g;
}
}
}
// Replace worst and second_worst with plus and minus child
if (second_worst) {
uint64_t sw_id = second_worst->id;
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), [&](const FuzzyController& c) { return c.id == sw_id; });
if (it != gladiators_.end()) {
gladiators_.erase(it);
}
gladiators_.push_back(fission_pair.first);
}
uint64_t w_id = worst.id;
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), [&](const FuzzyController& c) { return c.id == w_id; });
if (it != gladiators_.end()) {
gladiators_.erase(it);
}
gladiators_.push_back(fission_pair.second);
} else {
// Phoenix Rebirth or Standard replacement
uint64_t w_id = worst.id;
auto it = std::find_if(gladiators_.begin(), gladiators_.end(), [&](const FuzzyController& c) { return c.id == w_id; });
if (it != gladiators_.end()) {
gladiators_.erase(it);
}
if (coin(rng) < 0.1f && !elites.empty()) {
auto* prime_elite = elites[0];
gladiators_.push_back(prime_elite->create_orthogonal_child(phase_phoenix_intensity));
} else {
gladiators_.push_back(child);
}
}
// Periodic Reset
if (elite_strategy_ == EliteStrategy::Reset) {
reset_step_counter_++;
if (reset_step_counter_ >= 500) {
reset_step_counter_ = 0;
for (auto& g : gladiators_) {
g.fitness = 0.0f;
g.ema_fitness = 0.0f;
g.fitness_history.clear();
}
}
}
// Archive best
if (best_active.fitness > -999.0f) {
add_to_repository(best_active);
}
} }
void Population::resize(int target_size, float training_progress) { void Population::resize(int target_size, float training_progress) {
// TODO: Port resize logic int current_size = static_cast<int>(gladiators_.size());
if (current_size == target_size) return;
static thread_local std::mt19937 rng{std::random_device{}()};
if (current_size < target_size) {
int needed = target_size - current_size;
bool has_eval = false;
for (const auto& g : gladiators_) {
if (g.evaluation_count > 0) {
has_eval = true;
break;
}
}
if (has_eval) {
std::vector<std::pair<float, FuzzyController*>> candidates;
for (auto& g : gladiators_) {
candidates.push_back({get_effective_fitness(g, training_progress), &g});
}
std::sort(candidates.begin(), candidates.end(),
[](const std::pair<float, FuzzyController*>& a, const std::pair<float, FuzzyController*>& b) {
return a.first > b.first;
});
int limit = std::min(10, static_cast<int>(candidates.size()));
std::uniform_int_distribution<int> cand_dist(0, limit - 1);
for (int i = 0; i < needed; ++i) {
FuzzyController* parent = candidates[cand_dist(rng)].second;
float mutation_str = 0.1f;
auto child = parent->mutate(mutation_str, 1.0f);
float stability = 1.0f - std::min(1.0f, mutation_str);
std::uniform_real_distribution<float> noise_dist(-0.1f, 0.1f);
float noise = noise_dist(rng) * std::abs(parent->fitness);
child.fitness = parent->fitness * stability + noise;
gladiators_.push_back(child);
}
} else {
for (int i = 0; i < needed; ++i) {
gladiators_.emplace_back();
}
}
} else {
std::vector<FuzzyController*> evaluated;
std::vector<FuzzyController*> unevaluated;
for (auto& g : gladiators_) {
if (g.evaluation_count > 0) {
evaluated.push_back(&g);
} else {
unevaluated.push_back(&g);
}
}
std::sort(evaluated.begin(), evaluated.end(),
[this, training_progress](const FuzzyController* a, const FuzzyController* b) {
return get_effective_fitness(*a, training_progress) > get_effective_fitness(*b, training_progress);
});
std::vector<FuzzyController> new_pop;
new_pop.reserve(target_size);
for (int i = 0; i < std::min(target_size, static_cast<int>(evaluated.size())); ++i) {
new_pop.push_back(*evaluated[i]);
}
int remaining = target_size - static_cast<int>(new_pop.size());
for (int i = 0; i < std::min(remaining, static_cast<int>(unevaluated.size())); ++i) {
new_pop.push_back(*unevaluated[i]);
}
gladiators_ = std::move(new_pop);
}
} }
void Population::calm_down() { void Population::calm_down() {
@@ -106,17 +489,78 @@ void Population::calm_down() {
} }
float Population::get_diversity_index() const { float Population::get_diversity_index() const {
// TODO: Compute behavioral spread if (gladiators_.size() < 2) return 0.0f;
return 0.5f; float sum_dist = 0.0f;
int count = 0;
for (size_t i = 0; i < gladiators_.size(); ++i) {
for (size_t j = i + 1; j < gladiators_.size(); ++j) {
float dist_sq = 0.0f;
for (size_t w = 0; w < GENOME_SIZE; ++w) {
float diff = gladiators_[i].genome.weights[w] - gladiators_[j].genome.weights[w];
dist_sq += diff * diff;
}
sum_dist += std::sqrt(dist_sq);
count++;
}
}
return sum_dist / static_cast<float>(count);
} }
std::vector<FuzzyController*> Population::get_elites() { std::vector<FuzzyController*> Population::get_elites() {
// TODO: Implement strategy-aware elite selection if (gladiators_.size() <= static_cast<size_t>(ELITE_COUNT)) {
return {}; std::vector<FuzzyController*> ptrs;
ptrs.reserve(gladiators_.size());
for (auto& g : gladiators_) {
ptrs.push_back(&g);
}
return ptrs;
}
std::vector<std::pair<float, FuzzyController*>> candidates;
candidates.reserve(gladiators_.size());
for (auto& g : gladiators_) {
float effective_fitness = 0.0f;
if (elite_strategy_ == EliteStrategy::AgePenalty) {
effective_fitness = g.fitness / std::log(static_cast<float>(g.age) + 2.0f);
} else if (elite_strategy_ == EliteStrategy::EMA) {
effective_fitness = g.ema_fitness;
} else if (elite_strategy_ == EliteStrategy::Rolling) {
if (!g.fitness_history.empty()) {
float sum = 0.0f;
for (float f : g.fitness_history) sum += f;
effective_fitness = sum / g.fitness_history.size();
} else {
effective_fitness = g.fitness;
}
} else {
effective_fitness = g.fitness;
}
candidates.push_back({effective_fitness, &g});
}
std::sort(candidates.begin(), candidates.end(),
[](const std::pair<float, FuzzyController*>& a, const std::pair<float, FuzzyController*>& b) {
return a.first > b.first;
});
std::vector<FuzzyController*> elites;
elites.reserve(ELITE_COUNT);
for (int i = 0; i < ELITE_COUNT; ++i) {
elites.push_back(candidates[i].second);
}
return elites;
} }
void Population::add_to_repository(const FuzzyController& controller) { void Population::add_to_repository(const FuzzyController& controller) {
// TODO: Maintain sorted repository auto it = std::lower_bound(repository_.begin(), repository_.end(), controller,
[](const FuzzyController& a, const FuzzyController& b) {
return a.fitness > b.fitness;
});
repository_.insert(it, controller);
if (repository_.size() > 1000) {
repository_.resize(1000);
}
} }
} // namespace fces } // namespace fces