@@ 3,7 3,7 @@ use std::{collections::VecDeque, convert::Infallible, error::Error};
use rand::{Rng, RngCore};
use thiserror::Error;
-use crate::{comparison::{BetterThanOperator, MinimizingOperator}, crossover::Crossover, evolution::EvolutionStats, fitness::FitnessFunction, pairing::Pairing, perturbation::PerturbationOperator, population::{EvaluatedChromosome, EvaluatedPopulation, Population}, replacement::Replacement, selection::Selection};
+use crate::{comparison::{BetterThanOperator, MinimizingOperator}, crossover::Crossover, evolution::{evolution_algorithm_best_candidate, EvolutionCandidate, EvolutionResult, EvolutionStats}, fitness::FitnessFunction, pairing::Pairing, perturbation::PerturbationOperator, population::{EvaluatedChromosome, EvaluatedPopulation, Population}, replacement::Replacement, selection::Selection};
pub trait ConstraintFunction {
type Chromosome;
@@ 224,11 224,12 @@ pub fn evolve_constraint_penalty_weight_tau_target
}
}
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Clone, Debug)]
pub struct ConstrainedEvaluation<const CONSTRAINTS: usize, TOut> {
fitness: TOut,
constraints: [TOut; CONSTRAINTS],
- weighted_sum: TOut
+ weighted_sum: TOut,
+ is_feasible: bool,
}
impl<const CONSTRAINTS: usize, TOut: PartialOrd> PartialOrd for ConstrainedEvaluation<CONSTRAINTS, TOut> {
@@ 245,12 246,12 @@ pub struct ConstrainedEvalFitness<'a,
TConstraint: ConstraintFunction<Chromosome = TIn, Out = TOut>> {
fitness: &'a TFitness,
constraints: [&'a TConstraint; CONSTRAINTS],
- constraint_weights: Vec<TOut>
+ constraint_weights: [TOut; CONSTRAINTS]
}
impl <'a,
const CONSTRAINTS: usize,
- TOut: std::ops::Mul<Output = TOut> + std::ops::AddAssign + Copy,
+ TOut: std::ops::Mul<Output = TOut> + std::ops::AddAssign + Copy + Default,
TIn,
TFitness: FitnessFunction<In = TIn, Out = TOut>,
TConstraint: ConstraintFunction<Chromosome = TIn, Out = TOut>>
@@ 267,21 268,31 @@ impl <'a,
};
let mut weighted_sum = fit;
let mut constraints = [fit; CONSTRAINTS];
+ let mut is_feasible = true;
for (i, (constraint, weight)) in self.constraints.iter().zip(self.constraint_weights.iter()).enumerate() {
- let constraint = match constraint.evaluate(inp) {
+ let constraint_eval = match constraint.evaluate(inp) {
Ok(constraint) => constraint,
Err(err) =>
return Err(ConstrainedFitnessErr::ConstraintErr(err))
};
- constraints[i] = constraint;
- weighted_sum += weight.clone() * constraint;
+ constraints[i] = constraint_eval;
+
+ weighted_sum += match constraint.is_feasible(inp) {
+ Ok(true) => weight.clone() * constraint_eval,
+ Ok(false) => {
+ is_feasible = false;
+ Default::default()
+ },
+ Err(err) => return Err(ConstrainedFitnessErr::ConstraintErr(err))
+ };
}
Ok(ConstrainedEvaluation {
fitness: fit,
constraints,
- weighted_sum
+ weighted_sum,
+ is_feasible
})
}
}
@@ 316,21 327,22 @@ fn stochastic_ranking_sort<const CONSTRAINTS: usize, TIn, TOut: PartialOrd + Def
indices
}
-pub struct StochasticRankingSelection<TSelection, TBetterThan> {
+pub struct StochasticRankingSelection<'a, TSelection, TBetterThan> {
N: usize,
p: f64,
- selection: TSelection,
- better_than: TBetterThan
+ selection: &'a mut TSelection,
+ better_than: &'a TBetterThan
}
const MINIMIZING_OPERATOR: MinimizingOperator = MinimizingOperator;
-impl<const CONSTRAINTS: usize,
+impl<'a,
+ const CONSTRAINTS: usize,
TChromosome,
TResult: PartialOrd + Default,
TSelection: Selection<(), usize>,
TBetterThan: BetterThanOperator<TResult>>
- Selection<TChromosome, ConstrainedEvaluation<CONSTRAINTS, TResult>> for StochasticRankingSelection<TSelection, TBetterThan> {
+ Selection<TChromosome, ConstrainedEvaluation<CONSTRAINTS, TResult>> for StochasticRankingSelection<'a, TSelection, TBetterThan> {
fn select(&self,
count: usize,
evaluations: &EvaluatedPopulation<TChromosome, ConstrainedEvaluation<CONSTRAINTS, TResult>>,
@@ 339,7 351,7 @@ impl<const CONSTRAINTS: usize,
) -> impl Iterator<Item = usize> {
let sorted_indices = stochastic_ranking_sort(
evaluations.population.as_slice(),
- self.N, self.p, &self.better_than, rng
+ self.N, self.p, self.better_than, rng
);
let mut rankings = vec![EvaluatedChromosome {
chromosome: (),
@@ 363,3 375,108 @@ impl<const CONSTRAINTS: usize,
.into_iter()
}
}
+
+pub fn stochastic_ranking_evolution_algorithm
+ <TChromosome: Clone,
+ TResult: PartialOrd + std::ops::Mul<Output = TResult> + std::ops::AddAssign + Copy + Default,
+ const DParents: usize,
+ const CONSTRAINTS: usize,
+ TFitness: FitnessFunction<In = TChromosome, Out = TResult>,
+ TSelection: Selection<(), usize>,
+ TPairing: Pairing<DParents, Chromosome = TChromosome, Out = ConstrainedEvaluation<CONSTRAINTS, TResult>>,
+ TCrossover: Crossover<DParents, Chromosome = TChromosome, Out = ConstrainedEvaluation<CONSTRAINTS, TResult>>,
+ TReplacement: Replacement<TChromosome, ConstrainedEvaluation<CONSTRAINTS, TResult>>,
+ TConstraint: ConstraintFunction<Chromosome = TChromosome, Out = TResult>,
+ TPerturbation: PerturbationOperator<Chromosome = TChromosome>>(
+ initial_population: Population<TChromosome>,
+ parents_count: usize,
+ N: usize,
+ p: f64,
+ fitness: &mut TFitness,
+ constraints: [&TConstraint; CONSTRAINTS],
+ constraint_weights: [TResult; CONSTRAINTS],
+ pairing: &mut TPairing,
+ selection: &mut TSelection,
+ crossover: &mut TCrossover,
+ perturbation: &mut TPerturbation,
+ replacement: &mut TReplacement,
+ better_than: &(impl BetterThanOperator<ConstrainedEvaluation<CONSTRAINTS, TResult>> + BetterThanOperator<TResult>),
+ // TODO: termination condition
+ iterations: usize,
+ rng: &mut dyn RngCore,
+ // mut evolutionary_strategy: impl FnMut(
+ // usize,
+ // &EvolutionStats<TChromosome, TResult>,
+ // &EvaluatedPopulation<TChromosome, TResult>,
+
+ // &mut TPairing,
+ // &mut TCrossover,
+ // &mut TPerturbation,
+ // &mut TReplacement,
+ // &mut ConstrainedEvalFitness<CONSTRAINTS, TChromosome, TResult, TFitness, TConstraint>,
+ // ),
+ ) -> Result<(EvolutionResult<TChromosome, TResult>, Vec<f64>), Box<dyn Error>>
+{
+ let mut constrained_fitness = ConstrainedEvalFitness {
+ fitness,
+ constraints,
+ constraint_weights,
+ };
+
+ let mut stochastic_ranking_selection =
+ StochasticRankingSelection {
+ N,
+ p,
+ selection,
+ better_than
+ };
+
+ let mut feasible_fractions = Vec::with_capacity(iterations);
+
+ evolution_algorithm_best_candidate(
+ initial_population,
+ parents_count,
+ &mut constrained_fitness,
+ &mut stochastic_ranking_selection,
+ pairing,
+ crossover,
+ perturbation,
+ replacement,
+ better_than,
+ iterations,
+ rng,
+ |iteration, stats, population, fitness, selection, pairing, crossover, perturbation, replacement| {
+ let feasible_fraction = population.population
+ .iter()
+ .map(|x| x.evaluation.is_feasible)
+ .count() as f64 / population.population.len() as f64;
+
+ feasible_fractions.push(feasible_fraction);
+
+ // evolutionary_strategy(
+ // iteration,
+ // stats,
+ // population,
+ // fitness
+ // )
+ },
+ |_, evaluation, best_candidate| {
+ // Do not save enfeasible solutions!
+ if !evaluation.is_feasible {
+ return false;
+ }
+
+ if best_candidate.is_none() {
+ return true;
+ }
+
+ better_than.better_than(
+ evaluation,
+ &best_candidate.as_ref().unwrap().evaluated_chromosome.evaluation
+ )
+ }).map(|res|
+ (
+ res.map(|evaluation| evaluation.fitness),
+ feasible_fractions
+ ))
+}