#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; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Problems.Instances; namespace HeuristicLab.Encodings.ParameterConfigurationEncoding { [Item("ParameterConfigurationTree", "Represents a parameter configuration.")] [StorableClass] public class ParameterConfigurationTree : ParameterizedValueConfiguration, IEnumerable { [Storable] private long combinationsCount; public long CombinationsCount { get { return combinationsCount; } private set { if (combinationsCount != value) { combinationsCount = value; OnCombinationsCountChanged(); } } } [Storable] private DoubleValue quality; public DoubleValue Quality { get { return quality; } set { if (quality != value) { quality = value; OnQualityChanged(); } } } [Storable] private DoubleArray normalizedQualityAverages; public DoubleArray NormalizedQualityAverages { get { return normalizedQualityAverages; } set { if (normalizedQualityAverages != value) { normalizedQualityAverages = value; } } } [Storable] private DoubleArray normalizedQualityDeviations; public DoubleArray NormalizedQualityDeviations { get { return normalizedQualityDeviations; } set { if (normalizedQualityDeviations != value) { normalizedQualityDeviations = value; } } } [Storable] private DoubleArray normalizedEvaluatedSolutions; public DoubleArray NormalizedEvaluatedSolutions { get { return normalizedEvaluatedSolutions; } set { if (normalizedEvaluatedSolutions != value) { normalizedEvaluatedSolutions = value; } } } [Storable] private DoubleArray bestQualities; public DoubleArray BestQualities { get { return bestQualities; } set { if (bestQualities != value) { bestQualities = value; } } } [Storable] private DoubleArray averageQualities; public DoubleArray AverageQualities { get { return averageQualities; } set { averageQualities = value; } } [Storable] private DoubleArray worstQualities; public DoubleArray WorstQualities { get { return worstQualities; } set { worstQualities = value; } } [Storable] private DoubleArray qualityVariances; public DoubleArray QualityVariances { get { return qualityVariances; } set { qualityVariances = value; } } [Storable] private DoubleArray qualityStandardDeviations; public DoubleArray QualityStandardDeviations { get { return qualityStandardDeviations; } set { qualityStandardDeviations = value; } } [Storable] private ItemList averageExecutionTimes; public ItemList AverageExecutionTimes { get { return averageExecutionTimes; } set { averageExecutionTimes = value; } } [Storable] private DoubleArray averageEvaluatedSolutions; public DoubleArray AverageEvaluatedSolutions { get { return averageEvaluatedSolutions; } set { averageEvaluatedSolutions = value; } } [Storable] private IntValue repetitions; public IntValue Repetitions { get { return repetitions; } set { repetitions = value; } } [Storable] protected RunCollection runs; public RunCollection Runs { get { return runs; } set { runs = value; } } [Storable] protected IDictionary parameters; public IDictionary Parameters { get { return parameters; } set { parameters = value; } } public ParameterizedValueConfiguration AlgorithmConfiguration { get { return this.ParameterConfigurations.ElementAt(0).ValueConfigurations.First() as ParameterizedValueConfiguration; } } public ParameterizedValueConfiguration ProblemConfiguration { get { return this.ParameterConfigurations.ElementAt(1).ValueConfigurations.First() as ParameterizedValueConfiguration; } } #region Constructors and Cloning [StorableConstructor] protected ParameterConfigurationTree(bool deserializing) : base(deserializing) { } protected ParameterConfigurationTree(ParameterConfigurationTree original, Cloner cloner) : base(original, cloner) { this.quality = cloner.Clone(original.quality); this.normalizedQualityAverages = cloner.Clone(original.normalizedQualityAverages); this.normalizedQualityDeviations = cloner.Clone(original.normalizedQualityDeviations); this.normalizedEvaluatedSolutions = cloner.Clone(original.normalizedEvaluatedSolutions); this.bestQualities = cloner.Clone(original.BestQualities); this.averageQualities = cloner.Clone(original.averageQualities); this.worstQualities = cloner.Clone(original.worstQualities); this.qualityStandardDeviations = cloner.Clone(original.qualityStandardDeviations); this.qualityVariances = cloner.Clone(original.qualityVariances); this.averageExecutionTimes = cloner.Clone(original.averageExecutionTimes); this.averageEvaluatedSolutions = cloner.Clone(original.averageEvaluatedSolutions); this.repetitions = cloner.Clone(original.repetitions); this.runs = cloner.Clone(original.runs); this.parameters = new Dictionary(); if (original.parameters != null) { foreach (var p in original.parameters) { this.parameters.Add(p.Key, cloner.Clone(p.Value)); } } } public ParameterConfigurationTree() : base() { } public ParameterConfigurationTree(IAlgorithm algorithm, IProblem problem) : base(null, algorithm.GetType(), false) { this.Optimize = false; this.IsOptimizable = false; this.parameters = new Dictionary(); this.Name = algorithm.ItemName; var algProblemItem = new AlgorithmProblemItem(); algProblemItem.AlgorithmParameter.Value = algorithm; algProblemItem.ProblemParameter.Value = problem; this.discoverValidValues = false; var algConfig = new SingleValuedParameterConfiguration("Algorithm", algProblemItem.AlgorithmParameter); var problemConfig = new SingleValuedParameterConfiguration("Problem", algProblemItem.ProblemParameter); algConfig.CombinationsCountChanged += new EventHandler(UpdateConfigurationsCount); problemConfig.CombinationsCountChanged += new EventHandler(UpdateConfigurationsCount); this.parameterConfigurations.Add(algConfig); this.parameterConfigurations.Add(problemConfig); // problems can be modified in the list of problem instances, so the parameters which are not Optimize=true, // must not be modifiable in the parameter configuration tree. otherwise the parameter values would be ambiguous ProblemConfiguration.ValuesReadOnly = true; CombinationsCount = GetCombinationCount(0); } public override IDeepCloneable Clone(Cloner cloner) { return new ParameterConfigurationTree(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (ProblemConfiguration != null) ProblemConfiguration.ValuesReadOnly = true; CombinationsCount = GetCombinationCount(0); } #endregion public virtual void CollectResultValues(IDictionary values) { values.Add("RunsAverageExecutionTimes", AverageExecutionTimes); values.Add("RunsAverageEvaluatedSolutions", AverageEvaluatedSolutions); values.Add("Repetitions", Repetitions); values.Add("RunsBestQualities", BestQualities); values.Add("RunsAverageQualities", AverageQualities); values.Add("RunsWorstQualities", WorstQualities); values.Add("RunsQualityVariances", QualityVariances); values.Add("RunsQualityStandardDeviations", QualityStandardDeviations); values.Add("QualitiesNormalized", NormalizedQualityAverages); values.Add("AverageQualityNormalized", Quality); values.Add("Runs", Runs); } public virtual void CollectParameterValues(IDictionary values) { foreach (var p in parameters) { values.Add(p); } } #region Events public event EventHandler QualityChanged; private void OnQualityChanged() { var handler = QualityChanged; if (handler != null) handler(this, EventArgs.Empty); } private void Quality_ValueChanged(object sender, EventArgs e) { OnQualityChanged(); } private void UpdateConfigurationsCount(object sender, EventArgs e) { CombinationsCount = GetCombinationCount(0); } #endregion public override void Parameterize(IParameterizedItem item) { this.parameters.Clear(); var algorithm = (IAlgorithm)item; var problem = algorithm.Problem; ProblemConfiguration.Parameterize(problem); AlgorithmConfiguration.Parameterize(algorithm); algorithm.CollectParameterValues(this.Parameters); } public IEnumerator GetEnumerator() { IEnumerator enumerator = new ParameterCombinationsEnumerator(this); enumerator.Reset(); return enumerator; } /// /// returns the number of possible parameter combinations /// /// algorithm stops counting when max is reached. zero for infinite counting /// public long GetCombinationCount(long max) { long cnt = 0; foreach (var c in this) { cnt++; if (max > 0 && cnt >= max) { return cnt; } } return cnt; } public IOptimizable GetRandomOptimizable(IRandom random) { List allOptimizables = GetAllOptimizables(); return allOptimizables[random.Next(allOptimizables.Count)]; } public override string ToString() { return this.Name; } public IRun ToRun(bool clearParameters) { return ToRun(this.ParameterInfoString, clearParameters); } public IRun ToRun(string name, bool clearParameters) { IRun run = new Run(); run.Name = name; this.CollectResultValues(run.Results); this.CollectParameterValues(run.Parameters); if (clearParameters) ClearParameters(run, this.GetOptimizedParameterNames()); return run; } public override string ParameterInfoString { get { string algorithmInfo = this.AlgorithmConfiguration.ParameterInfoString; string problemInfo = this.ProblemConfiguration.ParameterInfoString; var sb = new StringBuilder(); if (!string.IsNullOrEmpty(algorithmInfo)) { sb.Append("Algorithm ("); sb.Append(algorithmInfo); sb.Append(")"); } if (!string.IsNullOrEmpty(problemInfo)) { if (sb.Length > 0) sb.Append(", "); sb.Append("Problem( "); sb.Append(problemInfo); sb.Append(")"); } return sb.ToString(); } } public override void CollectOptimizedParameterNames(List parameterNames, string prefix) { AlgorithmConfiguration.CollectOptimizedParameterNames(parameterNames, string.Empty); ProblemConfiguration.CollectOptimizedParameterNames(parameterNames, string.Empty); } #region Helpers /// /// Removes those parameters from the run which are not declared in parametersToKeep /// private void ClearParameters(IRun run, IEnumerable parametersToKeep) { var parametersToRemove = new List(); foreach (var parameter in run.Parameters) { if (!parametersToKeep.Contains(parameter.Key)) parametersToRemove.Add(parameter.Key); } foreach (var parameter in parametersToRemove) run.Parameters.Remove(parameter); } #endregion } }