#region License Information
/* HeuristicLab
* Copyright (C) 2002-2013 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.Linq;
using HeuristicLab.Collections;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
using HeuristicLab.Operators;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.PluginInfrastructure;
namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[StorableClass]
[Item("MultiSymbolicDataAnalysisExpressionCrossover", "Randomly selects and applies one of its crossovers every time it is called.")]
public class MultiSymbolicDataAnalysisExpressionCrossover : StochasticMultiBranch, ITracingSymbolicExpressionTreeOperator,
ISymbolicDataAnalysisExpressionCrossover where T : class, IDataAnalysisProblemData {
private const string ParentsParameterName = "Parents";
private const string ChildParameterName = "Child";
private const string MaximumSymbolicExpressionTreeLengthParameterName = "MaximumSymbolicExpressionTreeLength";
private const string MaximumSymbolicExpressionTreeDepthParameterName = "MaximumSymbolicExpressionTreeDepth";
private const string SymbolicDataAnalysisTreeInterpreterParameterName = "SymbolicExpressionTreeInterpreter";
private const string EvaluatorParameterName = "Evaluator";
private const string SymbolicDataAnalysisEvaluationPartitionParameterName = "EvaluationPartition";
private const string RelativeNumberOfEvaluatedSamplesParameterName = "RelativeNumberOfEvaluatedSamples";
private const string ProblemDataParameterName = "ProblemData";
private const string SymbolicExpressionTreeNodeComparerParameterName = "SymbolicExpressionTreeNodeComparer";
private const string SymbolicExpressionTreeNodeComparerParameterDescription = "The comparison operator used to check if two symbolic expression tree nodes are equal or similar.";
protected override bool CreateChildOperation {
get { return true; }
}
public override bool CanChangeName {
get { return false; }
}
#region parameter properties
public ILookupParameter SymbolicDataAnalysisTreeInterpreterParameter {
get { return (ILookupParameter)Parameters[SymbolicDataAnalysisTreeInterpreterParameterName]; }
}
public ILookupParameter> ParentsParameter {
get { return (ScopeTreeLookupParameter)Parameters[ParentsParameterName]; }
}
public ILookupParameter ChildParameter {
get { return (ILookupParameter)Parameters[ChildParameterName]; }
}
public IValueLookupParameter MaximumSymbolicExpressionTreeLengthParameter {
get { return (IValueLookupParameter)Parameters[MaximumSymbolicExpressionTreeLengthParameterName]; }
}
public IValueLookupParameter MaximumSymbolicExpressionTreeDepthParameter {
get { return (IValueLookupParameter)Parameters[MaximumSymbolicExpressionTreeDepthParameterName]; }
}
public ILookupParameter> EvaluatorParameter {
get { return (ILookupParameter>)Parameters[EvaluatorParameterName]; }
}
public IValueLookupParameter EvaluationPartitionParameter {
get { return (IValueLookupParameter)Parameters[SymbolicDataAnalysisEvaluationPartitionParameterName]; }
}
public IValueLookupParameter RelativeNumberOfEvaluatedSamplesParameter {
get { return (IValueLookupParameter)Parameters[RelativeNumberOfEvaluatedSamplesParameterName]; }
}
public IValueLookupParameter ProblemDataParameter {
get { return (IValueLookupParameter)Parameters[ProblemDataParameterName]; }
}
public ValueParameter SymbolicExpressionTreeNodeComparerParameter {
get { return (ValueParameter)Parameters[SymbolicExpressionTreeNodeComparerParameterName]; }
}
#endregion
#region Properties
public ISymbolicExpressionTreeNodeComparer SymbolicExpressionTreeNodeComparer {
get { return (ISymbolicExpressionTreeNodeComparer)SymbolicExpressionTreeNodeComparerParameter.ActualValue; }
}
#endregion
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
if (!Parameters.ContainsKey(SymbolicExpressionTreeNodeComparerParameterName))
Parameters.Add(new ValueParameter(SymbolicExpressionTreeNodeComparerParameterName, SymbolicExpressionTreeNodeComparerParameterDescription));
}
[StorableConstructor]
protected MultiSymbolicDataAnalysisExpressionCrossover(bool deserializing) : base(deserializing) { }
protected MultiSymbolicDataAnalysisExpressionCrossover(MultiSymbolicDataAnalysisExpressionCrossover original, Cloner cloner) : base(original, cloner) { }
public override IDeepCloneable Clone(Cloner cloner) { return new MultiSymbolicDataAnalysisExpressionCrossover(this, cloner); }
public MultiSymbolicDataAnalysisExpressionCrossover()
: base() {
Parameters.Add(new ValueLookupParameter(RelativeNumberOfEvaluatedSamplesParameterName, "The relative number of samples of the dataset partition, which should be randomly chosen for evaluation between the start and end index."));
Parameters.Add(new ValueLookupParameter(ProblemDataParameterName, "The problem data on which the symbolic data analysis solution should be evaluated."));
Parameters.Add(new LookupParameter(SymbolicDataAnalysisTreeInterpreterParameterName, "The interpreter that should be used to calculate the output values of the symbolic data analysis tree."));
Parameters.Add(new ValueLookupParameter(MaximumSymbolicExpressionTreeLengthParameterName, "The maximal length (number of nodes) of the symbolic expression tree."));
Parameters.Add(new ValueLookupParameter(MaximumSymbolicExpressionTreeDepthParameterName, "The maximal depth of the symbolic expression tree (a tree with one node has depth = 0)."));
Parameters.Add(new LookupParameter>(EvaluatorParameterName, "The single objective solution evaluator"));
Parameters.Add(new ValueLookupParameter(SymbolicDataAnalysisEvaluationPartitionParameterName, "The start index of the dataset partition on which the symbolic data analysis solution should be evaluated."));
Parameters.Add(new ScopeTreeLookupParameter(ParentsParameterName, "The parent symbolic expression trees which should be crossed."));
Parameters.Add(new LookupParameter(ChildParameterName, "The child symbolic expression tree resulting from the crossover."));
Parameters.Add(new ValueParameter(SymbolicExpressionTreeNodeComparerParameterName, SymbolicExpressionTreeNodeComparerParameterDescription));
EvaluatorParameter.Hidden = true;
EvaluationPartitionParameter.Hidden = true;
SymbolicDataAnalysisTreeInterpreterParameter.Hidden = true;
ProblemDataParameter.Hidden = true;
RelativeNumberOfEvaluatedSamplesParameter.Hidden = true;
InitializeOperators();
name = "MultiSymbolicDataAnalysisExpressionCrossover";
}
private void InitializeOperators() {
var list = ApplicationManager.Manager.GetInstances().ToList();
var dataAnalysisCrossovers = from type in ApplicationManager.Manager.GetTypes(typeof(ISymbolicDataAnalysisExpressionCrossover))
where this.GetType().Assembly == type.Assembly
where !typeof(IMultiOperator).IsAssignableFrom(type)
select (ISymbolicDataAnalysisExpressionCrossover)Activator.CreateInstance(type);
list.AddRange(dataAnalysisCrossovers);
var checkedItemList = new CheckedItemList();
checkedItemList.AddRange(list.OrderBy(op => op.Name));
Operators = checkedItemList;
Operators_ItemsAdded(this, new CollectionItemsChangedEventArgs>(Operators.CheckedItems));
}
public ISymbolicExpressionTree Crossover(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1) {
double sum = Operators.CheckedItems.Sum(o => Probabilities[o.Index]);
if (sum.IsAlmost(0)) throw new InvalidOperationException(Name + ": All selected operators have zero probability.");
double r = random.NextDouble() * sum;
sum = 0;
int index = -1;
foreach (var indexedItem in Operators.CheckedItems) {
sum += Probabilities[indexedItem.Index];
if (sum > r) {
index = indexedItem.Index;
break;
}
}
return Operators[index].Crossover(random, parent0, parent1);
}
protected override void Operators_ItemsReplaced(object sender, CollectionItemsChangedEventArgs> e) {
base.Operators_ItemsReplaced(sender, e);
ParameterizeCrossovers();
}
protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs> e) {
base.Operators_ItemsAdded(sender, e);
ParameterizeCrossovers();
}
private void ParameterizeCrossovers() {
foreach (ISymbolicExpressionTreeCrossover op in Operators) {
op.ChildParameter.ActualName = ChildParameter.Name;
op.ParentsParameter.ActualName = ParentsParameter.Name;
}
foreach (IStochasticOperator op in Operators.OfType()) {
op.RandomParameter.ActualName = RandomParameter.Name;
}
foreach (ISymbolicExpressionTreeSizeConstraintOperator op in Operators.OfType()) {
op.MaximumSymbolicExpressionTreeDepthParameter.ActualName = MaximumSymbolicExpressionTreeDepthParameter.Name;
op.MaximumSymbolicExpressionTreeLengthParameter.ActualName = MaximumSymbolicExpressionTreeLengthParameter.Name;
}
foreach (ISymbolicDataAnalysisInterpreterOperator op in Operators.OfType()) {
op.SymbolicDataAnalysisTreeInterpreterParameter.ActualName = SymbolicDataAnalysisTreeInterpreterParameter.Name;
}
foreach (var op in Operators.OfType>()) {
op.ProblemDataParameter.ActualName = ProblemDataParameter.Name;
op.EvaluationPartitionParameter.ActualName = EvaluationPartitionParameter.Name;
op.RelativeNumberOfEvaluatedSamplesParameter.ActualName = RelativeNumberOfEvaluatedSamplesParameter.Name;
op.EvaluatorParameter.ActualName = EvaluatorParameter.Name;
}
var comparers = ApplicationManager.Manager.GetInstances();
foreach (var op in Operators.OfType()) {
op.SymbolicExpressionTreeNodeComparerParameter.ActualValue = comparers.First();
}
}
}
}