#region Namespaces
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
#endregion
namespace ScriptCode
{
/// <summary>
/// Optimization algorithm scripts are used to select the script parameter values to be used in the next optimization runs.
/// </summary>
public partial class MyOptimizationAlgorithm : OptimizationAlgorithmScriptBase // NEVER CHANGE THE CLASS NAME
{
#region Variables
// The number of generations.
private int _generations;
// The number of chromosomes selected in each generation.
private int _chromosomes;
// The number of parents used to create each generation other than the first.
private int _parents;
// The number of mutations allowed from the parent's child chromosomes.
private int _mutations;
// Use for holding the vector indexes of the current generation.
private List<int> _currentGeneration;
// The random number generator.
private Random _random;
#endregion
#region OnInitialize
/// <summary>
/// This function is used for accepting the script parameters and for initializing the script prior to all other function calls.
/// Once the script is assigned to a desktop, its parameter values can be specified by the user.
/// </summary>
/// --------------------------------------------------------------------------------------------------
/// PLEASE USE THE SCRIPT WIZARD (CTRL+W) TO ADD, EDIT AND REMOVE THE SCRIPT PARAMETERS
/// --------------------------------------------------------------------------------------------------
/// YOU MUST SET A PARAM TAG FOR EACH PARAMETER ACCEPTED BY THIS FUNCTION.
/// ALL PARAM TAGS SHOULD BE SET IN THE 'OnInitialize' REGION, RIGHT ABOVE THE 'OnInitialize' FUNCTION.
/// THE ORDER OF THE TAGS MUST MATCH THE ORDER OF THE ACTUAL PARAMETERS.
/// REQUIRED ATTRIBUTES:
/// (1) name: The exact parameter name.
/// (2) type: The type of data to collect from the user:
/// Set to "Integer" when the data type is 'int'
/// Set to "IntegerArray" when the data type is 'int[]'
/// Set to "DateTime" when the data type is 'long'
/// Set to "DateTimeArray" when the data type is 'long[]'
/// Set to "Boolean" when the data type is 'bool'
/// Set to "BooleanArray" when the data type is 'bool[]'
/// Set to "Double" when the data type is 'double'
/// Set to "DoubleArray" when the data type is 'double[]'
/// Set to "String" when the data type is 'string'
/// Set to "StringArray" when the data type is 'string[]'
/// OPTIONAL ATTRIBUTES:
/// (3) default: The default parameter value is only valid when the type is Integer, Boolean, Double, String or an API Type.
/// (4) min: The minimum parameter value is only valid when the type is Integer or Double.
/// (5) max: The maximum parameter value is only valid when the type is Integer or Double.
/// EXAMPLE: <param name="" type="" default="" min="" max="">Enter the parameter description here.</param>
/// --------------------------------------------------------------------------------------------------
/// <param name="generations" type="Integer" default="10">The number of generations.</param>
/// <param name="chromosomes" type="Integer" default="20">The number of chromosomes selected in each generation.</param>
/// <param name="parents" type="Integer" default="3">The number of parents used to create each generation other than the first.</param>
/// <param name="mutations" type="Integer" default="1">The number of mutations allowed from the parent's child chromosomes.</param>
public void OnInitialize(
int generations,
int chromosomes,
int parents,
int mutations)
{
// Set the number of generations.
_generations = generations;
// Set the number of chromosomes.
_chromosomes = chromosomes;
// Set the number of parents.
_parents = parents;
// Set the number of mutations.
_mutations = mutations;
// Create for holding the vector indexes of the current generation.
_currentGeneration = new List<int>();
// Create the random number generator.
_random = new Random();
}
#endregion
#region OnSelectNextOptimizationVectors
/// <summary>
/// This function is called in order to select the next optimization vectors to be processed.
/// The function may be called multiple times in a row before the OnUpdateOptimizationVector function is called.
/// </summary>
/// <returns type="IntegerArray">The indexes of the next optimization vectors to process.</returns>
public override int[] OnSelectNextOptimizationVectors()
{
// Create for holding whether an optimization vector has been added to the new generation.
Dictionary<int, bool> exists = new Dictionary<int, bool>();
// Create for holding the vector for the new chromosomes.
List<int> newChromosomes = new List<int>();
// Check whether this is the first generation.
if (_currentGeneration.Count == 0) {
int attempts = 10000;
// Iterate until there are enough chromosomes in the new generation or there are no more attempts to select a unique random vector.
while (newChromosomes.Count < _chromosomes && attempts > 0) {
// Get a random vector index.
int index = _random.Next(0, OptimizationVectorCount());
// Check whether the vector hasn't been processed.
if (!exists.ContainsKey(index) && !OptimizationVectorIsProcessed(index)) {
// Add the vector index to the new chromosomes.
newChromosomes.Add(index);
// Add the index to the list of existing indexes.
exists.Add(index, true);
}
// Reduce the number of attempts.
attempts--;
}
}
else {
// The number of unique parent attempts.
int uniqueParentAttempts = 0;
// Create for holding the next parent chromosomes.
List<int> nextParentChromosomes = new List<int>();
// Iterate until there are enough parents, while selecting the best vectors.
while (nextParentChromosomes.Count < _parents && uniqueParentAttempts < _parents) {
double bestScore = double.MinValue;
int bestVector = - 1;
// Iterate over the all of the vectors while searching for the best parents.
for (int i = 0; i < OptimizationVectorCount(); i++) {
// Check whether the current vector score is an improvement and the vector hasn't yet been selected as a parent.
if (OptimizationVectorScore(i) > bestScore && !nextParentChromosomes.Contains(i)) {
// Update the best score.
bestScore = OptimizationVectorScore(i);
// Update the best vector.
bestVector = i;
}
}
// Add the best vector to the list of parents.
nextParentChromosomes.Add(bestVector);
// Increase the number of attempts.
uniqueParentAttempts++;
}
// Select the index of the first parent chromosome.
int firstIndex = _random.Next(0, nextParentChromosomes.Count);
// Select the index of the second parent chromosome.
int secondIndex = _random.Next(0, nextParentChromosomes.Count);
// The number of unique parent attempts.
uniqueParentAttempts = 100;
// Iterate until a different second parent chromosome is selected.
while (firstIndex == secondIndex && uniqueParentAttempts > 0) {
// Select the index of the second parent chromosome.
secondIndex = _random.Next(0, nextParentChromosomes.Count);
// Reduce the number of attempts.
uniqueParentAttempts--;
}
// Get the first parent chromosome.
double[] firstParent = OptimizationVectorValues(nextParentChromosomes[firstIndex]);
// Get the second parent chromosome.
double[] secondParent = OptimizationVectorValues(nextParentChromosomes[secondIndex]);
// The child chromosome.
double[] child = new double[firstParent.Length];
// Create the child vector from the selected parents.
for (int i = 0; i < child.Length; i++) {
// Randomly select items from the parents.
if (_random.NextDouble() >= 0.5)
child[i] = firstParent[i];
else child[i] = secondParent[i];
}
// The number of attempts to find a unique vector.
int attempts = 10000;
// Set the allowed mutations.
int allowedMutations = _mutations;
// Iterate until there are enough chromosomes in the new generation or there are no more attempts to create a unique vector.
while (newChromosomes.Count < _chromosomes && attempts > 0) {
// Create for holding the optimization vectors which match the child, given the number of allowed mutations.
List<int> childMatches = new List<int>();
// Iterate over the optimization vectors while searching for those that match the child, given the number of allowed mutations.
for (int i = 0; i < OptimizationVectorCount(); i++) {
// Check whether the vector hasn't yet been processed.
if (!OptimizationVectorIsProcessed(i)) {
// Get the values of the current vector.
double[] currentValues = OptimizationVectorValues(i);
// Use for counting the number of differences between the current optimization vector and the child.
int differences = 0;
// Iterate over the current vector values.
for (int j = 0; j < currentValues.Length; j++) {
// Check whether the current optimization vector has an items which is different than the child.
if (currentValues[j] != child[j])
differences++;
}
// Check whether the number of differences is less that the mutations allowed.
if (differences <= allowedMutations)
// Add the optimization vector as a possible child.
childMatches.Add(i);
}
}
// Check whether child matches were found.
if (childMatches.Count > 0) {
// Get a random child.
int index = _random.Next(0, childMatches.Count);
// Iterate until a unique child is selected.
while (exists.ContainsKey(childMatches[index]) && attempts > 0) {
// Get a random child.
index = _random.Next(0, childMatches.Count);
// Reduce the number of attempts.
attempts--;
}
// Check whether the vector hasn't been selected for this generation..
if (!exists.ContainsKey(childMatches[index])) {
// Add the optimization vector.
exists.Add(childMatches[index], true);
// Add the child to the new chromosomes list.
newChromosomes.Add(childMatches[index]);
}
}
// Increase the allowed mutations, since a match wasn't found.
else allowedMutations++;
// Reduce the number of attempts.
attempts--;
}
}
// Clear the chromosomes in the current generation.
_currentGeneration.Clear();
// Return the new chromosomes.
return newChromosomes.ToArray();
}
#endregion
#region OnGetMaxVectors
/// <summary>
/// This function is called to get the number of optimization vectors that the algorithm will
/// select and run if the optimization process runs to completion.
/// </summary>
/// <returns type="Integer">The maximum number of optimization vectors to be run.</returns>
public override int OnGetMaxVectors()
{
// Calculate the maximum number of vectors to calculate.
int maxVectors = _generations * _chromosomes;
// Check whether the number of vectors to run is less than the number of existing vectors.
if (maxVectors <= OptimizationVectorCount())
return maxVectors;
else return OptimizationVectorCount();
}
#endregion
#region OnUpdateOptimizationVector
/// <summary>
/// This function is called to notify the optimization algorithm that a vector has been processed.
/// </summary>
/// <param name="vectorIndex" type="Integer">The vector index of the optimization vector that has been processed</param>
public override void OnUpdateOptimizationVector(int vectorIndex)
{
// Check whether the current generation has too many chromosomes.
if (_currentGeneration.Count == _chromosomes)
_currentGeneration.Clear();
// Check whether the current generation can be added a vector.
if (_currentGeneration.Count < _chromosomes) {
// Add the specified vector to the generation.
_currentGeneration.Add(vectorIndex);
}
}
#endregion
#region OnShutdown
/// <summary>
/// This function is called when the script is shutdown.
/// </summary>
public override void OnShutdown()
{
// OnShutdown Content
}
#endregion
}
}