#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 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 System.Collections.Generic;
using System.Linq;
using HeuristicLab.Algorithms.GeneticAlgorithm;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Operators;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Problems.DataAnalysis.Symbolic;
namespace HeuristicLab.Algorithms.DataAnalysis.Symbolic {
[Item("Symbolic Data Analysis Island Genetic Algorithm", "A symbolic data analysis island genetic algorithm.")]
[Creatable("Data Analysis")]
[StorableClass]
public sealed class SymbolicDataAnalysisIslandGeneticAlgorithm : IslandGeneticAlgorithm {
private const string FixedSamplesParameterName = "NumberOfFixedSamples";
private const string FixedSamplesPartitionParameterName = "FixedSamplesPartition";
private const string FixedSamplesPartitionsParameterName = "FixedSamplesPartitions";
private const string EvaluatorParameterName = "IslandEvaluator";
private const string IslandIndexParameterName = "IslandIndex";
private const string ProblemEvaluatorParameterName = "ProblemEvaluator";
#region Problem Properties
public override Type ProblemType {
get { return typeof(ISymbolicDataAnalysisSingleObjectiveProblem); }
}
public new ISymbolicDataAnalysisSingleObjectiveProblem Problem {
get { return (ISymbolicDataAnalysisSingleObjectiveProblem)base.Problem; }
set { base.Problem = value; }
}
#endregion
#region parameters
public IFixedValueParameter FixedSamplesParameter {
get { return (IFixedValueParameter)Parameters[FixedSamplesParameterName]; }
}
public IValueParameter> FixedSamplesPartitionsParameter {
get { return (IValueParameter>)Parameters[FixedSamplesPartitionsParameterName]; }
}
public IValueParameter EvaluatorParameter {
get { return (IValueParameter)Parameters[EvaluatorParameterName]; }
}
private ILookupParameter ProblemEvaluatorParameter {
get { return (ILookupParameter)Parameters[ProblemEvaluatorParameterName]; }
}
#endregion
#region properties
public double FixedSamples {
get { return FixedSamplesParameter.Value.Value; }
set { FixedSamplesParameter.Value.Value = value; }
}
public ItemArray FixedSamplesPartitions {
get { return FixedSamplesPartitionsParameter.Value; }
set { FixedSamplesPartitionsParameter.Value = value; }
}
private readonly ScopeTreeAssigner islandIndexAssigner;
#endregion
[StorableConstructor]
private SymbolicDataAnalysisIslandGeneticAlgorithm(bool deserializing) : base(deserializing) { }
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
RegisterParameterEvents();
}
private SymbolicDataAnalysisIslandGeneticAlgorithm(SymbolicDataAnalysisIslandGeneticAlgorithm original, Cloner cloner)
: base(original, cloner) {
RegisterParameterEvents();
}
public override IDeepCloneable Clone(Cloner cloner) {
return new SymbolicDataAnalysisIslandGeneticAlgorithm(this, cloner);
}
public SymbolicDataAnalysisIslandGeneticAlgorithm()
: base() {
Parameters.Add(new FixedValueParameter(FixedSamplesParameterName, "The number of fixed samples used for fitness calculation in each island.", new PercentValue(0.2)));
Parameters.Add(new ValueParameter>(FixedSamplesPartitionsParameterName, "The fixed samples partitions used for fitness calculation for every island."));
Parameters.Add(new OptionalValueParameter(EvaluatorParameterName, "The evaluator of the algorithm."));
Parameters.Add(new LookupParameter(ProblemEvaluatorParameterName, "Internal parameter for name translation", "Evaluator"));
islandIndexAssigner = new ScopeTreeAssigner();
islandIndexAssigner.Name = "Insert island index";
islandIndexAssigner.LeftSideParameter.ActualName = IslandIndexParameterName;
var readonlyIslandIndexes = Enumerable.Range(0, NumberOfIslands.Value).Select(x => (IntValue)new IntValue(x).AsReadOnly());
islandIndexAssigner.RightSideParameter.Value = new ItemArray(readonlyIslandIndexes);
ScopeTreeAssigner fixedSamplesPartitionCreator = new ScopeTreeAssigner();
fixedSamplesPartitionCreator.Name = "Create fixed evaluation partition";
fixedSamplesPartitionCreator.LeftSideParameter.ActualName = FixedSamplesPartitionParameterName;
fixedSamplesPartitionCreator.RightSideParameter.ActualName = FixedSamplesPartitionsParameterName;
SubScopesCreator insertionPoint = OperatorGraph.Iterate().OfType().First();
islandIndexAssigner.Successor = fixedSamplesPartitionCreator;
fixedSamplesPartitionCreator.Successor = insertionPoint.Successor;
insertionPoint.Successor = islandIndexAssigner;
ReevaluateImmigrants = true;
ReevaluteElites = true;
RegisterParameterEvents();
RecalculateFixedSamplesPartitions();
}
private void RegisterParameterEvents() {
if (Problem != null) Problem.FitnessCalculationPartition.ValueChanged += Problem_Reset;
NumberOfIslandsParameter.ValueChanged += NumberOfIslandsParameter_ValueChanged;
NumberOfIslandsParameter.Value.ValueChanged += (o, ev) => NumberOfIslandsParameterValue_Changed();
FixedSamplesParameter.Value.ValueChanged += (o, e) => {
RecalculateFixedSamplesPartitions();
ReevaluateImmigrants = FixedSamples < Problem.FitnessCalculationPartition.Size;
};
Analyzer.Operators.PropertyChanged += (o, e) => ParameterizeAnalyzers();
EvaluatorParameter.ValueChanged += (o, e) => ParameterizeEvaluator();
}
protected override void ParameterizeSolutionsCreator() {
base.ParameterizeSolutionsCreator();
SolutionsCreator.EvaluatorParameter.ActualName = EvaluatorParameterName;
}
protected override void ParameterizeMainLoop() {
base.ParameterizeMainLoop();
MainLoop.EvaluatorParameter.ActualName = EvaluatorParameterName;
MainLoop.QualityParameter.ActualName = EvaluatorParameter.Value.QualityParameter.ActualName;
}
protected override void ParameterizeAnalyzers() {
base.ParameterizeAnalyzers();
foreach (var analyzer in Analyzer.Operators.OfType()) {
IParameter evaluatorParameter;
if (analyzer.Parameters.TryGetValue("Evaluator", out evaluatorParameter)) {
ILookupParameter param = evaluatorParameter as ILookupParameter;
if (evaluatorParameter != null) param.ActualName = ProblemEvaluatorParameterName;
}
}
}
private void ParameterizeEvaluator() {
var evaluator = EvaluatorParameter.Value;
evaluator.IterationsParameter.ActualName = "Generations";
evaluator.MaximumIterationsParameter.ActualName = MaximumGenerationsParameter.Name;
evaluator.DataMigrationIntervalParameter.ActualName = MigrationIntervalParameter.Name;
ParameterizeStochasticOperatorForIsland(evaluator);
}
private void NumberOfIslandsParameter_ValueChanged(object sender, EventArgs e) {
NumberOfIslands.ValueChanged += (o, ev) => NumberOfIslandsParameterValue_Changed();
NumberOfIslandsParameterValue_Changed();
}
private void NumberOfIslandsParameterValue_Changed() {
var readonlyIslandIndexes = Enumerable.Range(0, NumberOfIslands.Value).Select(x => (IntValue)new IntValue(x).AsReadOnly());
islandIndexAssigner.RightSideParameter.Value = new ItemArray(readonlyIslandIndexes);
RecalculateFixedSamplesPartitions();
}
protected override void Problem_Reset(object sender, EventArgs e) {
base.Problem_Reset(sender, e);
RecalculateFixedSamplesPartitions();
}
protected override void OnProblemChanged() {
Problem.FitnessCalculationPartition.ValueChanged += Problem_Reset;
if (Problem != null && EvaluatorParameter.Value == null) {
EvaluatorParameter.Value = new RandomSamplesEvaluator();
} else if (Problem == null)
EvaluatorParameter.Value = null;
ParameterizeStochasticOperator(EvaluatorParameter.Value);
RecalculateFixedSamplesPartitions();
base.OnProblemChanged();
}
private void RecalculateFixedSamplesPartitions() {
if (Problem == null) {
FixedSamplesPartitions = new ItemArray(Enumerable.Repeat(new IntRange(), NumberOfIslands.Value));
return;
}
var samplesStart = Problem.FitnessCalculationPartition.Start;
var samplesEnd = Problem.FitnessCalculationPartition.End;
var totalSamples = Problem.FitnessCalculationPartition.Size;
var fixedSamples = (int)(FixedSamples * totalSamples);
var islands = NumberOfIslands.Value;
double shift = (double)((totalSamples - fixedSamples)) / (islands - 1);
int offset = (int)Math.Floor(shift);
double remainder = shift - offset;
List partitions = new List();
for (int i = 0; i < islands; i++) {
var partitionStart = samplesStart + offset * i + (int)(remainder * i);
partitions.Add(new IntRange(partitionStart, partitionStart + fixedSamples));
}
//if the last partitions exceeds the allowed samples move the last partition forward.
int exceedsSamples = partitions[partitions.Count - 1].End - samplesEnd;
if (exceedsSamples > 0) {
partitions[partitions.Count - 1].Start -= exceedsSamples;
partitions[partitions.Count - 1].End -= exceedsSamples;
}
FixedSamplesPartitions = new ItemArray(partitions);
}
}
}