#region License Information
/* HeuristicLab
* Copyright (C) 2002-2019 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 HEAL.Attic;
using HeuristicLab.Random;
namespace HeuristicLab.Encodings.RealVectorEncoding {
///
/// An operator which creates a new random real vector with each element normally distributed in a specified range.
///
[Item("NormalDistributedRealVectorCreator", "An operator which creates a new random real vector with each element normally distributed in a specified range.")]
[StorableType("790F7401-DD2A-4910-8632-F737E39CE6EE")]
public class NormalDistributedRealVectorCreator : RealVectorCreator, IStrategyParameterCreator {
public IValueLookupParameter MeanParameter {
get { return (IValueLookupParameter)Parameters["Mean"]; }
}
public IValueLookupParameter SigmaParameter {
get { return (IValueLookupParameter)Parameters["Sigma"]; }
}
public IValueParameter MaximumTriesParameter {
get { return (IValueParameter)Parameters["MaximumTries"]; }
}
[StorableConstructor]
protected NormalDistributedRealVectorCreator(StorableConstructorFlag _) : base(_) { }
protected NormalDistributedRealVectorCreator(NormalDistributedRealVectorCreator original, Cloner cloner) : base(original, cloner) { }
public NormalDistributedRealVectorCreator()
: base() {
Parameters.Add(new ValueLookupParameter("Mean", "The mean vector around which the points will be sampled."));
Parameters.Add(new ValueLookupParameter("Sigma", "The standard deviations for all or for each dimension."));
Parameters.Add(new ValueParameter("MaximumTries", "The maximum number of tries to sample within the specified bounds.", new IntValue(1000)));
}
public override IDeepCloneable Clone(Cloner cloner) {
return new NormalDistributedRealVectorCreator(this, cloner);
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
if (!Parameters.ContainsKey("MaximumTries"))
Parameters.Add(new ValueParameter("MaximumTries", "The maximum number of tries to sample within the specified bounds.", new IntValue(1000)));
}
///
/// Generates a new random real vector normally distributed around the given mean with the given and in the interval [min,max).
///
///
/// Thrown when is null.
/// Thrown when is null or of length 0.
/// Thrown when is null or of length 0.
///
///
/// If no bounds are given the bounds will be set to (double.MinValue;double.MaxValue).
///
/// If dimensions of the mean do not lie within the given bounds they're set to either to the min or max of the bounds depending on whether the given dimension
/// for the mean is smaller or larger than the bounds. If min and max for a certain dimension are almost the same the resulting value will be set to min.
///
/// However, please consider that such static bounds are not really meaningful to optimize.
///
/// The sigma vector can contain 0 values in which case the dimension will be exactly the same as the given mean.
///
/// The random number generator.
/// The mean vector around which the resulting vector is sampled.
/// The vector of standard deviations, must have at least one row.
/// The lower and upper bound (1st and 2nd column) of the positions in the vector. If there are less rows than dimensions, the rows are cycled.
/// The maximum number of tries to sample a value inside the bounds for each dimension. If a valid value cannot be obtained, the mean will be used.
/// The newly created real vector.
public static RealVector Apply(IntValue lengthValue, IRandom random, RealVector means, DoubleArray sigmas, DoubleMatrix bounds, int maximumTries = 1000) {
if (lengthValue == null || lengthValue.Value == 0) throw new ArgumentException("Length is not defined or zero");
if (random == null) throw new ArgumentNullException("Random is not defined", "random");
if (means == null || means.Length == 0) throw new ArgumentNullException("Mean is not defined", "mean");
if (sigmas == null || sigmas.Length == 0) throw new ArgumentNullException("Sigma is not defined.", "sigma");
if (bounds == null || bounds.Rows == 0) bounds = new DoubleMatrix(new[,] { { double.MinValue, double.MaxValue } });
var length = lengthValue.Value;
var nd = new NormalDistributedRandom(random, 0, 1);
var result = new RealVector(length);
for (int i = 0; i < result.Length; i++) {
var min = bounds[i % bounds.Rows, 0];
var max = bounds[i % bounds.Rows, 1];
var mean = means[i % means.Length];
var sigma = sigmas[i % sigmas.Length];
if (min.IsAlmost(max) || mean < min) result[i] = min;
else if (mean > max) result[i] = max;
else {
int count = 0;
bool inRange;
do {
result[i] = mean + sigma * nd.NextDouble();
inRange = result[i] >= min && result[i] < max;
count++;
} while (count < maximumTries && !inRange);
if (count == maximumTries && !inRange)
result[i] = mean;
}
}
return result;
}
///
/// Forwards the call to .
///
/// The pseudo random number generator to use.
/// The length of the real vector.
/// The lower and upper bound (1st and 2nd column) of the positions in the vector. If there are less rows than dimensions, the rows are cycled.
/// The newly created real vector.
protected override RealVector Create(IRandom random, IntValue length, DoubleMatrix bounds) {
return Apply(length, random, MeanParameter.ActualValue, SigmaParameter.ActualValue, bounds, MaximumTriesParameter.Value.Value);
}
}
}