forked from giacomelli/GeneticSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
OrderBasedCrossover.cs
124 lines (108 loc) · 5.23 KB
/
OrderBasedCrossover.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using GeneticSharp.Domain.Chromosomes;
using GeneticSharp.Domain.Randomizations;
namespace GeneticSharp.Domain.Crossovers
{
/// <summary>
/// Order-based crossover (OX2).
/// <remarks>
/// OX2 was suggested in connection with schedule problems, is a modification of the OX1 operator.
/// The OX2 operator selects at random several positions in a parent string, and the order of the elements in the
/// selected positions of this parent is imposed on the other parent. For example, consider the parents
/// (1 2 3 4 5 6 7 8) and (2 4 6 8 7 5 3 1), and suppose that in the second parent in the second, third
/// and sixth positions are selected. The elements in these positions are 4, 6 and 5 respectively.
/// In the first parent, these elements are present at the fourth, fifth and sixth positions.
/// Now the offspring are equal to parent 1 except in the fourth, fifth and sixth positions: (1 2 3 * * * 7 8).
/// We add the missing elements to the offspring in the same order in which they appear in the second parent.
/// This results in (1 2 3 4 6 5 7 8). Exchanging the role of the first parent and the second parent gives,
/// using the same selected positions, (2 4 3 8 7 5 6 1).
/// </remarks>
/// </summary>
[DisplayName("Order-based (OX2)")]
public class OrderBasedCrossover : CrossoverBase
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="GeneticSharp.Domain.Crossovers.OrderBasedCrossover"/> class.
/// </summary>
public OrderBasedCrossover()
: base(2, 2)
{
IsOrdered = true;
}
#endregion
#region Methods
/// <summary>
/// Performs the cross with specified parents generating the children.
/// </summary>
/// <param name="parents">The parents chromosomes.</param>
/// <returns>The offspring (children) of the parents.</returns>
protected override IList<IChromosome> PerformCross(IList<IChromosome> parents)
{
ValidateParents(parents);
var parentOne = parents[0];
var parentTwo = parents[1];
var rnd = RandomizationProvider.Current;
var swapIndexesLength = rnd.GetInt(1, parentOne.Length - 1);
var swapIndexes = rnd.GetUniqueInts(swapIndexesLength, 0, parentOne.Length);
var firstChild = CreateChild(parentOne, parentTwo, swapIndexes);
var secondChild = CreateChild(parentTwo, parentOne, swapIndexes);
return new List<IChromosome>() { firstChild, secondChild };
}
/// <summary>
/// Validates the parents.
/// </summary>
/// <param name="parents">The parents.</param>
protected virtual void ValidateParents(IList<IChromosome> parents)
{
if (parents.AnyHasRepeatedGene())
{
throw new CrossoverException(this, "The Order-based Crossover (OX2) can be only used with ordered chromosomes. The specified chromosome has repeated genes.");
}
}
/// <summary>
/// Creates the child.
/// </summary>
/// <param name="firstParent">First parent.</param>
/// <param name="secondParent">Second parent.</param>
/// <param name="swapIndexes">The swap indexes.</param>
/// <returns>
/// The child.
/// </returns>
protected virtual IChromosome CreateChild(IChromosome firstParent, IChromosome secondParent, int[] swapIndexes)
{
// ...suppose that in the second parent in the second, third
// and sixth positions are selected. The elements in these positions are 4, 6 and 5 respectively...
var secondParentSwapGenes = secondParent.GetGenes()
.Select((g, i) => new { Gene = g, Index = i })
.Where((g) => swapIndexes.Contains(g.Index))
.ToArray();
var firstParentGenes = firstParent.GetGenes();
// ...in the first parent, these elements are present at the fourth, fifth and sixth positions...
var firstParentSwapGenes = firstParentGenes
.Select((g, i) => new { Gene = g, Index = i })
.Where((g) => secondParentSwapGenes.Any(s => s.Gene == g.Gene))
.ToArray();
var child = firstParent.CreateNew();
var secondParentSwapGensIndex = 0;
for (int i = 0; i < firstParent.Length; i++)
{
// Now the offspring are equal to parent 1 except in the fourth, fifth and sixth positions.
// We add the missing elements to the offspring in the same order in which they appear in the second parent.
if (firstParentSwapGenes.Any(f => f.Index == i))
{
child.ReplaceGene(i, secondParentSwapGenes[secondParentSwapGensIndex++].Gene);
}
else
{
child.ReplaceGene(i, firstParentGenes[i]);
}
}
return child;
}
#endregion
}
}