1 | #region License Information |
---|
2 | /* HeuristicLab |
---|
3 | * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL) |
---|
4 | * |
---|
5 | * This file is part of HeuristicLab. |
---|
6 | * |
---|
7 | * HeuristicLab is free software: you can redistribute it and/or modify |
---|
8 | * it under the terms of the GNU General Public License as published by |
---|
9 | * the Free Software Foundation, either version 3 of the License, or |
---|
10 | * (at your option) any later version. |
---|
11 | * |
---|
12 | * HeuristicLab is distributed in the hope that it will be useful, |
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | * GNU General Public License for more details. |
---|
16 | * |
---|
17 | * You should have received a copy of the GNU General Public License |
---|
18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>. |
---|
19 | */ |
---|
20 | #endregion |
---|
21 | |
---|
22 | using System; |
---|
23 | using HeuristicLab.Common; |
---|
24 | using HeuristicLab.Core; |
---|
25 | using HeuristicLab.Data; |
---|
26 | using HeuristicLab.Parameters; |
---|
27 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; |
---|
28 | |
---|
29 | namespace HeuristicLab.Encodings.RealVectorEncoding { |
---|
30 | /// <summary> |
---|
31 | /// Performs the simulated binary crossover (SBX) on a vector of real values such that each position is either crossed contracted or expanded with a certain probability. |
---|
32 | /// The probability distribution is designed such that the children will lie closer to their parents as is the case with the single point binary crossover. |
---|
33 | /// </summary> |
---|
34 | /// <remarks> |
---|
35 | /// It is implemented as described in Deb, K. and Agrawal, R. B. 1995. Simulated binary crossover for continuous search space. Complex Systems, 9, pp. 115-148. |
---|
36 | /// </remarks> |
---|
37 | [Item("SimulatedBinaryCrossover", "The simulated binary crossover (SBX) is implemented as described in Deb, K. and Agrawal, R. B. 1995. Simulated binary crossover for continuous search space. Complex Systems, 9, pp. 115-148.")] |
---|
38 | [StorableClass] |
---|
39 | public class SimulatedBinaryCrossover : RealVectorCrossover { |
---|
40 | /// <summary> |
---|
41 | /// The parameter must be greater or equal than 0. Common values are in the range [0;5] and more often just [2;5]. |
---|
42 | /// </summary> |
---|
43 | public ValueLookupParameter<DoubleValue> ContiguityParameter { |
---|
44 | get { return (ValueLookupParameter<DoubleValue>)Parameters["Contiguity"]; } |
---|
45 | } |
---|
46 | |
---|
47 | [StorableConstructor] |
---|
48 | protected SimulatedBinaryCrossover(bool deserializing) : base(deserializing) { } |
---|
49 | protected SimulatedBinaryCrossover(SimulatedBinaryCrossover original, Cloner cloner) : base(original, cloner) { } |
---|
50 | /// <summary> |
---|
51 | /// Initializes a new instance of <see cref="SimulatedBinaryCrossover"/> with one |
---|
52 | /// parameter (<c>Contiguity</c>). |
---|
53 | /// </summary> |
---|
54 | public SimulatedBinaryCrossover() |
---|
55 | : base() { |
---|
56 | Parameters.Add(new ValueLookupParameter<DoubleValue>("Contiguity", "Specifies whether the crossover should produce very different (small value) or very similar (large value) children. Valid values must be greater or equal to 0.", new DoubleValue(2))); |
---|
57 | } |
---|
58 | |
---|
59 | public override IDeepCloneable Clone(Cloner cloner) { |
---|
60 | return new SimulatedBinaryCrossover(this, cloner); |
---|
61 | } |
---|
62 | |
---|
63 | /// <summary> |
---|
64 | /// Performs the simulated binary crossover on a real vector. Each position is crossed with a probability of 50% and if crossed either a contracting crossover or an expanding crossover is performed, again with equal probability. |
---|
65 | /// For more details refer to the paper by Deb and Agrawal. |
---|
66 | /// </summary> |
---|
67 | /// <exception cref="ArgumentException">Thrown when the parents' vectors are of unequal length or when <paramref name="contiguity"/> is smaller than 0.</exception> |
---|
68 | /// <remarks> |
---|
69 | /// The manipulated value is not restricted by the (possibly) specified lower and upper bounds. Use the <see cref="BoundsChecker"/> to correct the values after performing the crossover. |
---|
70 | /// </remarks> |
---|
71 | /// <param name="random">The random number generator to use.</param> |
---|
72 | /// <param name="parent1">The first parent vector.</param> |
---|
73 | /// <param name="parent2">The second parent vector.</param> |
---|
74 | /// <param name="contiguity">The contiguity value that specifies how close a child should be to its parents (larger value means closer). The value must be greater or equal than 0. Typical values are in the range [2;5].</param> |
---|
75 | /// <returns>The vector resulting from the crossover.</returns> |
---|
76 | public static RealVector Apply(IRandom random, RealVector parent1, RealVector parent2, DoubleValue contiguity) { |
---|
77 | if (parent1.Length != parent2.Length) throw new ArgumentException("SimulatedBinaryCrossover: Parents are of unequal length"); |
---|
78 | if (contiguity.Value < 0) throw new ArgumentException("SimulatedBinaryCrossover: Contiguity value is smaller than 0", "contiguity"); |
---|
79 | int length = parent1.Length; |
---|
80 | RealVector result = new RealVector(length); |
---|
81 | for (int i = 0; i < length; i++) { |
---|
82 | if (length == 1 || random.NextDouble() < 0.5) { // cross this variable |
---|
83 | double u = random.NextDouble(); |
---|
84 | double beta = 0; |
---|
85 | if (u < 0.5) { // if u is smaller than 0.5 perform a contracting crossover |
---|
86 | beta = Math.Pow(2 * u, 1.0 / (contiguity.Value + 1)); |
---|
87 | } else if (u > 0.5) { // otherwise perform an expanding crossover |
---|
88 | beta = Math.Pow(0.5 / (1.0 - u), 1.0 / (contiguity.Value + 1)); |
---|
89 | } else if (u == 0.5) |
---|
90 | beta = 1; |
---|
91 | |
---|
92 | if (random.NextDouble() < 0.5) |
---|
93 | result[i] = ((parent1[i] + parent2[i]) / 2.0) - beta * 0.5 * Math.Abs(parent1[i] - parent2[i]); |
---|
94 | else |
---|
95 | result[i] = ((parent1[i] + parent2[i]) / 2.0) + beta * 0.5 * Math.Abs(parent1[i] - parent2[i]); |
---|
96 | } else result[i] = parent1[i]; |
---|
97 | } |
---|
98 | return result; |
---|
99 | } |
---|
100 | |
---|
101 | /// <summary> |
---|
102 | /// Checks number of parents, availability of the parameters and forwards the call to <see cref="Apply(IRandom, RealVector, RealVector, DoubleValue)"/>. |
---|
103 | /// </summary> |
---|
104 | /// <exception cref="ArgumentException">Thrown when there are not exactly 2 parents or when the contiguity parameter could not be found.</exception> |
---|
105 | /// <param name="random">The random number generator.</param> |
---|
106 | /// <param name="parents">The collection of parents (must be of size 2).</param> |
---|
107 | /// <returns>The real vector resulting from the crossover.</returns> |
---|
108 | protected override RealVector Cross(IRandom random, ItemArray<RealVector> parents) { |
---|
109 | if (parents.Length != 2) throw new ArgumentException("SimulatedBinaryCrossover: The number of parents is not equal to 2"); |
---|
110 | if (ContiguityParameter.ActualValue == null) throw new InvalidOperationException("SimulatedBinaryCrossover: Parameter " + ContiguityParameter.ActualName + " could not be found."); |
---|
111 | return Apply(random, parents[0], parents[1], ContiguityParameter.ActualValue); |
---|
112 | } |
---|
113 | } |
---|
114 | } |
---|