@@ 1,8 1,9 @@
use std::{collections::VecDeque, convert::Infallible, error::Error};
+use rand::{Rng, RngCore};
use thiserror::Error;
-use crate::{comparison::BetterThanOperator, crossover::Crossover, evolution::EvolutionStats, fitness::FitnessFunction, pairing::Pairing, perturbation::PerturbationOperator, population::EvaluatedPopulation, replacement::Replacement, selection::Selection};
+use crate::{comparison::{BetterThanOperator, MinimizingOperator}, crossover::Crossover, evolution::EvolutionStats, fitness::FitnessFunction, pairing::Pairing, perturbation::PerturbationOperator, population::{EvaluatedChromosome, EvaluatedPopulation, Population}, replacement::Replacement, selection::Selection};
pub trait ConstraintFunction {
type Chromosome;
@@ 223,8 224,142 @@ pub fn evolve_constraint_penalty_weight_tau_target
}
}
+#[derive(PartialEq, Debug)]
+pub struct ConstrainedEvaluation<const CONSTRAINTS: usize, TOut> {
+ fitness: TOut,
+ constraints: [TOut; CONSTRAINTS],
+ weighted_sum: TOut
+}
+
+impl<const CONSTRAINTS: usize, TOut: PartialOrd> PartialOrd for ConstrainedEvaluation<CONSTRAINTS, TOut> {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ self.weighted_sum.partial_cmp(&other.weighted_sum)
+ }
+}
+
+pub struct ConstrainedEvalFitness<'a,
+ const CONSTRAINTS: usize,
+ TIn,
+ TOut,
+ TFitness: FitnessFunction<In = TIn, Out = TOut>,
+ TConstraint: ConstraintFunction<Chromosome = TIn, Out = TOut>> {
+ fitness: &'a TFitness,
+ constraints: [&'a TConstraint; CONSTRAINTS],
+ constraint_weights: Vec<TOut>
+}
+
+impl <'a,
+ const CONSTRAINTS: usize,
+ TOut: std::ops::Mul<Output = TOut> + std::ops::AddAssign + Copy,
+ TIn,
+ TFitness: FitnessFunction<In = TIn, Out = TOut>,
+ TConstraint: ConstraintFunction<Chromosome = TIn, Out = TOut>>
+ FitnessFunction for ConstrainedEvalFitness<'a, CONSTRAINTS, TIn, TOut, TFitness, TConstraint> {
+ type In = TFitness::In;
+ type Out = ConstrainedEvaluation<CONSTRAINTS, TOut>;
+ type Err = ConstrainedFitnessErr<TFitness::Err, TConstraint::Err>;
+
+ fn fit(self: &Self, inp: &Self::In) -> Result<Self::Out, Self::Err> {
+ let fit = match self.fitness.fit(inp) {
+ Ok(fit) => fit,
+ Err(err) =>
+ return Err(ConstrainedFitnessErr::FitnessErr(err))
+ };
+ let mut weighted_sum = fit;
+ let mut constraints = [fit; CONSTRAINTS];
+
+ for (i, (constraint, weight)) in self.constraints.iter().zip(self.constraint_weights.iter()).enumerate() {
+ let constraint = match constraint.evaluate(inp) {
+ Ok(constraint) => constraint,
+ Err(err) =>
+ return Err(ConstrainedFitnessErr::ConstraintErr(err))
+ };
+ constraints[i] = constraint;
+ weighted_sum += weight.clone() * constraint;
+ }
+
+ Ok(ConstrainedEvaluation {
+ fitness: fit,
+ constraints,
+ weighted_sum
+ })
+ }
+}
+
+fn stochastic_ranking_sort<const CONSTRAINTS: usize, TIn, TOut: PartialOrd + Default>(
+ evaluations: &[EvaluatedChromosome<TIn, ConstrainedEvaluation<CONSTRAINTS, TOut>>],
+ N: usize,
+ p: f64,
+ better_than: &(impl BetterThanOperator<TOut> + ?Sized),
+ rng: &mut dyn RngCore
+) -> Vec<usize> {
+ let mut indices = (0..evaluations.len()).collect::<Vec<_>>();
+ for _ in 0..N {
+ for j in 0..evaluations.len()-1 {
+ let u = rng.random_range(0.0..=1.0);
+
+ let current_evaluation = &evaluations[indices[j]].evaluation;
+ let next_evaluation = &evaluations[indices[j + 1]].evaluation;
+
+ if (current_evaluation.weighted_sum == Default::default() && next_evaluation.weighted_sum == Default::default()) || u < p {
+ if better_than.better_than(&next_evaluation.fitness, ¤t_evaluation.fitness) {
+ indices.swap(j, j + 1);
+ }
} else {
- fitness.constraints_weight *= c;
+ if current_evaluation.weighted_sum > next_evaluation.weighted_sum {
+ indices.swap(j, j + 1);
+ }
}
}
+ }
+
+ indices
+}
+
+pub struct StochasticRankingSelection<TSelection, TBetterThan> {
+ N: usize,
+ p: f64,
+ selection: TSelection,
+ better_than: TBetterThan
+}
+
+const MINIMIZING_OPERATOR: MinimizingOperator = MinimizingOperator;
+
+impl<const CONSTRAINTS: usize,
+ TChromosome,
+ TResult: PartialOrd + Default,
+ TSelection: Selection<(), usize>,
+ TBetterThan: BetterThanOperator<TResult>>
+ Selection<TChromosome, ConstrainedEvaluation<CONSTRAINTS, TResult>> for StochasticRankingSelection<TSelection, TBetterThan> {
+ fn select(&self,
+ count: usize,
+ evaluations: &EvaluatedPopulation<TChromosome, ConstrainedEvaluation<CONSTRAINTS, TResult>>,
+ _: &dyn BetterThanOperator<ConstrainedEvaluation<CONSTRAINTS, TResult>>,
+ rng: &mut dyn RngCore
+ ) -> impl Iterator<Item = usize> {
+ let sorted_indices = stochastic_ranking_sort(
+ evaluations.population.as_slice(),
+ self.N, self.p, &self.better_than, rng
+ );
+ let mut rankings = vec![EvaluatedChromosome {
+ chromosome: (),
+ evaluation: 0
+ }; evaluations.population.len()];
+
+ for (ranking, index) in sorted_indices.into_iter().enumerate() {
+ rankings[index] = EvaluatedChromosome {
+ chromosome: (),
+ evaluation: ranking
+ };
+ }
+
+ // Replace with this better than
+ self.selection.select(
+ count,
+ &EvaluatedPopulation::from_vec(rankings),
+ &MINIMIZING_OPERATOR,
+ rng)
+ .collect::<Vec<_>>()
+ .into_iter()
+ }
}