/
Individual.cs
101 lines (90 loc) · 3.42 KB
/
Individual.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
namespace Localwire.Graphinder.Core.Algorithms.GeneticAlgorithm
{
using System;
using System.Linq;
using Graph;
using Problems;
/// <summary>
/// Represents single individual (atomic element of a population) holding solution to given problem.
/// </summary>
public class Individual : BaseModel, IComparable<Individual>
{
//Needed for crossover and passing Graph to offspring
public readonly Graph Graph;
public readonly IProblem Problem;
private readonly Random _random = new Random();
private readonly bool[] _currentSolution;
private readonly uint _totalSize;
private int _currentOutcome;
public Individual(Graph graph, IProblem problem, bool[] solution = null, Guid? id = null) : base(id)
{
if (graph == null || problem == null) throw new ArgumentNullException("Neither graph nor problem can be null!");
if (!graph.IsValid()) throw new ArgumentException("Graph is not valid!");
Graph = graph;
Problem = problem;
_totalSize = (uint)Graph.TotalNodes;
if (solution == null || solution.Length < _totalSize)
{
_currentSolution = new bool[_totalSize];
RandomizeSolution();
}
else
{
_currentSolution = solution;
}
EnsureCorectness();
}
public bool[] CurrentSolution { get { return _currentSolution; } }
public int SolutionOutcome { get { return _currentOutcome; } }
//TODO: Should be dependent on IProblem's criterias!
public uint SolutionFitness { get { return Convert.ToUInt32(Graph.TotalNodes - SolutionOutcome) + 1; } }
public int CompareTo(Individual other)
{
if (other == null) return 1;
var fitnessComparison = SolutionFitness.CompareTo(other.SolutionFitness);
if (fitnessComparison != 0)
return fitnessComparison;
return Id.CompareTo(other.Id);
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var casted = obj as Individual;
if (casted == null) return false;
return casted.Id.Equals(Id);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
/// <summary>
/// Ensure correctness of solution that individual holds
/// </summary>
private void EnsureCorectness()
{
if (Problem == null) throw new ArgumentException("Problem for individual has not been set");
//Keep rolling until solution is correct
while (!Problem.IsSolutionCorrect(_currentSolution))
{
for (int i = 0; i < _currentSolution.Length; i++)
{
if (!_currentSolution[i])
{
_currentSolution[i] = !_currentSolution[i];
break;
}
}
}
_currentOutcome = _currentSolution.Count(s => s);
}
/// <summary>
/// Randomize initial solution of individual
/// </summary>
private void RandomizeSolution()
{
for (int i = 0; i < _totalSize; i++)
_currentSolution[i] = _random.NextDouble() <= 0.5;
}
}
}