Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/RunCollectionVariableInteractionNetworkView.cs @ 13727

Last change on this file since 13727 was 13727, checked in by bburlacu, 8 years ago

#2288: Added directed graph chart and layout class for the visualization of knowledge network graphs. Added RunCollectionVariableInteractionNetworkView and removed the old view.

File size: 15.2 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.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Text;
28using System.Windows.Forms;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Core.Views;
32using HeuristicLab.Data;
33using HeuristicLab.MainForm;
34using HeuristicLab.Optimization;
35using HeuristicLab.Problems.DataAnalysis;
36using HeuristicLab.Visualization;
37using Rectangle = HeuristicLab.Visualization.Rectangle;
38
39namespace HeuristicLab.VariableInteractionNetworks.Views {
40  [View("Variable Interaction Network")]
41  [Content(typeof(RunCollection), IsDefaultView = false)]
42
43  public sealed partial class RunCollectionVariableInteractionNetworkView : ItemView {
44    public RunCollectionVariableInteractionNetworkView() {
45      InitializeComponent();
46      ConfigureNodeShapes();
47    }
48
49    public new RunCollection Content {
50      get { return (RunCollection)base.Content; }
51      set {
52        if (value != null && value != Content) {
53          base.Content = value;
54        }
55      }
56    }
57
58    private static VariableInteractionNetwork BuildNetworkFromSolutionQualities(RunCollection runs, double threshold, bool useBestRunsPerTarget = false) {
59      var nodes = new Dictionary<string, IVertex>();
60      var vn = new VariableInteractionNetwork();
61      var targets = runs.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).ToList();
62      var targetQualities = new Dictionary<string, double>();
63      var targetInputs = new Dictionary<string, List<string>>();
64
65      if (useBestRunsPerTarget) {
66        foreach (var target in targets) {
67          var bestRun = target.OrderBy(x => ((DoubleValue)x.Results["Best training solution quality"]).Value).First();
68          var bestQuality = ((DoubleValue)bestRun.Results["Best training solution quality"]).Value;
69          var pd = (IRegressionProblemData)bestRun.Parameters["ProblemData"];
70          if (threshold > bestQuality) continue; // skip if quality is below the treshold
71          targetQualities[target.Key] = bestQuality;
72          targetInputs[target.Key] = pd.AllowedInputVariables.ToList();
73        }
74      } else {
75        foreach (var target in targets) {
76          var avgQuality = CalculateAverageQuality(new RunCollection(target));
77          if (threshold > avgQuality) continue;
78          targetQualities[target.Key] = avgQuality;
79          var pd = (IRegressionProblemData)target.First().Parameters["ProblemData"];
80          targetInputs[target.Key] = pd.AllowedInputVariables.ToList();
81        }
82      }
83
84      foreach (var ti in targetQualities) {
85        var target = ti.Key;
86        var variables = targetInputs[ti.Key];
87        var quality = ti.Value;
88        IVertex targetNode;
89
90        if (!nodes.TryGetValue(target, out targetNode)) {
91          targetNode = new VariableNetworkNode { Label = target };
92          vn.AddVertex(targetNode);
93          nodes[target] = targetNode;
94        }
95
96        IVertex variableNode;
97        if (variables.Count > 0) {
98          var variableList = new List<string>(variables);
99          variableList.Add(target);
100          var junctionLabel = Concatenate(variableList);
101          IVertex junctionNode;
102          if (!nodes.TryGetValue(junctionLabel, out junctionNode)) {
103            junctionNode = new JunctionNetworkNode { Label = string.Empty };
104            vn.AddVertex(junctionNode);
105            nodes[junctionLabel] = junctionNode;
106          }
107          IArc arc;
108          foreach (var v in variables) {
109            var impact = quality;
110            if (!nodes.TryGetValue(v, out variableNode)) {
111              variableNode = new VariableNetworkNode { Label = v };
112              vn.AddVertex(variableNode);
113              nodes[v] = variableNode;
114            }
115            arc = new Arc(variableNode, junctionNode) { Weight = impact };
116            vn.AddArc(arc);
117          }
118          arc = new Arc(junctionNode, targetNode) { Weight = junctionNode.InArcs.Sum(x => x.Weight) };
119          vn.AddArc(arc);
120        } else {
121          foreach (var v in variables) {
122            var impact = quality;
123            if (!nodes.TryGetValue(v, out variableNode)) {
124              variableNode = new VariableNetworkNode { Label = v };
125              vn.AddVertex(variableNode);
126              nodes[v] = variableNode;
127            }
128            var arc = new Arc(variableNode, targetNode) { Weight = impact };
129            vn.AddArc(arc);
130          }
131        }
132      }
133
134      return vn;
135    }
136
137    private static VariableInteractionNetwork BuildNetworkFromVariableImpacts(RunCollection runs, string qualityResultName, bool maximization, string impactsResultName, double threshold, bool useBestRunsPerTarget = false) {
138      var nodes = new Dictionary<string, IVertex>();
139      var vn = new VariableInteractionNetwork();
140      var targets = runs.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).ToList();
141
142      var targetImpacts = new Dictionary<string, Dictionary<string, double>>();
143
144      if (useBestRunsPerTarget) {
145        var bestRunsPerTarget = maximization ?
146          targets.Select(x => x.OrderBy(y => ((DoubleValue)y.Results[qualityResultName]).Value).Last()) :
147          targets.Select(x => x.OrderBy(y => ((DoubleValue)y.Results[qualityResultName]).Value).First());
148
149        foreach (var run in bestRunsPerTarget) {
150          var pd = (IRegressionProblemData)run.Parameters["ProblemData"];
151          var target = pd.TargetVariable;
152          var impacts = (DoubleMatrix)run.Results[impactsResultName];
153          targetImpacts[target] = impacts.RowNames.Select((x, i) => new { Name = x, Index = i }).ToDictionary(x => x.Name, x => impacts[x.Index, 0]);
154        }
155      } else {
156        foreach (var target in targets) {
157          var averageImpacts = CalculateAverageImpacts(new RunCollection(target), impactsResultName);
158          targetImpacts[target.Key] = averageImpacts;
159        }
160      }
161
162      foreach (var ti in targetImpacts) {
163        var target = ti.Key;
164        var variableImpacts = ti.Value;
165        IVertex targetNode;
166
167        var variables = variableImpacts.Keys.Where(x => variableImpacts[x] >= threshold).ToList();
168        if (variables.Count == 0) continue;
169
170        if (!nodes.TryGetValue(target, out targetNode)) {
171          targetNode = new VariableNetworkNode { Label = target };
172          vn.AddVertex(targetNode);
173          nodes[target] = targetNode;
174        }
175
176        IVertex variableNode;
177        if (variables.Count > 1) {
178          var variableList = new List<string>(variables) { target };
179          var junctionLabel = Concatenate(variableList);
180          IVertex junctionNode;
181          if (!nodes.TryGetValue(junctionLabel, out junctionNode)) {
182            junctionNode = new JunctionNetworkNode { Label = string.Empty };
183            vn.AddVertex(junctionNode);
184            nodes[junctionLabel] = junctionNode;
185          }
186          IArc arc;
187          foreach (var v in variables) {
188            var impact = variableImpacts[v];
189            if (!nodes.TryGetValue(v, out variableNode)) {
190              variableNode = new VariableNetworkNode { Label = v };
191              vn.AddVertex(variableNode);
192              nodes[v] = variableNode;
193            }
194            arc = new Arc(variableNode, junctionNode) { Weight = impact };
195            vn.AddArc(arc);
196          }
197          arc = new Arc(junctionNode, targetNode) { Weight = junctionNode.InArcs.Sum(x => x.Weight) };
198          vn.AddArc(arc);
199        } else {
200          foreach (var v in variables) {
201            var impact = variableImpacts[v];
202            if (!nodes.TryGetValue(v, out variableNode)) {
203              variableNode = new VariableNetworkNode { Label = v };
204              vn.AddVertex(variableNode);
205              nodes[v] = variableNode;
206            }
207            var arc = new Arc(variableNode, targetNode) { Weight = impact };
208            vn.AddArc(arc);
209          }
210        }
211      }
212      return vn;
213    }
214
215    private static double CalculateAverageQuality(RunCollection runs) {
216      var pd = (IRegressionProblemData)runs.First().Parameters["ProblemData"];
217      var target = pd.TargetVariable;
218      var inputs = pd.AllowedInputVariables;
219
220      if (!runs.All(x => {
221        var problemData = (IRegressionProblemData)x.Parameters["ProblemData"];
222        return target == problemData.TargetVariable && inputs.SequenceEqual(problemData.AllowedInputVariables);
223      })) {
224        throw new ArgumentException("All runs must have the same target and inputs.");
225      }
226      return runs.Average(x => ((DoubleValue)x.Results["Best training solution quality"]).Value);
227    }
228
229    private static Dictionary<string, double> CalculateAverageImpacts(RunCollection runs, string resultName) {
230      var pd = (IRegressionProblemData)runs.First().Parameters["ProblemData"];
231      var target = pd.TargetVariable;
232      var inputs = pd.AllowedInputVariables.ToList();
233
234      var impacts = inputs.ToDictionary(x => x, x => 0d);
235
236      // check if all the runs have the same target and same inputs
237      if (!runs.All(x => {
238        var problemData = (IRegressionProblemData)x.Parameters["ProblemData"];
239        return target == problemData.TargetVariable && inputs.SequenceEqual(problemData.AllowedInputVariables);
240      })) {
241        throw new ArgumentException("All runs must have the same target and inputs.");
242      }
243
244      foreach (var run in runs) {
245        var impactsMatrix = (DoubleMatrix)run.Results[resultName];
246
247        int i = 0;
248        foreach (var v in impactsMatrix.RowNames) {
249          impacts[v] += impactsMatrix[i, 0];
250          ++i;
251        }
252      }
253
254      foreach (var v in inputs) {
255        impacts[v] /= runs.Count;
256      }
257
258      return impacts;
259    }
260
261    private static string Concatenate(IEnumerable<string> strings) {
262      var sb = new StringBuilder();
263      foreach (var s in strings) {
264        sb.Append(s);
265      }
266      return sb.ToString();
267    }
268
269    private void ConfigureNodeShapes() {
270      graphChart.ClearShapes();
271      var font = new Font(FontFamily.GenericSansSerif, 12);
272      graphChart.AddShape(typeof(VariableNetworkNode), new LabeledPrimitive(new Ellipse(graphChart.Chart, new PointD(0, 0), new PointD(30, 30), Pens.Black, Brushes.White), "", font));
273      graphChart.AddShape(typeof(JunctionNetworkNode), new LabeledPrimitive(new Rectangle(graphChart.Chart, new PointD(0, 0), new PointD(15, 15), Pens.Black, Brushes.DarkGray), "", font));
274    }
275
276    #region events
277    protected override void OnContentChanged() {
278      base.OnContentChanged();
279      var run = Content.First();
280      var pd = (IRegressionProblemData)run.Parameters["ProblemData"];
281      var variables = new HashSet<string>(new List<string>(pd.Dataset.DoubleVariables));
282      impactResultNameComboBox.Items.Clear();
283      foreach (var result in run.Results.Where(x => x.Value is DoubleMatrix)) {
284        var m = (DoubleMatrix)result.Value;
285        if (m.RowNames.All(x => variables.Contains(x)))
286          impactResultNameComboBox.Items.Add(result.Key);
287      }
288      qualityResultNameComboBox.Items.Clear();
289      foreach (var result in run.Results.Where(x => x.Value is DoubleValue)) {
290        qualityResultNameComboBox.Items.Add(result.Key);
291      }
292      if (impactResultNameComboBox.Items.Count > 0) {
293        impactResultNameComboBox.Text = (string)impactResultNameComboBox.Items[0];
294      }
295      if (qualityResultNameComboBox.Items.Count > 0) {
296        qualityResultNameComboBox.Text = (string)qualityResultNameComboBox.Items[0];
297      }
298      if (impactResultNameComboBox.Items.Count > 0 && qualityResultNameComboBox.Items.Count > 0)
299        NetworkConfigurationChanged(this, EventArgs.Empty);
300    }
301
302    private void TextBoxValidating(object sender, CancelEventArgs e) {
303      double v;
304      string errorMsg = "Could not parse the entered value. Please input a real number.";
305      var tb = (TextBox)sender;
306      if (!double.TryParse(tb.Text, out v)) {
307        e.Cancel = true;
308        tb.Select(0, tb.Text.Length);
309
310        // Set the ErrorProvider error with the text to display.
311        this.errorProvider.SetError(tb, errorMsg);
312        errorProvider.BlinkStyle = ErrorBlinkStyle.NeverBlink;
313        errorProvider.SetIconPadding(tb, -20);
314      }
315    }
316
317    private void NetworkConfigurationBoxValidated(object sender, EventArgs e) {
318      var tb = (TextBox)sender;
319      errorProvider.SetError(tb, string.Empty);
320      NetworkConfigurationChanged(sender, e);
321    }
322
323    private void LayoutConfigurationBoxValidated(object sender, EventArgs e) {
324      var tb = (TextBox)sender;
325      errorProvider.SetError(tb, string.Empty);
326      LayoutConfigurationChanged(sender, e);
327    }
328
329    private void NetworkConfigurationChanged(object sender, EventArgs e) {
330      var useBest = impactAggregationComboBox.SelectedIndex <= 0;
331      var threshold = double.Parse(impactThresholdTextBox.Text);
332      var qualityResultName = qualityResultNameComboBox.Text;
333      var impactsResultName = impactResultNameComboBox.Text;
334      if (string.IsNullOrEmpty(qualityResultName) || string.IsNullOrEmpty(impactsResultName))
335        return;
336      var maximization = maximizationCheckBox.Checked;
337      var network = BuildNetworkFromVariableImpacts(Content, qualityResultName, maximization, impactsResultName, threshold, useBest);
338      if (network.Vertices.Any())
339        graphChart.Graph = network;
340    }
341
342    private void LayoutConfigurationChanged(object sender, EventArgs e) {
343      ConstrainedForceDirectedLayout.EdgeRouting routingMode;
344      switch (edgeRoutingComboBox.SelectedIndex) {
345        case 0:
346          routingMode = ConstrainedForceDirectedLayout.EdgeRouting.None;
347          break;
348        case 1:
349          routingMode = ConstrainedForceDirectedLayout.EdgeRouting.Polyline;
350          break;
351        case 2:
352          routingMode = ConstrainedForceDirectedLayout.EdgeRouting.Orthogonal;
353          break;
354        default:
355          throw new ArgumentException("Invalid edge routing mode.");
356      }
357      var idealEdgeLength = double.Parse(idealEdgeLengthTextBox.Text);
358      if (routingMode == graphChart.RoutingMode && idealEdgeLength.IsAlmost(graphChart.IdealEdgeLength)) return;
359      graphChart.RoutingMode = routingMode;
360      graphChart.PerformEdgeRouting = routingMode != ConstrainedForceDirectedLayout.EdgeRouting.None;
361      graphChart.IdealEdgeLength = idealEdgeLength;
362      graphChart.Draw();
363    }
364    #endregion
365  }
366}
Note: See TracBrowser for help on using the repository browser.