Skip to content

Commit 895cfdb

Browse files
Added support for dynamically expanding genome.
1 parent de54fee commit 895cfdb

File tree

5 files changed

+109
-7
lines changed

5 files changed

+109
-7
lines changed

Diff for: AIProgrammer.Fitness/Concrete/XmlToJsonFitness.cs

+40-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,22 @@ namespace AIProgrammer.Fitness.Concrete
1212
{
1313
public class XmlToJsonFitness : FitnessBase
1414
{
15-
private static string[] _trainingExamples = { "<a>boy</a>", "<zt>Yaks</zt>", "<you>i</you>" };
15+
private static string[] _trainingExamples = { "<b>i</b>", "<i>One</i>", "<a>me</a>" };
16+
// private static string[] _trainingExamples = { "<me>i</me>", "<us>You</us>", "<her>it</her>" };
1617
private static string[] _trainingResults = new string[_trainingExamples.Length];
1718

19+
/// <summary>
20+
/// Previously generated BrainPlus functions for outputting json characters: { } " :
21+
/// To use, set _appendCode = XmlToJsonFitness.XmlToJsonFunctions in main program.
22+
///
23+
/// Generated using StrictStringFitness with StringFunction with the following settings:
24+
/// TargetString = "{ } \" :"
25+
/// private static IFunction _functionGenerator = new StringFunction(() => GetFitnessMethod(), _bestStatus, fitnessFunction, OnGeneration, _crossoverRate, _mutationRate, _genomeSize, _targetParams);
26+
/// ...
27+
/// return new StringStrictFitness(_ga, _maxIterationCount, _targetParams.TargetString, _appendCode);
28+
/// </summary>
29+
public static string XmlToJsonFunctions = "8-----.@-[8[[---.@D+2++.@->4------.@";
30+
1831
public XmlToJsonFitness(GA ga, int maxIterationCount, string appendFunctions = null)
1932
: base(ga, maxIterationCount, appendFunctions)
2033
{
@@ -38,6 +51,8 @@ protected override double GetFitnessMethod(string program)
3851
{
3952
double countBonus = 0;
4053
double penalty = 0;
54+
//HashSet<int> memoryHash = new HashSet<int>();
55+
//HashSet<int> printCommandHash = new HashSet<int>();
4156

4257
for (int i = 0; i < _trainingExamples.Length; i++)
4358
{
@@ -63,6 +78,20 @@ protected override double GetFitnessMethod(string program)
6378
(b) =>
6479
{
6580
_console.Append((char)b);
81+
82+
// Record the instruction index being used for this print statement.
83+
/*if (!printCommandHash.Add(_bf.m_CurrentInstructionPointer))
84+
{
85+
// This is kind of cheating, but we need to force diversity by decoupling the cases. Force them to use unique print statements, not used by any other case.
86+
penalty += 200;
87+
}*/
88+
89+
/*// Record the memory register being used for this output. Used to support diversity.
90+
if (state >= _trainingExamples[i].Length && _console.Length <= _trainingResults[i].Length)
91+
{
92+
// This is a valid output character to consider. Record the memory register of where its data is stored.
93+
memoryHash.Add(_bf.m_CurrentDataPointer);
94+
}*/
6695
});
6796
_bf.Run(_maxIterationCount);
6897
}
@@ -82,8 +111,11 @@ protected override double GetFitnessMethod(string program)
82111
}
83112
}
84113

114+
// Bonus for using functions.
115+
//countBonus += _bf.m_ExecutedFunctions.Count * 25;
116+
85117
// Length bonus (percentage of 100).
86-
countBonus += 10 * ((_trainingResults[i].Length - Math.Abs(_console.Length - _trainingResults[i].Length)) / _trainingResults[i].Length);
118+
//countBonus += 256 * ((_trainingResults[i].Length - Math.Abs(_console.Length - _trainingResults[i].Length)) / _trainingResults[i].Length);
87119

88120
// Make the AI wait until a solution is found without the penalty (too many input characters).
89121
Fitness -= penalty;
@@ -97,6 +129,12 @@ protected override double GetFitnessMethod(string program)
97129
Ticks += _bf.m_Ticks;
98130
}
99131

132+
/*// Give a bonus for using multiple memory registers, supporting diversity.
133+
if (memoryHash.Count > 1)
134+
{
135+
countBonus += memoryHash.Count * 10;
136+
}*/
137+
100138
if (_fitness != Double.MaxValue)
101139
{
102140
_fitness = Fitness + countBonus;

Diff for: AIProgrammer.GA/GA.cs

+12
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,18 @@ private void CreateNextGeneration()
283283
GAParams.NextGeneration.Add(g);
284284
}
285285

286+
// Expand genomes.
287+
if (GAParams.NextGeneration[0].Length != GAParams.GenomeSize)
288+
{
289+
Parallel.ForEach(GAParams.NextGeneration, (genome) =>
290+
{
291+
if (genome.Length != GAParams.GenomeSize)
292+
{
293+
genome.Expand(GAParams.GenomeSize);
294+
}
295+
});
296+
}
297+
286298
GAParams.ThisGeneration = new List<Genome>(GAParams.NextGeneration);
287299
/*GAParams.m_thisGeneration.Clear();
288300
foreach (Genome ge in GAParams.m_nextGeneration)

Diff for: AIProgrammer.Types/Genome.cs

+41
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,47 @@ public void Mutate()
203203
}
204204
}
205205

206+
public void Expand(int size)
207+
{
208+
int originalSize = m_genes.Length;
209+
int difference = size - originalSize;
210+
211+
// Resize the genome array.
212+
double[] newGenes = new double[size];
213+
214+
if (difference > 0)
215+
{
216+
if (m_random.NextDouble() < 0.5)
217+
{
218+
// Extend at front.
219+
Array.Copy(m_genes, 0, newGenes, difference, originalSize);
220+
221+
for (int i = 0; i < difference; i++)
222+
{
223+
newGenes[i] = m_random.NextDouble();
224+
}
225+
}
226+
else
227+
{
228+
// Extend at back.
229+
Array.Copy(m_genes, 0, newGenes, 0, originalSize);
230+
231+
for (int i = originalSize; i < size; i++)
232+
{
233+
newGenes[i] = m_random.NextDouble();
234+
}
235+
}
236+
237+
m_genes = newGenes;
238+
}
239+
else
240+
{
241+
Array.Resize(ref m_genes, size);
242+
}
243+
244+
m_length = size;
245+
}
246+
206247
public double[] Genes()
207248
{
208249
return m_genes;

Diff for: AIProgrammer/App.config

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<configuration>
33
<appSettings>
4-
<add key="BrainfuckVersion" value="1"/> <!-- 1 = Brainfuck Classic, 2 = BrainPlus (Brainfuck Extended Type 3, Functions, Faster) -->
4+
<add key="BrainfuckVersion" value="2"/> <!-- 1 = Brainfuck Classic, 2 = BrainPlus (Brainfuck Extended Type 3, Functions, Faster) -->
55
</appSettings>
66
<startup>
77
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />

Diff for: AIProgrammer/Program.cs

+15-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Program
3030
private static GA _ga = null; // Our genetic algorithm instance.
3131
private static GAStatus _bestStatus = new GAStatus(); // Holds values for displaying best generation statistics.
3232
private static DateTime _startTime = DateTime.Now; // Time the program was started.
33-
private static string _appendCode = null; // Program code, containing functions, that will be appended to main program code
33+
private static string _appendCode = XmlToJsonFitness.XmlToJsonFunctions; // Program code, containing functions, that will be appended to main program code
3434
private static TargetParams _targetParams = new TargetParams { TargetString = "hi" }; // Used for displaying the target fitness
3535

3636
#endregion
@@ -39,8 +39,11 @@ class Program
3939

4040
private static double _crossoverRate = 0.70; // Percentage chance that a child genome will use crossover of two parents.
4141
private static double _mutationRate = 0.01; // Percentage chance that a child genome will mutate a gene.
42-
private static int _genomeSize = 250; // Number of programming instructions in generated program (size of genome array).
42+
private static int _genomeSize = 200; // Number of programming instructions in generated program (size of genome array).
43+
private static int _maxGenomeSize = 120; // The max length a genome may grow to (only applicable if _expandAmount > 0).
4344
private static int _maxIterationCount = 2000; // Max iterations a program may run before being killed (prevents infinite loops).
45+
private static int _expandAmount = 0; // The max genome size will expand by this amount, every _expandRate iterations (may help learning). Set to 0 to disable.
46+
private static int _expandRate = 10000; // The max genome size will expand by _expandAmount, at this interval of generations.
4447

4548
#endregion
4649

@@ -61,7 +64,7 @@ class Program
6164
/// <returns>IFitness</returns>
6265
private static IFitness GetFitnessMethod()
6366
{
64-
return new StringStrictFitness(_ga, _maxIterationCount, _targetParams.TargetString, _appendCode);
67+
return new XmlToJsonFitness(_ga, _maxIterationCount, _appendCode);
6568
}
6669

6770
#region Worker Methods
@@ -74,10 +77,18 @@ private static void OnGeneration(GA ga)
7477
if (_bestStatus.Iteration++ > 1000)
7578
{
7679
_bestStatus.Iteration = 0;
77-
Console.WriteLine("Best Fitness: " + _bestStatus.TrueFitness + "/" + _targetParams.TargetFitness + " " + Math.Round(_bestStatus.TrueFitness / _targetParams.TargetFitness * 100, 2) + "%, Ticks: " + _bestStatus.Ticks + ", Running: " + Math.Round((DateTime.Now - _startTime).TotalMinutes) + "m, Best Output: " + _bestStatus.Output + ", Changed: " + _bestStatus.LastChangeDate.ToString() + ", Program: " + _bestStatus.Program);
80+
Console.WriteLine("Best Fitness: " + _bestStatus.TrueFitness + "/" + _targetParams.TargetFitness + " " + Math.Round(_bestStatus.TrueFitness / _targetParams.TargetFitness * 100, 2) + "%, Ticks: " + _bestStatus.Ticks + ", Running: " + Math.Round((DateTime.Now - _startTime).TotalMinutes) + "m, Size: " + _genomeSize + ", Best Output: " + _bestStatus.Output + ", Changed: " + _bestStatus.LastChangeDate.ToString() + ", Program: " + _bestStatus.Program);
7881

7982
ga.Save("my-genetic-algorithm.dat");
8083
}
84+
85+
if (_expandAmount > 0 && ga.GAParams.CurrentGeneration > 0 && ga.GAParams.CurrentGeneration % _expandRate == 0 && _genomeSize < _maxGenomeSize)
86+
{
87+
_genomeSize += _expandAmount;
88+
ga.GAParams.GenomeSize = _genomeSize;
89+
90+
_bestStatus.Fitness = 0; // Update display of best program, since genome has changed and we have a better/worse new best fitness.
91+
}
8192
}
8293

8394
/// <summary>

0 commit comments

Comments
 (0)