|
using System; |
|
using System.Collections.Generic; |
|
using System.Collections.ObjectModel; |
|
using System.Linq; |
|
using OxyPlot; |
|
using OxyPlot.Series; |
|
using static System.Math; |
|
|
|
namespace EvolutionSimpleAlgoritm |
|
{ |
|
public class MainViewModel |
|
{ |
|
public ObservableCollection<DataPoint> BestFromGenerations { get; } = new ObservableCollection<DataPoint>(); |
|
public ObservableCollection<ScatterPoint> AllGenerations { get; } = new ObservableCollection<ScatterPoint>(); |
|
|
|
private static readonly Func<double, double> FittnesFunction = |
|
x => -(Pow(x - 100, 2) / 100) + (Sin(x) * 50) + 10; |
|
|
|
|
|
private static readonly Random Random = new Random(); |
|
|
|
private static HashSet<byte> GeneratePopulation(int populationSize) |
|
{ |
|
HashSet<byte> population = new HashSet<byte>(); |
|
while (population.Count < populationSize) |
|
{ |
|
population.Add((byte) Random.Next(Byte.MinValue, Byte.MaxValue)); |
|
} |
|
return population; |
|
} |
|
|
|
private static HashSet<byte> RecombinePopulation( |
|
IEnumerable<(byte individual , double fitnessValue)> population, |
|
int populatationSize, int eliteClons) |
|
{ |
|
var newPopulation = new HashSet<byte>(); |
|
foreach (var elite in population.OrderByDescending(t => t.Item2).Take(eliteClons)) |
|
{ |
|
newPopulation.Add(elite.Item1); // clone elite individual to new population |
|
} |
|
|
|
var min = population.Min(t => t.Item2); |
|
while (newPopulation.Count < populatationSize) |
|
{ |
|
byte x = population.GetRandomItem(b => b.Item2 - min).Item1; |
|
byte y = x; // initialize |
|
while (y == x) |
|
{ |
|
y = population.GetRandomItem(b => b.Item2 - min).Item1; |
|
} |
|
newPopulation.Add(RecombineGenomtype(x, y)); |
|
} |
|
|
|
|
|
return newPopulation; |
|
} |
|
|
|
private static byte RecombineGenomtype(byte x, byte y) |
|
{ |
|
var split = Random.Next(0, 32); |
|
byte mask = (byte) ((1 << split) - 1); |
|
byte xpart = (byte) (x & mask); |
|
byte ypart = (byte) (y & ~mask); |
|
byte z = (byte) (xpart | ypart); |
|
|
|
while (Random.NextDouble() < 0.2) //mutation |
|
{ |
|
var mutationBit = Random.Next(0, 31); |
|
mask = (byte) (1 << mutationBit); |
|
z ^= mask; // invert bit |
|
} |
|
|
|
return z; |
|
} |
|
|
|
public void Recalculate() |
|
{ |
|
var population = GeneratePopulation(populationSize: 8); |
|
ClearChart(); |
|
|
|
for (int i = 0; i < 100; i++) |
|
{ |
|
var selection = population |
|
.Select(b => (b, FittnesFunction(b))) |
|
.ToList(); |
|
|
|
AddChartValues(selection, i); |
|
|
|
population = RecombinePopulation(selection, populatationSize: 8, eliteClons: 1); |
|
} |
|
} |
|
|
|
private void ClearChart() |
|
{ |
|
BestFromGenerations.Clear(); |
|
AllGenerations.Clear(); |
|
} |
|
|
|
private void AddChartValues(List<(byte individual, double fitnesValue)> population, int i) |
|
{ |
|
var eliteFittnes = population |
|
.OrderByDescending(t => t.Item2) |
|
.First() |
|
.Item2; //take fitness value |
|
|
|
BestFromGenerations.Add(new DataPoint(i, eliteFittnes)); |
|
foreach (var p in population) |
|
{ |
|
AllGenerations.Add(new ScatterPoint(i, p.Item2, 1)); |
|
} |
|
} |
|
} |
|
} |