#region License Information /* HeuristicLab * Copyright (C) 2002-2010 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.Algorithms.GeneticAlgorithm; using HeuristicLab.Collections; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.PluginInfrastructure; using HeuristicLab.Problems.DataAnalysis; using HeuristicLab.Problems.TestFunctions; using HEAL.Attic; namespace HeuristicLab.Problems.MetaOptimization { [Item("Meta Optimization Problem", "Represents a Meta Optimization Problem.")] [Creatable("Problems")] [StorableType("C30ECB0D-AF79-4C52-B00E-C5A5FDB71B0C")] public sealed class MetaOptimizationProblem : SingleObjectiveHeuristicOptimizationProblem, IStorableContent { public string Filename { get; set; } public const string AlgorithmTypeParameterName = "AlgorithmType"; public const string ProblemTypeParameterName = "ProblemType"; public const string ProblemsParameterName = "Problems"; public const string ParameterConfigurationTreeParameterName = "ParameterConfiguration"; public const string RepetitionsParameterName = "Repetitions"; public const string QualityMeasureNameName = "QualityMeasureName"; public const string IntValueManipulatorParameterName = "IntValueManipulator"; public const string DoubleValueManipulatorParameterName = "DoubleValueManipulator"; public const string IntValueCrossoverParameterName = "IntValueCrossover"; public const string DoubleValueCrossoverParameterName = "DoubleValueCrossover"; public const string QualityWeightParameterName = "QualityWeight"; public const string StandardDeviationWeightParameterName = "StandardDeviationWeight"; public const string EvaluatedSolutionsWeightParameterName = "EvaluatedSolutionsWeight"; #region Parameter Properties public IValueParameter> AlgorithmTypeParameter { get { return (ValueParameter>)Parameters[AlgorithmTypeParameterName]; } } public IValueParameter> ProblemTypeParameter { get { return (ValueParameter>)Parameters[ProblemTypeParameterName]; } } public IValueParameter> ProblemsParameter { get { return (ValueParameter>)Parameters[ProblemsParameterName]; } } public IValueParameter ParameterConfigurationTreeParameter { get { return (OptionalValueParameter)Parameters[ParameterConfigurationTreeParameterName]; } } public IValueParameter RepetitionsParameter { get { return (ValueParameter)Parameters[RepetitionsParameterName]; } } public IConstrainedValueParameter IntValueManipulatorParameter { get { return (ConstrainedValueParameter)Parameters[IntValueManipulatorParameterName]; } } public IConstrainedValueParameter DoubleValueManipulatorParameter { get { return (ConstrainedValueParameter)Parameters[DoubleValueManipulatorParameterName]; } } public IValueParameter QualityMeasureNameParameter { get { return (ValueParameter)Parameters[QualityMeasureNameName]; } } public IConstrainedValueParameter IntValueCrossoverParameter { get { return (ConstrainedValueParameter)Parameters[IntValueCrossoverParameterName]; } } public IConstrainedValueParameter DoubleValueCrossoverParameter { get { return (ConstrainedValueParameter)Parameters[DoubleValueCrossoverParameterName]; } } #endregion #region Properties public IAlgorithm Algorithm { get { return CreateAlgorithm(AlgorithmType.Value, Problems.FirstOrDefault()); } } public ConstrainedTypeValue AlgorithmType { get { return AlgorithmTypeParameter.Value; } set { AlgorithmTypeParameter.Value = value; } } public ConstrainedTypeValue ProblemType { get { return ProblemTypeParameter.Value; } set { ProblemTypeParameter.Value = value; } } public ConstrainedItemList Problems { get { return ProblemsParameter.Value; } set { ProblemsParameter.Value = value; } } public ParameterConfigurationTree ParameterConfigurationTree { get { return ParameterConfigurationTreeParameter.Value; } set { ParameterConfigurationTreeParameter.Value = value; } } public IntValue Repetitions { get { return RepetitionsParameter.Value; } set { RepetitionsParameter.Value = value; } } private BestParameterConfigurationAnalyzer BestParameterConfigurationAnalyzer { get { return Operators.OfType().FirstOrDefault(); } } private ReferenceQualityAnalyzer ReferenceQualityAnalyzer { get { return Operators.OfType().FirstOrDefault(); } } private SolutionCacheAnalyzer RunsAnalyzer { get { return Operators.OfType().FirstOrDefault(); } } private PMOPopulationDiversityAnalyzer PMOPopulationDiversityAnalyzer { get { return Operators.OfType().FirstOrDefault(); } } private PMOProblemQualitiesAnalyzer PMOProblemQualitiesAnalyzer { get { return Operators.OfType().FirstOrDefault(); } } private PMOBestSolutionHistoryAnalyzer PMOBestSolutionHistoryAnalyzer { get { return Operators.OfType().FirstOrDefault(); } } #endregion public MetaOptimizationProblem() : base() { Parameters.Add(new ValueParameter>(AlgorithmTypeParameterName, "The algorithm which's parameters should be optimized.", new ConstrainedTypeValue(typeof(GeneticAlgorithm)))); Parameters.Add(new ValueParameter>(ProblemTypeParameterName, "The problem type.", new ConstrainedTypeValue())); Parameters.Add(new ValueParameter>(ProblemsParameterName, "The problems that should be evaluated.", new ConstrainedItemList())); Parameters.Add(new OptionalValueParameter(ParameterConfigurationTreeParameterName, "Tree of algorithm parameters that should be optimized.")); // needs to be optional, when last problem is removed from list, it must be set null Parameters.Add(new ValueParameter(RepetitionsParameterName, "The number of evaluations for each problem.", new IntValue(3))); Parameters.Add(new ValueParameter(QualityMeasureNameName, "The name of the quality result of the base-level algorithm. Subresults can be accessed by dot separator.", new StringValue("BestQuality"))); var validIntManipulators = new ItemSet(ApplicationManager.Manager.GetInstances()); var validDoubleManipulators = new ItemSet(ApplicationManager.Manager.GetInstances()); var validIntCrossovers = new ItemSet(ApplicationManager.Manager.GetInstances()); var validDoubleCrossovers = new ItemSet(ApplicationManager.Manager.GetInstances()); Parameters.Add(new ConstrainedValueParameter(IntValueManipulatorParameterName, validIntManipulators, validIntManipulators.Where(x => x.GetType() == typeof(NormalIntValueManipulator)).SingleOrDefault())); Parameters.Add(new ConstrainedValueParameter(DoubleValueManipulatorParameterName, validDoubleManipulators, validDoubleManipulators.Where(x => x.GetType() == typeof(NormalDoubleValueManipulator)).SingleOrDefault())); Parameters.Add(new ConstrainedValueParameter(IntValueCrossoverParameterName, validIntCrossovers, validIntCrossovers.Where(x => x.GetType() == typeof(NormalIntValueCrossover)).SingleOrDefault())); Parameters.Add(new ConstrainedValueParameter(DoubleValueCrossoverParameterName, validDoubleCrossovers, validDoubleCrossovers.Where(x => x.GetType() == typeof(NormalDoubleValueCrossover)).SingleOrDefault())); Parameters.Add(new ValueParameter(QualityWeightParameterName, new DoubleValue(1))); Parameters.Add(new ValueParameter(StandardDeviationWeightParameterName, new DoubleValue(0.01))); Parameters.Add(new ValueParameter(EvaluatedSolutionsWeightParameterName, new DoubleValue(0.0005))); Maximization = new BoolValue(false); SolutionCreator = new RandomParameterConfigurationCreator(); Evaluator = new PMOEvaluator(); InitializeOperators(); RegisterParameterEvents(); ParameterizeAnalyzer(); ParameterizeSolutionCreator(); ParameterizeEvaluator(); ParameterizeOperators(); AlgorithmTypeParameter_ValueChanged(this, EventArgs.Empty); } [StorableConstructor] private MetaOptimizationProblem(StorableConstructorFlag _) : base(_) { } private MetaOptimizationProblem(MetaOptimizationProblem original, Cloner cloner) : base(original, cloner) { this.RegisterParameterEvents(); } public override IDeepCloneable Clone(Cloner cloner) { return new MetaOptimizationProblem(this, cloner); } #region Helpers [StorableHook(HookType.AfterDeserialization)] private void AfterDeserializationHook() { if (!Parameters.ContainsKey(QualityMeasureNameName)) Parameters.Add(new ValueParameter(QualityMeasureNameName, "The name of the quality result of the base-level algorithm. Subresults can be accessed by dot separator.", new StringValue("BestQuality"))); // backwards compatibility RegisterParameterEvents(); } private void RegisterParameterEvents() { SolutionCreatorParameter.ValueChanged += new EventHandler(SolutionCreatorParameter_ValueChanged); EvaluatorParameter.ValueChanged += new EventHandler(EvaluatorParameter_ValueChanged); Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged); AlgorithmTypeParameter.ValueChanged += new EventHandler(AlgorithmTypeParameter_ValueChanged); AlgorithmType.ValueChanged += new EventHandler(AlgorithmType_ValueChanged); ProblemTypeParameter.ValueChanged += new EventHandler(ProblemTypeParameter_ValueChanged); ProblemType.ValueChanged += new EventHandler(ProblemType_ValueChanged); Problems.ItemsAdded += new Collections.CollectionItemsChangedEventHandler>(Problems_ItemsAdded); Problems.ItemsRemoved += new Collections.CollectionItemsChangedEventHandler>(Problems_ItemsRemoved); } private void InitializeOperators() { Operators.AddRange(ApplicationManager.Manager.GetInstances().Cast()); Operators.Add(new ReferenceQualityAnalyzer()); Operators.Add(new BestParameterConfigurationAnalyzer()); Operators.Add(new SolutionCacheAnalyzer()); Operators.Add(new PMOPopulationDiversityAnalyzer()); Operators.Add(new PMOProblemQualitiesAnalyzer()); Operators.Add(new PMOBestSolutionHistoryAnalyzer()); } private void ParameterizeSolutionCreator() { } private void ParameterizeEvaluator() { ((PMOEvaluator)Evaluator).ParameterConfigurationParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } private void ParameterizeAnalyzer() { if (BestParameterConfigurationAnalyzer != null) { BestParameterConfigurationAnalyzer.ParameterConfigurationParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } if (ReferenceQualityAnalyzer != null) { ReferenceQualityAnalyzer.ParameterConfigurationParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } if (RunsAnalyzer != null) { RunsAnalyzer.ParameterConfigurationParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } if (PMOPopulationDiversityAnalyzer != null) { PMOPopulationDiversityAnalyzer.SolutionParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; PMOPopulationDiversityAnalyzer.StoreHistoryParameter.Value.Value = true; } if (PMOProblemQualitiesAnalyzer != null) { PMOProblemQualitiesAnalyzer.ParameterConfigurationParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } if (PMOBestSolutionHistoryAnalyzer != null) { PMOBestSolutionHistoryAnalyzer.ParameterConfigurationParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } } private void ParameterizeOperators() { foreach (IParameterConfigurationCrossover op in Operators.OfType()) { op.ParentsParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; op.ChildParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } foreach (IParameterConfigurationManipulator op in Operators.OfType()) { op.ParameterConfigurationTreeParameter.ActualName = ((RandomParameterConfigurationCreator)SolutionCreator).ParameterConfigurationParameter.ActualName; } } #endregion #region Events private void SolutionCreatorParameter_ValueChanged(object sender, EventArgs e) { ParameterizeSolutionCreator(); ParameterizeEvaluator(); ParameterizeAnalyzer(); ParameterizeOperators(); OnSolutionCreatorChanged(); } private void EvaluatorParameter_ValueChanged(object sender, EventArgs e) { Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged); ParameterizeEvaluator(); ParameterizeAnalyzer(); OnEvaluatorChanged(); } private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) { ParameterizeAnalyzer(); } private void AlgorithmTypeParameter_ValueChanged(object sender, EventArgs e) { AlgorithmType_ValueChanged(sender, e); } private void AlgorithmType_ValueChanged(object sender, EventArgs e) { IAlgorithm instance = (IAlgorithm)Activator.CreateInstance(AlgorithmType.Value); this.ProblemType.ValidTypes = ApplicationManager.Manager.GetTypes(instance.ProblemType, true).ToList(); var newProblemType = this.ProblemType.ValidTypes.SingleOrDefault(t => t == typeof(SingleObjectiveTestFunctionProblem)) ?? this.ProblemType.ValidTypes.Where(t => t != typeof(MetaOptimizationProblem)).FirstOrDefault(); if (this.ProblemType.Value != newProblemType) this.ProblemType.Value = newProblemType; // ProblemType_ValueChanged will add one problem and create ParameterConfigurationTree else ProblemType_ValueChanged(this, EventArgs.Empty); // call explicitly } private void ProblemTypeParameter_ValueChanged(object sender, EventArgs e) { ProblemType_ValueChanged(sender, e); } private void ProblemType_ValueChanged(object sender, EventArgs e) { Problems.Clear(); Problems.Type = ProblemType.Value; Problems.Add((IProblem)Activator.CreateInstance(this.ProblemType.Value)); } private void Problems_ItemsAdded(object sender, CollectionItemsChangedEventArgs> e) { // the first problem in the list is always the instance for the algorithm - this way some basic wiring between problem and algorithm can be sustained if (e.Items.Single().Index == 0) { ParameterConfigurationTreeParameter.ActualValue = new ParameterConfigurationTree(CreateAlgorithm(AlgorithmType.Value, e.Items.Single().Value), e.Items.Single().Value); // special for DataAnalysisProblem: Because of wiring between algorithm and problem, ParameterConfigurationTree needs to be recreated on Reset event var dap = e.Items.Single().Value as IDataAnalysisProblem; if (dap != null) { dap.Reset += new EventHandler(DataAnalysisProblem_Reset); } } } private void Problems_ItemsRemoved(object sender, CollectionItemsChangedEventArgs> e) { if (e.Items.Single().Index == 0) { ParameterConfigurationTreeParameter.ActualValue = null; var dap = e.Items.Single().Value as IDataAnalysisProblem; if (dap != null) { dap.Reset -= new EventHandler(DataAnalysisProblem_Reset); } } } private void DataAnalysisProblem_Reset(object sender, EventArgs e) { ParameterConfigurationTreeParameter.ActualValue = new ParameterConfigurationTree(CreateAlgorithm(AlgorithmType.Value, Problems.First()), Problems.First()); } #endregion private IAlgorithm CreateAlgorithm(Type algorithmType, IProblem problem) { IAlgorithm algorithm = (IAlgorithm)Activator.CreateInstance(algorithmType); algorithm.Problem = problem; return algorithm; } public void ImportAlgorithm(IAlgorithm algorithm) { AlgorithmType.Value = algorithm.GetType(); if (algorithm.Problem != null) ProblemType.Value = algorithm.Problem.GetType(); if (algorithm.Problem != null) { Problems.Clear(); Problems.Add((IProblem)algorithm.Problem); } ParameterConfigurationTreeParameter.ActualValue = new ParameterConfigurationTree(algorithm, Problems.First()); } } }