Skip to content

Commit 324d9e2

Browse files
committed
CK 170510
- New infrastructure for genetic algorithms including; selection, mutation and crossover with default implementations. -- Added random & tounament selection methods -- Added point crossover method -- Added random, flip & gaussian mutation methods - Added new Filters framework along with Roulette Wheel sampling, for sampling objects according to a probability distribution - Added extension methods to ease common functions - Added new collection (NSortedList) to overcome SortedList limitations for maintaining sorted collections in ascending and descending order. Adds: #35 (MVP), Tests Passing.
1 parent f7bf398 commit 324d9e2

32 files changed

+2520
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Linq;
5+
6+
using numl.AI.Collections;
7+
8+
using Xunit;
9+
10+
using MATH = System.Math;
11+
using System.Diagnostics;
12+
13+
namespace numl.Tests.CollectionTests
14+
{
15+
[Trait("CollectionTests", "CollectionTests")]
16+
public class CollectionsTests
17+
{
18+
[Fact]
19+
public void NSortedList_Sort_Test()
20+
{
21+
for (int run = 0; run < 2; run++)
22+
{
23+
bool reverse = (run != 0);
24+
25+
var sorted = new NSortedList<int>(-1, reverse);
26+
27+
int length = Math.Probability.Sampling.GetUniform(10, 1024);
28+
29+
for (int i = 0; i < length; i++)
30+
{
31+
int val = Math.Probability.Sampling.GetUniform(0, length - 1);
32+
sorted.Add(val);
33+
}
34+
35+
int remove = (int) MATH.Ceiling(length / 2.0);
36+
for (int i = 0; i < remove; i++)
37+
{
38+
int index = Math.Probability.Sampling.GetUniform(0, sorted.Count - 1);
39+
sorted.Remove(index);
40+
}
41+
42+
bool result = false;
43+
for (int i = 1; i < (length - remove); i++)
44+
{
45+
if (reverse)
46+
{
47+
result = sorted[i - 1] >= sorted[i];
48+
Assert.True(result, $"Item at {i - 1} was larger than expected");
49+
}
50+
else
51+
{
52+
result = sorted[i - 1] <= sorted[i];
53+
Assert.True(result, $"Item at {i - 1} was smaller than expected");
54+
}
55+
}
56+
}
57+
}
58+
59+
[Fact]
60+
public void NSortedList_Limit_Reverse_Test()
61+
{
62+
for (int run = 0; run < 2; run++)
63+
{
64+
int length = Math.Probability.Sampling.GetUniform(10, 1024);
65+
bool reverse = (run != 0);
66+
67+
var sorted = new NSortedList<int>(length, reverse);
68+
69+
for (int i = 0; i < length; i++)
70+
{
71+
int val = Math.Probability.Sampling.GetUniform(0, length - 1);
72+
sorted.Add(val);
73+
}
74+
75+
length = (length / 2);
76+
77+
sorted.Limit = length;
78+
79+
Assert.True(sorted.Count == length, "Length exceeds specified limit");
80+
81+
for (int i = 0; i < length / 2; i++)
82+
{
83+
int val = Math.Probability.Sampling.GetUniform(0, length - 1);
84+
sorted.Add(val);
85+
}
86+
87+
Assert.True(sorted.Count == length, "Length exceeds specified limit after additions");
88+
89+
bool result = false;
90+
for (int i = 1; i < sorted.Count; i++)
91+
{
92+
if (reverse)
93+
{
94+
result = sorted[i - 1] >= sorted[i];
95+
Assert.True(result, $"Item at {i - 1} was larger than expected");
96+
}
97+
else
98+
{
99+
result = sorted[i - 1] <= sorted[i];
100+
Assert.True(result, $"Item at {i - 1} was smaller than expected");
101+
}
102+
}
103+
}
104+
}
105+
106+
[Fact]
107+
public void NSortedList_Size_Test()
108+
{
109+
var sorted = new NSortedList<int>();
110+
111+
int length = Math.Probability.Sampling.GetUniform(10, 1024);
112+
113+
var dict = new Dictionary<int, int>();
114+
115+
for (int i = 0; i < length; i++)
116+
{
117+
int val = Math.Probability.Sampling.GetUniform(0, length - 1);
118+
sorted.Add(val);
119+
120+
dict[val] = (dict.ContainsKey(val) ? dict[val] + 1 : 1);
121+
}
122+
123+
int remove = (int) MATH.Ceiling(length / 2.0);
124+
for (int i = 0; i < remove; i++)
125+
{
126+
int val = Math.Probability.Sampling.GetUniform(0, sorted.Count - 1);
127+
128+
if (dict.ContainsKey(val))
129+
{
130+
sorted.Remove(val);
131+
132+
dict[val] = 0;
133+
134+
Assert.False(sorted.Contains(val));
135+
}
136+
}
137+
138+
var contains = (dict.Where(w => w.Value == 0 && sorted.Contains(w.Key)));
139+
140+
bool result = (contains.Count() == 0);
141+
142+
Assert.True(result, "Length was not equal to the elements in the collection");
143+
144+
bool lresult = (sorted.Select(s => s).Count() == sorted.Count);
145+
146+
Assert.True(lresult, "Enumerator extends beyond number of accessible items in collection");
147+
}
148+
149+
[Fact]
150+
public void NSortedList_Speed_Test()
151+
{
152+
int epochs = 10000;
153+
154+
Stopwatch timer = new Stopwatch();
155+
156+
timer.Start();
157+
158+
var nsorted = new NSortedList<Foo>();
159+
160+
for (int i = 0; i < epochs; i++)
161+
{
162+
var foo = new Foo();
163+
nsorted.Add(foo);
164+
}
165+
166+
timer.Stop();
167+
168+
long ts1 = timer.ElapsedMilliseconds;
169+
170+
timer.Stop();
171+
Foo._Id = 0;
172+
173+
timer.Start();
174+
175+
var sorted = new SortedList<int, Foo>();
176+
177+
for (int i = 0; i < epochs; i++)
178+
{
179+
var foo = new Foo();
180+
sorted.Add(foo.Weight, foo);
181+
}
182+
183+
timer.Stop();
184+
185+
long ts2 = timer.ElapsedMilliseconds;
186+
187+
Assert.True(ts1 < ts2);
188+
}
189+
190+
public class Foo : IComparable
191+
{
192+
internal static int _Id = 0;
193+
194+
public int Weight { get; set; }
195+
196+
public Foo()
197+
{
198+
this.Weight = (++_Id);
199+
}
200+
201+
public int CompareTo(object obj)
202+
{
203+
var other = (Foo) obj;
204+
205+
return this.Weight.CompareTo(other.Weight);
206+
}
207+
}
208+
}
209+
}
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
using Xunit;
6+
7+
using numl.Math.Probability;
8+
using numl.Math.LinearAlgebra;
9+
using numl.Genetic;
10+
using numl.Genetic.Functions.Crossover;
11+
using numl.Genetic.Functions.Mutation;
12+
13+
namespace numl.Tests.GeneticTests
14+
{
15+
public abstract class BaseGenetic
16+
{
17+
18+
public void Test_Mutation<T>(Func<T> factory, bool binary, int length, Func<IChromosome, IChromosome, bool> fnTest,
19+
Func<int, double> fnSequenceInitializer = null)
20+
where T : IMutationFunction
21+
{
22+
var s = (fnSequenceInitializer == null ?
23+
Vector.Create(length, i => (binary ? (i % 2 == 0 ? 1 : 0) : (i + 1)))
24+
: Vector.Create(length, fnSequenceInitializer));
25+
26+
var parent = new Chromosome()
27+
{
28+
Sequence = s.Copy()
29+
};
30+
31+
var mutator = factory();
32+
33+
var clone = mutator.Mutate(parent);
34+
35+
bool result = fnTest(parent, clone);
36+
37+
Assert.True(result);
38+
}
39+
40+
public void Test_Crossover<T>(Func<T> factory, int length, Func<IChromosome, IChromosome, IChromosome, bool> fnTest)
41+
where T : ICrossoverFunction
42+
{
43+
ICrossoverFunction crossover = factory();
44+
45+
var s1 = Vector.Create(length, i => (i + 1) * 100);
46+
var parent1 = new Chromosome()
47+
{
48+
Sequence = s1.Copy()
49+
};
50+
51+
var s2 = Vector.Create(length, i => (i + 1));
52+
var parent2 = new Chromosome()
53+
{
54+
Sequence = s2.Copy()
55+
};
56+
57+
var child = crossover.Crossover(parent1, parent2);
58+
59+
bool result = fnTest(parent1, parent2, child);
60+
61+
Assert.True(result);
62+
}
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
using Xunit;
7+
8+
using numl.Genetic;
9+
using numl.Genetic.Functions.Crossover;
10+
11+
using MATH = System.Math;
12+
13+
namespace numl.Tests.GeneticTests
14+
{
15+
[Trait("Category", "Genetic")]
16+
public class CrossoverTests : BaseGenetic
17+
{
18+
[Fact]
19+
public void Test_Point_Crossover()
20+
{
21+
double prob = 0.25;
22+
int points = 5;
23+
int length = 50;
24+
25+
while (prob <= 1.0)
26+
{
27+
var crossover = new PointCrossover(points) { Probability = prob };
28+
29+
this.Test_Crossover(() => crossover, length,
30+
(p1, p2, child) =>
31+
{
32+
bool result = false;
33+
34+
var sequence = child.Sequence;
35+
36+
double count1 = p1.Sequence.Intersect(sequence).Count();
37+
double count2 = p2.Sequence.Intersect(sequence).Count();
38+
39+
double p = (MATH.Pow(prob, points)) / 2;
40+
41+
double c1 = 0, c2 = 0;
42+
43+
int i; double diff; double t1 = 0, t2 = 0;
44+
for (i = 0; i < crossover.Points.Length - 1; i++)
45+
{
46+
diff = (crossover.Points[i + 1] - crossover.Points[i]);
47+
48+
if (i % 2 == 0)
49+
{
50+
c1 += diff;
51+
t1 += (diff / length) * (1.0 - p);
52+
}
53+
else
54+
{
55+
c2 += diff;
56+
t2 += (diff / length) * p;
57+
}
58+
}
59+
60+
diff = length - crossover.Points[i];
61+
62+
if (i % 2 == 0)
63+
{
64+
c1 += diff;
65+
t1 += (diff / length) * (1.0 - p);
66+
}
67+
else
68+
{
69+
c2 += diff;
70+
t2 += (diff / length) * p;
71+
}
72+
73+
t1 = t1 / (t1 + t2);
74+
t2 = t2 / (t1 + t2);
75+
76+
result = (t1 >= (1.0 - p * 2.0) && t2 <= p * 2.0);
77+
78+
return result;
79+
});
80+
81+
prob += 0.25;
82+
}
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)