Скачиваний:
0
Добавлен:
26.10.2025
Размер:
135.17 Кб
Скачать

3.3. Код юнит-тестов оператора мутации

namespace EvolutionaryAlgorithmTemplate.Tests

{

// FakeRandom позволяет задать последовательность возвращаемых значений для NextDouble()

public class FakeRandom : Random

{

private Queue<double> values;

public FakeRandom(IEnumerable<double> values)

{

this.values = new Queue<double>(values);

}

public override double NextDouble()

{

return values.Dequeue();

}

}

public class GenMutationTests

{

/*

Тест проверяет, что если rnd.NextDouble() возвращает значение больше mutationProbability,

мутация не происходит и значение гена остаётся неизменным.

*/

[Fact]

public void Mutation_ShouldNotChangeValue_WhenRandomValueIsAboveProbability()

{

double initialValue = 0.0;

double xmin = -5.0;

double xmax = 5.0;

double mutationProbability = 0.1;

// Первое значение 0.5 (>= 0.1) – мутация не срабатывает.

var fakeRandom = new FakeRandom(new List<double> { 0.5 });

Gen gene = new Gen(initialValue);

gene.Mutation(xmin, xmax, mutationProbability, fakeRandom);

// значение должно остаться неизменным

Assert.Equal(initialValue, gene.Value);

}

/*

Тест проверяет корректное изменение значения гена при срабатывании мутации,

когда новое значение вычисляется в пределах [xmin, xmax].

Для xmin=-5, xmax=5 нижняя граница смещения равна -1, верхняя – 1.

При втором значении rnd.NextDouble() равном 1.0, смещение Δ = -1 + 1*(2) = 1.

Новое значение = 1.0 + 1 = 2.0. */

[Fact]

public void Mutation_ShouldMutateValueWithinBounds()

{

double initialValue = 1.0;

double xmin = -5.0;

double xmax = 5.0;

double mutationProbability = 0.1;

// Первое значение 0.05 (< 0.1) – мутация срабатывает.

// Второе значение 1.0 приводит к Δ = -1 + 1.0*2 = 1.

var fakeRandom = new FakeRandom(new List<double> { 0.05, 1.0 });

Gen gene = new Gen(initialValue);

gene.Mutation(xmin, xmax, mutationProbability, fakeRandom);

// новое значение должно быть равно 2.0

Assert.Equal(2.0, gene.Value);

}

/*

Тест проверяет округление по верхнему пределу.

Если значение после мутации выходит за xmax, оно должно быть ограничено значением xmax.

Например, для initialValue=4.8 и Δ=1.0 новое значение 5.8 должно быть обрезано до 5.0.

*/

[Fact]

public void Mutation_ShouldClampToXmax_WhenValueExceedsXmax()

{

double initialValue = 4.8;

double xmin = -5.0;

double xmax = 5.0;

double mutationProbability = 0.1;

// Первое значение 0.05 (< 0.1) – мутация срабатывает.

// Второе значение 1.0 даёт Δ = 1, таким образом newValue = 4.8 + 1 = 5.8, которое должно быть округлено до 5.0.

var fakeRandom = new FakeRandom(new List<double> { 0.05, 1.0 });

Gen gene = new Gen(initialValue);

gene.Mutation(xmin, xmax, mutationProbability, fakeRandom);

// значение должно быть ограничено xmax (5.0)

Assert.Equal(5.0, gene.Value);

}

/*

Тест проверяет округление по нижнему пределу.

Если значение после мутации выходит за xmin, оно должно быть ограничено значением xmin.

Например, для initialValue=-4.8 и Δ=-1.0 новое значение -5.8 должно быть округлено до -5.0.

*/

[Fact]

public void Mutation_ShouldClampToXmin_WhenValueFallsBelowXmin()

{

double initialValue = -4.8;

double xmin = -5.0;

double xmax = 5.0;

double mutationProbability = 0.1;

// Первое значение 0.05 (< 0.1) – мутация срабатывает.

// Второе значение 0.0 приводит к Δ = xmin/5 = -1, таким образом newValue = -4.8 - 1 = -5.8, которое должно быть округлено до -5.0.

var fakeRandom = new FakeRandom(new List<double> { 0.05, 0.0 });

Gen gene = new Gen(initialValue);

gene.Mutation(xmin, xmax, mutationProbability, fakeRandom);

// значение должно быть ограничено xmin (-5.0)

Assert.Equal(-5.0, gene.Value);

}

}

}

3.4. Итог юнит-тестов оператора мутации

Рис.3 ­— Скриншот прохождения юнит-тестов оператора мутации

4. Оператор кроссинговера

4.1. Модель оператора кроссинговера

Оператор кроссинговера BLX‑a‑b.

Для i-го гена вычисляется d = |x - y|. Если x ≤ y, интервал для потомка [x - a*d, y + b*d], иначе [y - b*d, x + a*d]. Для каждого потомка генерируется случайное значение в этом интервале.

4.2. Код программной реализации оператора кроссинговера

namespace EvolutionaryAlgorithmTemplate

{

/*Класс Chromosome (Хромосома)

Хранит вектор рабочих параметров – список объектов Gen, каждый из которых содержит вещественное значение

Свойства:

Gens – список генов

XMin, XMax – границы допустимых значений рабочих параметров

Dimension – число рабочих параметров

Методы:

Конструкторы для создания хромосомы из списка вещественных значений или из списка генов

BLX‑a‑b кроссинговер – для создания потомков

Mutation – выполняет мутацию, выбирая случайный ген */

public class Chromosome

{

public List<Gen> Gens { get; private set; }

public double XMin { get; private set; }

public double XMax { get; private set; }

public int Dimension => Gens.Count;

// Создание хромосомы по списку рабочих параметров

public Chromosome(List<double> values, double xmin, double xmax)

{

XMin = xmin;

XMax = xmax;

Gens = new List<Gen>();

foreach (var val in values)

{

// Если значение выходит за пределы, ограничиваем его

double clamped = Math.Max(xmin, Math.Min(val, xmax));

Gens.Add(new Gen(clamped));

}

}

// Альтернативный конструктор, принимающий уже сформированные гены

public Chromosome(List<Gen> gens, double xmin, double xmax)

{

XMin = xmin;

XMax = xmax;

Gens = new List<Gen>(gens);

}

/*

Оператор кроссинговера BLX‑a‑b.

Для i-го гена вычисляется d = |x - y|. Если x ≤ y, интервал для потомка [x - a*d, y + b*d],

иначе [y - b*d, x + a*d]. Для каждого потомка генерируется случайное значение в этом интервале.

*/

public static (Chromosome, Chromosome) BLXabCrossover(

Chromosome parent1,

Chromosome parent2,

double a, double b,

double xmin, double xmax,

Random rnd)

{

if (parent1.Dimension != parent2.Dimension)

throw new ArgumentException("Размерности хромосом должны совпадать!");

int n = parent1.Dimension;

List<double> child1Values = new List<double>();

List<double> child2Values = new List<double>();

for (int i = 0; i < n; i++)

{

double x = parent1.Gens[i].Value;

double y = parent2.Gens[i].Value;

double d = Math.Abs(x - y);

double lower, upper;

if (x <= y)

{

lower = x - a * d;

upper = y + b * d;

}

else

{

lower = y - b * d;

upper = x + a * d;

}

double child1Value = lower + rnd.NextDouble() * (upper - lower);

double child2Value = lower + rnd.NextDouble() * (upper - lower);

// Ограничиваем значения в [xmin, xmax]

child1Value = Math.Max(xmin, Math.Min(child1Value, xmax));

child2Value = Math.Max(xmin, Math.Min(child2Value, xmax));

child1Values.Add(child1Value);

child2Values.Add(child2Value);

}

Chromosome child1 = new Chromosome(child1Values, xmin, xmax);

Chromosome child2 = new Chromosome(child2Values, xmin, xmax);

return (child1, child2);

}

// Выполняет мутацию хромосомы: выбирается случайный ген и к нему применяется метод мутации

public void Mutation(double mutationProbability, Random rnd)

{

int index = rnd.Next(Dimension);

Gens[index].Mutation(XMin, XMax, mutationProbability, rnd);

}

}

}

Соседние файлы в предмете Методы и модели искусственного интеллекта в управлении техническими системами