Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistentDataStructures/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionDiscretizer.cs @ 16188

Last change on this file since 16188 was 14186, checked in by swagner, 8 years ago

#2526: Updated year of copyrights in license headers

File size: 8.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Text;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Data;
29using HeuristicLab.Parameters;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31
32namespace HeuristicLab.Optimization {
33  [Item("RunCollection Discretizer",
34    "Creates several levels from the distribution of a certain result accross a run collection and " +
35    "assigns a discretized value. Non-existing numbers as well as NaN and infinities are excluded from the caluclation.")]
36  [StorableClass]
37  public class RunCollectionDiscretizer : ParameterizedNamedItem, IRunCollectionModifier {
38
39    public override bool CanChangeName { get { return false; } }
40    public override bool CanChangeDescription { get { return false; } }
41
42    #region Parameters
43    public ValueParameter<StringValue> SourceParameter {
44      get { return (ValueParameter<StringValue>)Parameters["Source"]; }
45    }
46    public ValueParameter<StringValue> TargetParameter {
47      get { return (ValueParameter<StringValue>)Parameters["Target"]; }
48    }
49    public ValueParameter<DoubleValue> SpreadParameter {
50      get { return (ValueParameter<DoubleValue>)Parameters["Spread"]; }
51    }
52    public ValueParameter<StringValue> GroupByParameter {
53      get { return (ValueParameter<StringValue>)Parameters["GroupBy"]; }
54    }   
55    public ValueParameter<ItemList<StringValue>> LevelsParameter {
56      get { return (ValueParameter<ItemList<StringValue>>)Parameters["Levels"]; }
57    }   
58    #endregion
59
60    private string Source { get { return SourceParameter.Value.Value; } }
61    private string Target {
62      get { return TargetParameter.Value.Value; }
63      set { TargetParameter.Value.Value = value; }
64    }   
65    private double Spread { get { return SpreadParameter.Value.Value; } }
66    private string GroupBy { get { return GroupByParameter.Value.Value; } }
67    private List<string> Levels { get { return LevelsParameter.Value.Select(v => v.Value).ToList(); } }
68
69      #region Construction & Cloning
70    [StorableConstructor]
71    protected RunCollectionDiscretizer(bool deserializing) : base(deserializing) { }
72    protected RunCollectionDiscretizer(RunCollectionDiscretizer original, Cloner cloner)
73      : base(original, cloner) {
74      RegisterEvents();
75    }
76    public RunCollectionDiscretizer() {
77      Parameters.Add(new ValueParameter<StringValue>("Source", "Source value name to be fuzzified.", new StringValue("Value")));
78      Parameters.Add(new ValueParameter<StringValue>("Target", "Target value name. The new, fuzzified variable to be created.", new StringValue("Calc.Value")));
79      Parameters.Add(new ValueParameter<DoubleValue>("Spread", "The number of standard deviations considered one additional level. Set to zero to use empirical distribution instead.", new DoubleValue(1)));
80      Parameters.Add(new ValueParameter<StringValue>("GroupBy", "Create separate analyzes for different values of this variable.", new StringValue("")));
81      Parameters.Add(new ValueParameter<ItemList<StringValue>>("Levels", "The list of levels to be assigned.",
82        new ItemList<StringValue> {
83          new StringValue("Very Low"),
84          new StringValue("Low"),
85          new StringValue("Average"),
86          new StringValue("High"),
87          new StringValue("Very High"),
88        }));     
89      RegisterEvents();
90      UpdateName();
91    }
92    public override IDeepCloneable Clone(Cloner cloner) {
93      return new RunCollectionDiscretizer(this, cloner);
94    }
95    [StorableHook(HookType.AfterDeserialization)]
96    private void AfterDeserialization() {
97      RegisterEvents();
98    }
99    #endregion
100
101    private void RegisterEvents() {
102      SourceParameter.ToStringChanged += SourceParameter_NameChanged;
103      TargetParameter.ToStringChanged += Parameter_NameChanged;
104      GroupByParameter.ToStringChanged += Parameter_NameChanged;
105    }
106
107    private void SourceParameter_NameChanged(object sender, EventArgs e) {
108      Target = string.Format("{0}/Level", Source);
109    }
110
111    private void Parameter_NameChanged(object sender, EventArgs e) {
112      UpdateName();
113    }
114
115    private void UpdateName() {
116      name = string.Format("{0} := Discrete({1}{2})",
117        Target,
118        Source,
119        string.IsNullOrWhiteSpace(GroupBy) ? "" : string.Format("/{0}", GroupBy));       
120      OnNameChanged();
121    }
122
123    #region IRunCollectionModifier Members
124
125    public void Modify(List<IRun> runs) {
126      foreach (var group in runs
127        .Select(r => new {Run=r, Value=GetSourceValue(r)})
128        .Where(r => r.Value.HasValue && !double.IsNaN(r.Value.Value) && !double.IsInfinity(r.Value.Value))
129        .Select(r => new {r.Run, r.Value.Value, Bin=GetGroupByValue(r.Run)})
130        .GroupBy(r => r.Bin).ToList()) {
131        var values = group.Select(r => r.Value).ToList();
132        if (values.Count > 0) {
133          if (Spread > 0) {
134            var avg = values.Average();
135            var stdDev = values.StandardDeviation();
136            foreach (var r in group) {
137              r.Run.Results[Target] = new StringValue(Discretize(r.Value, avg, stdDev));
138            }
139          } else {
140            values.Sort();
141            var a = values.ToArray();
142            foreach (var r in group) {
143              r.Run.Results[Target] = new StringValue(Discretize(r.Value, a));
144            }
145          }
146        }
147      }     
148    }
149
150    private double? GetSourceValue(IRun run) {
151      return CastSourceValue(run.Results) ?? CastSourceValue(run.Parameters);
152    }
153
154    private string GetGroupByValue(IRun run) {
155      if (string.IsNullOrWhiteSpace(GroupBy))
156        return String.Empty;
157      IItem value;
158      run.Results.TryGetValue(GroupBy, out value);
159      if (value == null)
160        run.Parameters.TryGetValue(GroupBy, out value);
161      if (value != null)
162        return value.ToString();
163      else
164        return String.Empty;
165    }
166
167    private double? CastSourceValue(IDictionary<string, IItem> variables) {
168      IItem value;
169      variables.TryGetValue(Source, out value);
170      var intValue = value as IntValue;
171      if (intValue != null)
172        return intValue.Value;
173      var doubleValue = value as DoubleValue;
174      if (doubleValue != null)
175        return doubleValue.Value;
176      return null;
177    }
178
179    private string Discretize(double value, double avg, double stdDev) {
180      double dev = (value - avg)/(stdDev*Spread);
181      int index;
182      if (Levels.Count % 2 == 1) {
183        index = (int) Math.Floor(Math.Abs(dev));
184        index = (Levels.Count - 1)/2 + Math.Sign(dev) * index;
185      } else {
186        index = (int) Math.Ceiling(Math.Abs(dev));
187        if (dev > 0)
188          index = Levels.Count/2 + index;
189        else
190          index = Levels.Count/2 + 1 - index;
191      }
192      return Levels[Math.Min(Levels.Count - 1, Math.Max(0, index))];
193    }
194
195    private string Discretize(double value, double[] values) {
196      var index = Array.BinarySearch(values, value);
197      var pos = 1.0*(index < 0 ? ~index : index)/(values.Length-1);
198      return Levels[Math.Min(Levels.Count - 1, Math.Max(0, (int) Math.Round(pos*(Levels.Count-1))))];
199    }
200
201    #endregion
202  }
203}
Note: See TracBrowser for help on using the repository browser.