using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Problems.MetaOptimization { [Item("AlgorithmRunsAnalyzer", "")] [StorableClass] public class AlgorithmRunsAnalyzer : SingleSuccessorOperator { #region Parameter properties public ILookupParameter QualityParameter { get { return (ILookupParameter)Parameters["Quality"]; } } public LookupParameter GenerationsParameter { get { return (LookupParameter)Parameters["Generations"]; } } public LookupParameter RepetitionsParameter { get { return (LookupParameter)Parameters[MetaOptimizationProblem.RepetitionsParameterName]; } } public ILookupParameter ParameterConfigurationParameter { get { return (ILookupParameter)Parameters["ParameterConfigurationTree"]; } } public ILookupParameter> ProblemsParameter { get { return (ILookupParameter>)Parameters[MetaOptimizationProblem.ProblemsParameterName]; } } public LookupParameter ReferenceQualityAveragesParameter { get { return (LookupParameter)Parameters["ReferenceQualityAverages"]; } } public LookupParameter ReferenceQualityDeviationsParameter { get { return (LookupParameter)Parameters["ReferenceQualityDeviations"]; } } public LookupParameter ReferenceEvaluatedSolutionAveragesParameter { get { return (LookupParameter)Parameters["ReferenceEvaluatedSolutionAverages"]; } } public LookupParameter ResultsParameter { get { return (LookupParameter)Parameters["Results"]; } } public ScopeTreeLookupParameter AlgorithmParameter { get { return (ScopeTreeLookupParameter)Parameters["Algorithm"]; } } public ScopeTreeLookupParameter ProblemIndexParameter { get { return (ScopeTreeLookupParameter)Parameters["ProblemIndex"]; } } public ScopeTreeLookupParameter RepetitionIndexParameter { get { return (ScopeTreeLookupParameter)Parameters["RepetitionIndex"]; } } public LookupParameter MaximizationParameter { get { return (LookupParameter)Parameters["Maximization"]; } } public LookupParameter QualityWeightParameter { get { return (LookupParameter)Parameters[MetaOptimizationProblem.QualityWeightParameterName]; } } public LookupParameter StandardDeviationWeightParameter { get { return (LookupParameter)Parameters[MetaOptimizationProblem.StandardDeviationWeightParameterName]; } } public LookupParameter EvaluatedSolutionsWeightParameter { get { return (LookupParameter)Parameters[MetaOptimizationProblem.EvaluatedSolutionsWeightParameterName]; } } private ScopeParameter CurrentScopeParameter { get { return (ScopeParameter)Parameters["CurrentScope"]; } } public IScope CurrentScope { get { return CurrentScopeParameter.ActualValue; } } public LookupParameter QualityMeasureNameParameter { get { return (LookupParameter)Parameters[MetaOptimizationProblem.QualityMeasureNameName]; } } #endregion [StorableConstructor] protected AlgorithmRunsAnalyzer(bool deserializing) : base(deserializing) { } public AlgorithmRunsAnalyzer() : base() { Parameters.Add(new LookupParameter("Random", "The pseudo random number generator which should be used to initialize the new random permutation.")); Parameters.Add(new LookupParameter("Quality", "The evaluated quality of the ParameterVector.")); Parameters.Add(new LookupParameter("Generations", "")); Parameters.Add(new LookupParameter(MetaOptimizationProblem.RepetitionsParameterName, "Number of evaluations on one problem.")); Parameters.Add(new LookupParameter("ParameterConfigurationTree", "")); Parameters.Add(new LookupParameter>(MetaOptimizationProblem.ProblemsParameterName, "")); Parameters.Add(new LookupParameter("ReferenceQualityAverages", "")); Parameters.Add(new LookupParameter("ReferenceQualityDeviations", "")); Parameters.Add(new LookupParameter("ReferenceEvaluatedSolutionAverages", "")); Parameters.Add(new LookupParameter("Results", "")); Parameters.Add(new ScopeTreeLookupParameter("Algorithm", "The finished algorithms containing Runs.")); Parameters.Add(new ScopeTreeLookupParameter("ProblemIndex", "The index of the problem an algorithm was executed with.")); Parameters.Add(new ScopeTreeLookupParameter("RepetitionIndex", "The index of the repetition")); Parameters.Add(new LookupParameter("Maximization", "Set to false if the problem should be minimized.")); Parameters.Add(new LookupParameter(MetaOptimizationProblem.QualityWeightParameterName)); Parameters.Add(new LookupParameter(MetaOptimizationProblem.StandardDeviationWeightParameterName)); Parameters.Add(new LookupParameter(MetaOptimizationProblem.EvaluatedSolutionsWeightParameterName)); Parameters.Add(new LookupParameter(MetaOptimizationProblem.QualityMeasureNameName)); Parameters.Add(new ScopeParameter("CurrentScope", "The current scope whose sub-scopes represent the parents.")); } protected AlgorithmRunsAnalyzer(AlgorithmRunsAnalyzer original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new AlgorithmRunsAnalyzer(this, cloner); } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (!Parameters.ContainsKey("CurrentScope")) Parameters.Add(new ScopeParameter("CurrentScope", "The current scope whose sub-scopes represent the parents.")); // backwards compatibility if (!Parameters.ContainsKey(MetaOptimizationProblem.QualityMeasureNameName)) Parameters.Add(new LookupParameter(MetaOptimizationProblem.QualityMeasureNameName)); // backwards compatibility } public override IOperation Apply() { ParameterConfigurationTree parameterConfiguration = ParameterConfigurationParameter.ActualValue; ItemArray algorithms = AlgorithmParameter.ActualValue; ItemArray problemIndices = ProblemIndexParameter.ActualValue; ItemArray repetitionIndices = RepetitionIndexParameter.ActualValue; IEnumerable parameterNames = parameterConfiguration.GetOptimizedParameterNames(); IItemList problems = ProblemsParameter.ActualValue; bool maximization = MaximizationParameter.ActualValue.Value; int repetitions = RepetitionsParameter.ActualValue.Value; double qualityWeight = QualityWeightParameter.ActualValue.Value; double standardDeviationWeight = StandardDeviationWeightParameter.ActualValue.Value; double evaluatedSolutionsWeight = EvaluatedSolutionsWeightParameter.ActualValue.Value; string qualityMeasureName = QualityMeasureNameParameter.ActualValue.Value; var resultNames = new List { qualityMeasureName, "Execution Time", "EvaluatedSolutions" }; int currentGeneration = GenerationsParameter.ActualValue != null ? GenerationsParameter.ActualValue.Value : 0; double[] referenceQualityAverages; double[] referenceQualityDeviations; double[] referenceEvaluatedSolutionAverages; GetReferenceValues(problems.Count, out referenceQualityAverages, out referenceQualityDeviations, out referenceEvaluatedSolutionAverages); ResultCollection results = ResultsParameter.ActualValue; if (algorithms.All(x => x.Runs.Count == 1)) { var runs = new RunCollection(); var qualities = new double[problems.Count][]; var executionTimes = new TimeSpan[problems.Count][]; var evaluatedSolutions = new int[problems.Count][]; for (int i = 0; i < problems.Count; i++) { qualities[i] = new double[repetitions]; evaluatedSolutions[i] = new int[repetitions]; executionTimes[i] = new TimeSpan[repetitions]; } for (int i = 0; i < algorithms.Length; i++) { int problemIndex = problemIndices[i].Value; int repetitionIndex = repetitionIndices[i].Value; IRun run = (IRun)algorithms[i].Runs.Single().Clone(); MetaOptimizationUtil.ClearResults(run, resultNames); MetaOptimizationUtil.ClearParameters(run, parameterNames); run.Results.Add("Meta-FromCache", new BoolValue(false)); run.Results.Add("Meta-Generation", new IntValue(currentGeneration)); run.Results.Add("Meta-ProblemIndex", new IntValue(problemIndex)); run.Name = string.Format("{0} Problem {1} Run {2}", parameterConfiguration.ParameterInfoString, problemIndex, repetitionIndex); qualities[problemIndex][repetitionIndex] = GetResultValue(run.Results, qualityMeasureName).Value; executionTimes[problemIndex][repetitionIndex] = (((TimeSpanValue)run.Results["Execution Time"]).Value); evaluatedSolutions[problemIndex][repetitionIndex] = (((IntValue)run.Results["EvaluatedSolutions"]).Value); runs.Add(run); } parameterConfiguration.AverageExecutionTimes = new ItemList(executionTimes.Select(t => new TimeSpanValue(TimeSpan.FromMilliseconds(t.Average(ts => ts.TotalMilliseconds))))); parameterConfiguration.AverageEvaluatedSolutions = new DoubleArray(evaluatedSolutions.Select(x => x.Average()).ToArray()); parameterConfiguration.Repetitions = new IntValue(repetitions); parameterConfiguration.AverageQualities = new DoubleArray(qualities.Select(q => q.Average()).ToArray()); if (maximization) parameterConfiguration.BestQualities = new DoubleArray(qualities.Select(q => q.Max()).ToArray()); else parameterConfiguration.BestQualities = new DoubleArray(qualities.Select(q => q.Min()).ToArray()); if (maximization) parameterConfiguration.WorstQualities = new DoubleArray(qualities.Select(q => q.Min()).ToArray()); else parameterConfiguration.WorstQualities = new DoubleArray(qualities.Select(q => q.Max()).ToArray()); parameterConfiguration.QualityVariances = new DoubleArray(qualities.Select(q => q.Variance()).ToArray()); parameterConfiguration.QualityStandardDeviations = new DoubleArray(qualities.Select(q => q.StandardDeviation()).ToArray()); parameterConfiguration.Runs = runs; this.QualityParameter.ActualValue = new DoubleValue(MetaOptimizationUtil.Normalize(parameterConfiguration, referenceQualityAverages, referenceQualityDeviations, referenceEvaluatedSolutionAverages, qualityWeight, standardDeviationWeight, evaluatedSolutionsWeight, maximization)); } else { // something terrible happened -> most probably due to invalid parameters. // penalty with worst quality from latest generation! double penaltyValue; if (maximization) penaltyValue = results.ContainsKey("CurrentWorstQuality") ? ((DoubleValue)results["CurrentWorstQuality"].Value).Value : referenceQualityAverages.Min(); else penaltyValue = results.ContainsKey("CurrentWorstQuality") ? ((DoubleValue)results["CurrentWorstQuality"].Value).Value : referenceQualityAverages.Max(); this.QualityParameter.ActualValue = new DoubleValue(penaltyValue); parameterConfiguration.Quality = new DoubleValue(penaltyValue); parameterConfiguration.AverageExecutionTimes = new ItemList(Enumerable.Repeat(new TimeSpanValue(TimeSpan.Zero), problems.Count)); parameterConfiguration.AverageEvaluatedSolutions = new DoubleArray(Enumerable.Repeat(0.0, problems.Count).ToArray()); parameterConfiguration.Repetitions = new IntValue(repetitions); parameterConfiguration.AverageQualities = new DoubleArray(Enumerable.Repeat(0.0, problems.Count).ToArray()); parameterConfiguration.BestQualities = new DoubleArray(Enumerable.Repeat(0.0, problems.Count).ToArray()); parameterConfiguration.WorstQualities = new DoubleArray(Enumerable.Repeat(0.0, problems.Count).ToArray()); parameterConfiguration.QualityVariances = new DoubleArray(Enumerable.Repeat(0.0, problems.Count).ToArray()); parameterConfiguration.QualityStandardDeviations = new DoubleArray(Enumerable.Repeat(0.0, problems.Count).ToArray()); parameterConfiguration.Runs = null; } // in OSGA there are more subscopes, so be careful which to delete CurrentScope.SubScopes.RemoveAll(x => x.Variables.Count((v) => (v.Name == "RepetitionCount")) == 1); return base.Apply(); } private T1 GetResultValue(IDictionary results, string resultName) { return (T1)results[resultName]; //string separator = "."; //string[] tokens = resultName.Split(separator.ToCharArray()); //IDictionary currentResults = results; //IItem currentResult = null; //for (int i = 0; i < tokens.Length; i++) { // if(currentResults == null) // throw new KeyNotFoundException("Result value " + resultName + " was not found"); // if (currentResults.ContainsKey(tokens[i])) { // currentResult = currentResults[tokens[i]]; // currentResults = currentResult as IDictionary; // } else { // throw new KeyNotFoundException("Result value " + resultName + " was not found"); // } //} //return (T1)currentResult; } private void GetReferenceValues(int problemsCount, out double[] referenceQualityAverages, out double[] referenceQualityDeviations, out double[] referenceEvaluatedSolutionAverages) { if (ReferenceQualityAveragesParameter.ActualValue == null) { // this is generation zero. no reference qualities for normalization have been calculated yet. in this special case the ReferenceQualityAnalyzer will do the normalization referenceQualityAverages = new double[problemsCount]; referenceQualityDeviations = new double[problemsCount]; referenceEvaluatedSolutionAverages = new double[problemsCount]; for (int i = 0; i < referenceQualityAverages.Length; i++) { referenceQualityAverages[i] = 1; referenceQualityDeviations[i] = 1; referenceEvaluatedSolutionAverages[i] = 1; } } else { referenceQualityAverages = ReferenceQualityAveragesParameter.ActualValue.ToArray(); referenceQualityDeviations = ReferenceQualityDeviationsParameter.ActualValue.ToArray(); referenceEvaluatedSolutionAverages = ReferenceEvaluatedSolutionAveragesParameter.ActualValue.ToArray(); } } } }