1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022019 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.IntegerVectorEncoding {


30  /// <summary>


31  /// Rounded blend alpha crossover for integer vectors (BLXa). Creates a new offspring by selecting a random value


32  /// from the interval between the two alleles of the parent solutions and rounding the result to the next feasible


33  /// integer. The interval is increased in both directions by the factor alpha.


34  /// </summary>


35  [Item("RoundedBlendAlphaCrossover", "The rounded blend alpha crossover (BLXa) for integer vectors creates new offspring by sampling a new value in the range [min_i  d * alpha, max_i + d * alpha) at each position i and rounding the result to the next feasible integer. Here min_i and max_i are the smaller and larger value of the two parents at position i and d is max_i  min_i.")]


36  [StorableClass]


37  public class RoundedBlendAlphaCrossover : BoundedIntegerVectorCrossover {


38  /// <summary>


39  /// The alpha parameter specifies how much the interval between the parents should be extended to the left and right.


40  /// The value of this parameter also determines the name of the operator: BLX0.0 for example means alpha is set to 0.


41  /// When Alpha is 0, then the offspring will only be chosen in between the parents, the bigger alpha is the more it will be possible to choose


42  /// values left and right of the min and max value for each gene.


43  /// </summary>


44  public ValueLookupParameter<DoubleValue> AlphaParameter {


45  get { return (ValueLookupParameter<DoubleValue>)Parameters["Alpha"]; }


46  }


47 


48  [StorableConstructor]


49  protected RoundedBlendAlphaCrossover(bool deserializing) : base(deserializing) { }


50  protected RoundedBlendAlphaCrossover(RoundedBlendAlphaCrossover original, Cloner cloner) : base(original, cloner) { }


51  /// <summary>


52  /// Initializes a new instance of <see cref="RoundedBlendAlphaCrossover"/> with one parameter (<c>Alpha</c>).


53  /// </summary>


54  public RoundedBlendAlphaCrossover()


55  : base() {


56  Parameters.Add(new ValueLookupParameter<DoubleValue>("Alpha", "The Alpha parameter controls the extension of the range beyond the two parents. It must be >= 0. A value of 0.5 means that half the range is added to both sides of the intervals.", new DoubleValue(0.5)));


57  }


58 


59  public override IDeepCloneable Clone(Cloner cloner) {


60  return new RoundedBlendAlphaCrossover(this, cloner);


61  }


62 


63  /// <summary>


64  /// Performs the rounded blend alpha crossover (BLXa) of two integer vectors.<br/>


65  /// It creates new offspring by sampling a new value in the range [min_i  d * alpha, max_i + d * alpha) at each position i


66  /// and rounding the result to the next integer.


67  /// Here min_i and max_i are the smaller and larger value of the two parents at position i and d is max_i  min_i.


68  /// </summary>


69  /// <exception cref="ArgumentException">


70  /// Thrown when <paramref name="parent1"/> and <paramref name="parent2"/> are of different length or<br/>


71  /// when <paramref name="alpha"/> is less than 0.


72  /// </exception>


73  /// <param name="random">The random number generator.</param>


74  /// <param name="parent1">The first parent for the crossover operation.</param>


75  /// <param name="parent2">The second parent for the crossover operation.</param>


76  /// <param name="bounds">The bounds and step size for each dimension (will be cycled in case there are less rows than elements in the parent vectors).</param>


77  /// <param name="alpha">The alpha value for the crossover.</param>


78  /// <returns>The newly created integer vector resulting from the crossover operation.</returns>


79  public static IntegerVector Apply(IRandom random, IntegerVector parent1, IntegerVector parent2, IntMatrix bounds, DoubleValue alpha) {


80  if (parent1.Length != parent2.Length) throw new ArgumentException("RoundedBlendAlphaCrossover: The parents' vectors are of different length.", "parent1");


81  if (alpha.Value < 0) throw new ArgumentException("RoundedBlendAlphaCrossover: Paramter alpha must be greater or equal than 0.", "alpha");


82  if (bounds == null  bounds.Rows < 1  bounds.Columns < 2) throw new ArgumentException("RoundedBlendAlphaCrossover: Invalid bounds specified.", "bounds");


83 


84  int length = parent1.Length;


85  var result = new IntegerVector(length);


86  double max = 0, min = 0, d = 0, resMin = 0, resMax = 0;


87  int minBound, maxBound, step = 1;


88 


89  for (int i = 0; i < length; i++) {


90  minBound = bounds[i % bounds.Rows, 0];


91  maxBound = bounds[i % bounds.Rows, 1];


92  if (bounds.Columns > 2) step = bounds[i % bounds.Rows, 2];


93  maxBound = FloorFeasible(minBound, maxBound, step, maxBound  1);


94 


95  max = Math.Max(parent1[i], parent2[i]);


96  min = Math.Min(parent1[i], parent2[i]);


97  d = Math.Abs(max  min);


98  resMin = FloorFeasible(minBound, maxBound, step, min  d * alpha.Value);


99  resMax = CeilingFeasible(minBound, maxBound, step, max + d * alpha.Value);


100 


101  result[i] = RoundFeasible(minBound, maxBound, step, resMin + random.NextDouble() * Math.Abs(resMax  resMin));


102  }


103  return result;


104  }


105 


106  /// <summary>


107  /// Checks that the number of parents is equal to 2 and forwards the call to <see cref="Apply(IRandom, RealVector, RealVector, DoubleValue)"/>.


108  /// </summary>


109  /// <exception cref="ArgumentException">Thrown when the number of parents is not equal to 2.</exception>


110  /// <exception cref="InvalidOperationException">Thrown when the parameter alpha could not be found.</exception>


111  /// <param name="random">The random number generator to use.</param>


112  /// <param name="parents">The collection of parents (must be of size 2).</param>


113  /// <param name="bounds">The bounds and step size for each dimension (will be cycled in case there are less rows than elements in the parent vectors).</param>


114  /// <returns>The integer vector resulting from the crossover operation.</returns>


115  protected override IntegerVector CrossBounded(IRandom random, ItemArray<IntegerVector> parents, IntMatrix bounds) {


116  if (parents.Length != 2) throw new ArgumentException("RoundedBlendAlphaCrossover: The number of parents is not equal to 2", "parents");


117  if (AlphaParameter.ActualValue == null) throw new InvalidOperationException("RoundedBlendAlphaCrossover: Parameter " + AlphaParameter.ActualName + " could not be found.");


118  return Apply(random, parents[0], parents[1], bounds, AlphaParameter.ActualValue);


119  }


120  }


121  }

