#region License Information /* HeuristicLab * Copyright (C) 2002-2016 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 HeuristicLab.Collections; using HeuristicLab.Common; using HeuristicLab.Optimization; using System; using System.Collections.Generic; using System.Linq; namespace HeuristicLab.OptimizationExpertSystem.Common { public class KNearestNeighborModel : IRecommendationModel { private readonly int K; private readonly string[] characteristics; private readonly Dictionary> performance; private readonly BidirectionalDictionary problemInstanceMap; private readonly double[] medianValues; public KNearestNeighborModel(int k, Dictionary> perfData, string[] characteristics) { this.K = k; this.performance = perfData; this.characteristics = characteristics; problemInstanceMap = new BidirectionalDictionary(); var i = 0; foreach (var pi in perfData.Keys) { problemInstanceMap.Add(i++, pi); } this.medianValues = KnowledgeCenter.GetMedianValues(perfData.Keys.OrderBy(problemInstanceMap.GetBySecond).ToArray(), characteristics); } public IEnumerable> GetRanking(IRun problemInstance) { double[] means, sdevs; var features = KnowledgeCenter.GetFeaturesStandardized(performance.Keys.OrderBy(problemInstanceMap.GetBySecond).ToArray(), characteristics, out means, out sdevs, medianValues); var feature = KnowledgeCenter.GetFeatures(new [] { problemInstance }, characteristics, medianValues)[0]; for (var f = 0; f < feature.Length; f++) { if (sdevs[f].IsAlmost(0)) feature[f] = 0; else feature[f] = (feature[f] - means[f]) / sdevs[f]; } var nearestK = features.Select((f, i) => new { ProblemInstanceIndex = i, Feature = f }) .OrderBy(x => x.Feature.Select((f, i) => (f - feature[i]) * (f - feature[i])).Sum()); var performances = new Dictionary(); var k = 0; foreach (var next in nearestK) { if (k >= K) break; var perfs = performance[problemInstanceMap.GetByFirst(next.ProblemInstanceIndex)]; if (perfs.Count == 0) continue; foreach (var p in perfs) { var ert = Math.Pow(10, p.Value); Performance perf; if (!performances.TryGetValue(p.Key, out perf)) { perf = new Performance(); performances[p.Key] = perf; } perf.Add(ert); } k++; } return performances.Select(x => new { Alg = x.Key, Perf = x.Value.ExpectedRuntime() }) .OrderBy(x => x.Perf) .Select(x => new KeyValuePair(x.Alg, x.Perf)); } private class Performance { private readonly List successful; private int runs; public int Fails { get { return runs - successful.Count; } } public Performance() { successful = new List(); } public void Add(double ert) { if (!double.IsInfinity(ert)) successful.Add(ert); runs++; } public double ExpectedRuntime() { if (successful.Count == 0) return int.MaxValue; return successful.Average() / (successful.Count / (double)runs); } } } }