using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Optimization; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.MetaOptimization { // todo: storable, name, descr, ... [StorableClass] public class ParameterConfigurationTree : ParameterizedValueConfiguration, IEnumerable { [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 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; this.parameterConfigurations.Add(new SingleValuedParameterConfiguration("Algorithm", algproblemitem.AlgorithmParameter)); this.parameterConfigurations.Add(new SingleValuedParameterConfiguration("Problem", algproblemitem.ProblemParameter)); // 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; } [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 override IDeepCloneable Clone(Cloner cloner) { return new ParameterConfigurationTree(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (ProblemConfiguration != null) ProblemConfiguration.ValuesReadOnly = true; } #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(); } #endregion public override void Parameterize(IParameterizedItem item) { this.parameters.Clear(); var algorithm = item as IAlgorithm; var problem = algorithm.Problem; ProblemConfiguration.Parameterize(problem); AlgorithmConfiguration.Parameterize(algorithm); algorithm.CollectParameterValues(this.Parameters); } public Experiment GenerateExperiment(IAlgorithm algorithm, bool createBatchRuns, int repetitions) { Experiment experiment = new Experiment(); foreach (ParameterizedValueConfiguration combination in this) { IAlgorithm clonedAlg = (IAlgorithm)algorithm.Clone(); clonedAlg.Name = combination.ParameterInfoString; combination.Parameterize(clonedAlg); clonedAlg.StoreAlgorithmInEachRun = false; if (createBatchRuns) { BatchRun batchRun = new BatchRun(string.Format("BatchRun: {0}", combination.ParameterInfoString)); batchRun.Optimizer = clonedAlg; batchRun.Repetitions = repetitions; experiment.Optimizers.Add(batchRun); } else { experiment.Optimizers.Add(clonedAlg); } } return experiment; } public Experiment GenerateExperiment(IAlgorithm algorithm) { return GenerateExperiment(algorithm, false, 0); } 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) MetaOptimizationUtil.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); } } }