Skip to content

Commit a6a7cb9

Browse files
committed
Merge pull request #25 from FlaviusAetius/GAinCSharp
Update selection to be more fair based on normalised fitness
2 parents b77da6d + 64e55aa commit a6a7cb9

File tree

6 files changed

+205
-191
lines changed

6 files changed

+205
-191
lines changed
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
<?xml version="1.0" encoding="utf-8" ?>
2-
<configuration>
3-
<startup>
4-
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
5-
</startup>
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
5+
</startup>
66
</configuration>
Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,34 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
5-
namespace GeneticAlgorithms
6-
{
7-
static class FitnessEvaluator
8-
{
9-
private static readonly Random Random = new Random(DateTime.Now.Millisecond);
10-
11-
public static int GetFitness(Genome genome, string answer)
12-
{
13-
return answer.Where((currentChar, i) => currentChar == genome[i]).Count();
14-
}
15-
16-
public static IEnumerable<double> NormaliseFitnessValues(IList<int> fitnessValues)
17-
{
18-
var totalFitness = fitnessValues.Sum();
19-
return fitnessValues.Select(i => (double) i/totalFitness);
20-
}
21-
22-
public static Genome CrossoverGenomes(Genome genome1, Genome genome2)
23-
{
24-
return new Genome(genome1.Phrase.Zip(genome2.Phrase, (g1, g2) => Random.Next(0,1) == 0 ? g1 : g2).ToArray());
25-
}
26-
27-
public static Genome MutateGenome(Genome genome, double mutationRate)
28-
{
29-
for (int i = 0; i < genome.Phrase.Length; i++)
30-
{
31-
genome.Phrase[i] = Random.NextDouble() < mutationRate
32-
? RandomGenomeGenerator.RandomChars(1).First()
33-
: genome.Phrase[i];
34-
}
35-
return genome;
36-
}
37-
}
38-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace GeneticAlgorithms
6+
{
7+
static class FitnessEvaluator
8+
{
9+
private static readonly Random Random = new Random(DateTime.Now.Millisecond);
10+
11+
public static int GetFitness(Genome genome, string answer)
12+
{
13+
var fitness = answer.Where((currentChar, i) => currentChar == genome[i]).Count();
14+
genome.Fitness = fitness;
15+
return fitness;
16+
}
17+
18+
public static Genome CrossoverGenomes(Genome genome1, Genome genome2)
19+
{
20+
return new Genome(genome1.Phrase.Zip(genome2.Phrase, (g1, g2) => Random.Next(0,2) == 0 ? g1 : g2).ToArray());
21+
}
22+
23+
public static Genome MutateGenome(Genome genome, double mutationRate)
24+
{
25+
for (int i = 0; i < genome.Phrase.Length; i++)
26+
{
27+
genome.Phrase[i] = Random.NextDouble() < mutationRate
28+
? RandomGenomeGenerator.RandomChars(1).First()
29+
: genome.Phrase[i];
30+
}
31+
return genome;
32+
}
33+
}
34+
}
Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
6-
7-
namespace GeneticAlgorithms
8-
{
9-
class Genome
10-
{
11-
public char[] Phrase { get; set; }
12-
public int Fitness { get; set; }
13-
14-
public Genome(int lengthOfPhrase)
15-
{
16-
Phrase = RandomGenomeGenerator.RandomChars(lengthOfPhrase).ToArray();
17-
}
18-
19-
public Genome(char[] chars)
20-
{
21-
Phrase = chars;
22-
}
23-
24-
public char this[int i]
25-
{
26-
get { return Phrase[i]; }
27-
set { Phrase[i] = value; }
28-
}
29-
}
30-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace GeneticAlgorithms
8+
{
9+
class Genome
10+
{
11+
public char[] Phrase { get; set; }
12+
public int Fitness { get; set; }
13+
public double NormalisedFitness { get; set; }
14+
15+
public Genome(int lengthOfPhrase)
16+
{
17+
Phrase = RandomGenomeGenerator.RandomChars(lengthOfPhrase).ToArray();
18+
}
19+
20+
public Genome(char[] chars)
21+
{
22+
Phrase = chars;
23+
}
24+
25+
public char this[int i]
26+
{
27+
get { return Phrase[i]; }
28+
set { Phrase[i] = value; }
29+
}
30+
}
31+
}
Lines changed: 69 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,69 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
6-
7-
namespace GeneticAlgorithms
8-
{
9-
class Population
10-
{
11-
private readonly int _size;
12-
private readonly double _mutationRate;
13-
private readonly int _lengthOfAnswer;
14-
private static string _target;
15-
public IList<Genome> Genomes { get; set; }
16-
17-
public Population(int size, double mutationRate, string target)
18-
{
19-
_size = size;
20-
_mutationRate = mutationRate;
21-
_lengthOfAnswer = target.Length;
22-
_target = target;
23-
Genomes = InitialisePopulation().ToList();
24-
}
25-
26-
public void GetNextGeneration()
27-
{
28-
Genomes = Rank().ToList();
29-
var random = new Random(DateTime.Now.Millisecond);
30-
for (int i = (_size/2)+1; i < _size; i++)
31-
{
32-
int random1 = random.Next(_size/2);
33-
int random2 = random.Next(_size/2);
34-
Genomes[i] = FitnessEvaluator.CrossoverGenomes(Genomes[random1], Genomes[random2]);
35-
Genomes[i] = FitnessEvaluator.MutateGenome(Genomes[i], _mutationRate);
36-
}
37-
}
38-
39-
public IOrderedEnumerable<Genome> Rank()
40-
{
41-
return Genomes.OrderByDescending(g => FitnessEvaluator.GetFitness(g, _target));
42-
}
43-
44-
private IEnumerable<Genome> InitialisePopulation()
45-
{
46-
for (int i = 0; i < _size; i++)
47-
{
48-
yield return new Genome(_lengthOfAnswer);
49-
}
50-
}
51-
}
52-
53-
54-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace GeneticAlgorithms
8+
{
9+
class Population
10+
{
11+
private readonly int _size;
12+
private readonly double _mutationRate;
13+
private readonly int _lengthOfAnswer;
14+
private static string _target;
15+
public IList<Genome> Genomes { get; set; }
16+
public IList<Genome> MatingPool { get; set; }
17+
18+
public Population(int size, double mutationRate, string target)
19+
{
20+
_size = size;
21+
_mutationRate = mutationRate;
22+
_lengthOfAnswer = target.Length;
23+
_target = target;
24+
Genomes = InitialisePopulation().ToList();
25+
}
26+
27+
public void GetNextGeneration()
28+
{
29+
Genomes = Rank().ToList();
30+
var random = new Random(DateTime.Now.Millisecond);
31+
for (int i = (_size/5)+1; i < _size; i++)
32+
{
33+
int random1 = random.Next(MatingPool.Count);
34+
int random2 = random.Next(MatingPool.Count);
35+
Genomes[i] = FitnessEvaluator.CrossoverGenomes(MatingPool[random1], MatingPool[random2]);
36+
Genomes[i] = FitnessEvaluator.MutateGenome(Genomes[i], _mutationRate);
37+
}
38+
}
39+
40+
public IOrderedEnumerable<Genome> Rank()
41+
{
42+
// get fitness and normalise
43+
MatingPool = new List<Genome>();
44+
foreach (Genome genome in Genomes) {
45+
genome.Fitness = FitnessEvaluator.GetFitness (genome, _target);
46+
}
47+
var totalFitness = Genomes.Sum(g => g.Fitness);
48+
foreach (Genome genome in Genomes) {
49+
genome.NormalisedFitness = (genome.Fitness / totalFitness) * 100;
50+
for (int i = 0; i < genome.NormalisedFitness + 1; i++) {
51+
MatingPool.Add (genome);
52+
}
53+
}
54+
55+
// order the genomes by fitness
56+
return Genomes.OrderByDescending(g => g.Fitness);
57+
}
58+
59+
private IEnumerable<Genome> InitialisePopulation()
60+
{
61+
for (int i = 0; i < _size; i++)
62+
{
63+
yield return new Genome(_lengthOfAnswer);
64+
}
65+
}
66+
}
67+
68+
69+
}
Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,43 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Diagnostics;
4-
using System.Linq;
5-
using System.Text;
6-
using System.Threading.Tasks;
7-
using System.Timers;
8-
9-
namespace GeneticAlgorithms
10-
{
11-
class Program
12-
{
13-
static void Main(string[] args)
14-
{
15-
var target = "to be or not to be that is the question";
16-
var population = new Population(100, 0.1, target);
17-
18-
var stopwatch = new Stopwatch();
19-
stopwatch.Start();
20-
21-
Genome first;
22-
int index = 0;
23-
do
24-
{
25-
population.GetNextGeneration();
26-
first = population.Rank().First();
27-
Console.WriteLine("Generation {0}: {1}", index++, JoinPhrase(first.Phrase));
28-
} while (JoinPhrase(first.Phrase) != target);
29-
30-
stopwatch.Stop();
31-
Console.WriteLine(stopwatch.Elapsed.ToString());
32-
}
33-
34-
static string JoinPhrase(IEnumerable<char> phrase)
35-
{
36-
var stringBuilder = new StringBuilder();
37-
phrase.ToList().ForEach(c => stringBuilder.Append(c));
38-
return stringBuilder.ToString();
39-
}
40-
}
41-
}
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using System.Timers;
8+
9+
namespace GeneticAlgorithms
10+
{
11+
class Program
12+
{
13+
static void Main(string[] args)
14+
{
15+
var target = "to be or not to be that is the question whether tis nobler in " +
16+
"the mind to suffer the strings and arrows of outrageous fortune or to " +
17+
"take up arms against a sea of troubles and by opposing end them";
18+
var population = new Population(1000, 0.01, target);
19+
20+
var stopwatch = new Stopwatch();
21+
stopwatch.Start();
22+
23+
Genome first;
24+
int index = 0;
25+
do
26+
{
27+
population.GetNextGeneration();
28+
first = population.Genomes.First();
29+
Console.WriteLine("Generation {0}, fitness = {1}: {2}", index++, first.Fitness, JoinPhrase(first.Phrase));
30+
} while (JoinPhrase(first.Phrase) != target);
31+
32+
stopwatch.Stop();
33+
Console.WriteLine(stopwatch.Elapsed.ToString());
34+
}
35+
36+
static string JoinPhrase(IEnumerable<char> phrase)
37+
{
38+
var stringBuilder = new StringBuilder();
39+
phrase.ToList().ForEach(c => stringBuilder.Append(c));
40+
return stringBuilder.ToString();
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)