#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Encodings.IntegerVectorEncoding {
///
/// Blend alpha-beta crossover for integer vectors (BLX-a-b). Creates a new offspring by selecting a
/// random value from the interval between the two alleles of the parent solutions and rounds the
/// result to the nearest feasible value. The interval is increased in both directions as follows:
/// Into the direction of the 'better' solution by the factor alpha, into the direction of the
/// 'worse' solution by the factor beta.
///
[Item("RoundedBlendAlphaBetaCrossover", "The rounded blend alpha beta crossover (BLX-a-b) for integer vectors is similar to the blend alpha crossover (BLX-a), but distinguishes between the better and worse of the parents. The interval from which to choose the new offspring can be extended beyond the better parent by specifying a higher alpha value, and beyond the worse parent by specifying a higher beta value. The new offspring is sampled uniformly in the extended range and rounded to the next feasible integer.")]
[StorableClass]
public class RoundedBlendAlphaBetaCrossover : BoundedIntegerVectorCrossover, ISingleObjectiveOperator {
///
/// Whether the problem is a maximization or minimization problem.
///
public ValueLookupParameter MaximizationParameter {
get { return (ValueLookupParameter)Parameters["Maximization"]; }
}
///
/// The quality of the parents.
///
public ScopeTreeLookupParameter QualityParameter {
get { return (ScopeTreeLookupParameter)Parameters["Quality"]; }
}
///
/// The Alpha parameter controls the extension of the range beyond the better parent. The value must be >= 0 and does not depend on Beta.
///
public ValueLookupParameter AlphaParameter {
get { return (ValueLookupParameter)Parameters["Alpha"]; }
}
///
/// The Beta parameter controls the extension of the range beyond the worse parent. The value must be >= 0 and does not depend on Alpha.
///
public ValueLookupParameter BetaParameter {
get { return (ValueLookupParameter)Parameters["Beta"]; }
}
[StorableConstructor]
protected RoundedBlendAlphaBetaCrossover(bool deserializing) : base(deserializing) { }
protected RoundedBlendAlphaBetaCrossover(RoundedBlendAlphaBetaCrossover original, Cloner cloner) : base(original, cloner) { }
///
/// Initializes a new instance of with four additional parameters
/// (Maximization, Quality, Alpha and Beta).
///
public RoundedBlendAlphaBetaCrossover()
: base() {
Parameters.Add(new ValueLookupParameter("Maximization", "Whether the problem is a maximization problem or not."));
Parameters.Add(new ScopeTreeLookupParameter("Quality", "The quality values of the parents."));
Parameters.Add(new ValueLookupParameter("Alpha", "The Alpha parameter controls the extension of the range beyond the better parent. The value must be >= 0 and does not depend on Beta.", new DoubleValue(0.75)));
Parameters.Add(new ValueLookupParameter("Beta", "The Beta parameter controls the extension of the range beyond the worse parent. The value must be >= 0 and does not depend on Alpha.", new DoubleValue(0.25)));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new RoundedBlendAlphaBetaCrossover(this, cloner);
}
///
/// Performs the rounded blend alpha beta crossover (BLX-a-b) on two parent vectors.
///
///
/// Thrown when either:
///
/// - The length of and is not equal.
/// - The parameter is smaller than 0.
/// - The parameter is smaller than 0.
///
///
/// The random number generator to use.
/// The better of the two parents with regard to their fitness.
/// The worse of the two parents with regard to their fitness.
/// The bounds and step size for each dimension (will be cycled in case there are less rows than elements in the parent vectors).
/// The parameter alpha.
/// The parameter beta.
/// The integer vector that results from the crossover.
public static IntegerVector Apply(IRandom random, IntegerVector betterParent, IntegerVector worseParent, IntMatrix bounds, DoubleValue alpha, DoubleValue beta) {
if (betterParent.Length != worseParent.Length) throw new ArgumentException("RoundedBlendAlphaBetaCrossover: The parents' vectors are of different length.", "betterParent");
if (alpha.Value < 0) throw new ArgumentException("RoundedBlendAlphaBetaCrossover: Parameter alpha must be greater or equal to 0.", "alpha");
if (beta.Value < 0) throw new ArgumentException("RoundedBlendAlphaBetaCrossover: Parameter beta must be greater or equal to 0.", "beta");
if (bounds == null || bounds.Rows < 1 || bounds.Columns < 2) throw new ArgumentException("RoundedBlendAlphaBetaCrossover: Invalid bounds specified.", "bounds");
int length = betterParent.Length;
double min, max, d;
var result = new IntegerVector(length);
int minBound, maxBound, step = 1;
for (int i = 0; i < length; i++) {
minBound = bounds[i % bounds.Rows, 0];
maxBound = bounds[i % bounds.Rows, 1];
if (bounds.Columns > 2) step = bounds[i % bounds.Rows, 2];
maxBound = FloorFeasible(minBound, maxBound, step, maxBound - 1);
d = Math.Abs(betterParent[i] - worseParent[i]);
if (betterParent[i] <= worseParent[i]) {
min = FloorFeasible(minBound, maxBound, step, betterParent[i] - d * alpha.Value);
max = CeilingFeasible(minBound, maxBound, step, worseParent[i] + d * beta.Value);
} else {
min = FloorFeasible(minBound, maxBound, step, worseParent[i] - d * beta.Value);
max = CeilingFeasible(minBound, maxBound, step, betterParent[i] + d * alpha.Value);
}
result[i] = RoundFeasible(minBound, maxBound, step, min + random.NextDouble() * (max - min));
}
return result;
}
///
/// Checks if the number of parents is equal to 2, if all parameters are available and forwards the call to .
///
/// Thrown when the number of parents is not equal to 2.
///
/// Thrown when either:
///
/// - Maximization parameter could not be found.
/// - Quality parameter could not be found or the number of quality values is not equal to the number of parents.
/// - Alpha parameter could not be found.
/// - Beta parameter could not be found.
///
///
/// The random number generator to use.
/// The collection of parents (must be of size 2).
/// The bounds and step size for each dimension (will be cycled in case there are less rows than elements in the parent vectors).
/// The integer vector that results from the crossover.
protected override IntegerVector CrossBounded(IRandom random, ItemArray parents, IntMatrix bounds) {
if (parents.Length != 2) throw new ArgumentException("RoundedBlendAlphaBetaCrossover: Number of parents is not equal to 2.", "parents");
if (MaximizationParameter.ActualValue == null) throw new InvalidOperationException("RoundedBlendAlphaBetaCrossover: Parameter " + MaximizationParameter.ActualName + " could not be found.");
if (QualityParameter.ActualValue == null || QualityParameter.ActualValue.Length != parents.Length) throw new InvalidOperationException("RoundedBlendAlphaBetaCrossover: Parameter " + QualityParameter.ActualName + " could not be found, or not in the same quantity as there are parents.");
if (AlphaParameter.ActualValue == null || BetaParameter.ActualValue == null) throw new InvalidOperationException("RoundedBlendAlphaBetaCrossover: Parameter " + AlphaParameter.ActualName + " or paramter " + BetaParameter.ActualName + " could not be found.");
ItemArray qualities = QualityParameter.ActualValue;
bool maximization = MaximizationParameter.ActualValue.Value;
if (maximization && qualities[0].Value >= qualities[1].Value || !maximization && qualities[0].Value <= qualities[1].Value)
return Apply(random, parents[0], parents[1], bounds, AlphaParameter.ActualValue, BetaParameter.ActualValue);
else {
return Apply(random, parents[1], parents[0], bounds, AlphaParameter.ActualValue, BetaParameter.ActualValue);
}
}
}
}