Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.VariableInteractionNetworks/HeuristicLab.VariableInteractionNetworks.Views/3.3/VariableInteractionNetworkView.cs @ 12614

Last change on this file since 12614 was 12568, checked in by arapeanu, 9 years ago

#2288: Fixed bug in SymbolicDataAnalysisVariableImpactsAnalyzer (simplification before optimization) and in VariableInteractionNetworkView for computing the adjacency matrix and sorting the variable impacts matrix

File size: 21.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.Windows.Forms;
28using HeuristicLab.Common;
29using HeuristicLab.Data;
30using HeuristicLab.MainForm;
31using HeuristicLab.MainForm.WindowsForms;
32using HeuristicLab.Optimization;
33using HeuristicLab.Problems.DataAnalysis;
34using HeuristicLab.Problems.DataAnalysis.Symbolic;
35using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
36using System.Collections;
37
38namespace HeuristicLab.VariableInteractionNetworks.Views
39{
40    [View("Variable Interaction Network")]
41    [Content(typeof(RunCollection), IsDefaultView = false)]
42
43    public sealed partial class VariableInteractionNetworkView : AsynchronousContentView
44    {
45        private const string variableImpactResultName = "Variable impacts";
46        private const string TrainingBestSolutionParameterName = "Best training solution";
47
48        public new RunCollection Content
49        {
50            get { return (RunCollection)base.Content; }
51            set { base.Content = value; }
52        }
53
54        public VariableInteractionNetworkView()
55        {
56            InitializeComponent();
57        }
58
59        internal class NoFocusTrackBar : System.Windows.Forms.TrackBar
60        {
61            [System.Runtime.InteropServices.DllImport("user32.dll")]
62            public extern static int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
63
64            private static int MakeParam(int loWord, int hiWord)
65            {
66                return (hiWord << 16) | (loWord & 0xffff);
67            }
68
69            protected override void OnGotFocus(EventArgs e)
70            {
71                base.OnGotFocus(e);
72                SendMessage(this.Handle, 0x0128, MakeParam(1, 0x1), 0);
73            }
74        }
75
76        #region events
77
78        //  #region Event Handlers (Content)
79        protected override void OnContentChanged()
80        {
81            base.OnContentChanged();
82            if (Content == null)
83            {
84                // TODO: Add code when content has been changed and is null
85            }
86            else
87            {
88                // TODO: Add code when content has been changed and is not null
89                viewHost2.Content = CalculateNodeImportance(CalculateAdjacencyMatrix());
90                var adjMatrix = CalculateAdjacencyMatrix();
91                viewHost1.Content = adjMatrix;
92                viewHost3.Content = (DoubleMatrix)adjMatrix.Clone();
93                trackBar1.Minimum = (int)(1000 * GetMinNonNullElement(adjMatrix));
94                trackBar1.Maximum = (int)(1000 * (adjMatrix.Max()));
95            }
96        }
97        #endregion
98
99        protected override void SetEnabledStateOfControls()
100        {
101            base.SetEnabledStateOfControls();
102            // TODO: Enable or disable controls based on whether the content is null or the view is set readonly
103        }
104
105        #region Event Handlers (child controls)
106        // TODO: Put event handlers of child controls here.
107        #endregion
108
109        private DoubleMatrix CalculateAdjacencyMatrix()
110        {
111            var runCollection = Content;
112            var inputVariables = ((IRegressionProblemData)runCollection.First().Parameters["ProblemData"]).InputVariables.Select(x => x.Value).ToList();
113            var groupRunCollection = Content.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).OrderBy(x => inputVariables.IndexOf(x.Key)).ToList();
114
115            var allVariableImpacts = runCollection.Select(run => (DoubleMatrix)run.Results[variableImpactResultName]);
116            var variableNames = (from variableImpact in allVariableImpacts
117                                 from variableName in variableImpact.RowNames
118                                 select variableName).Distinct().ToArray();
119           
120            var vars = new List<Tuple<int, string>>();
121           
122            var allowedInputs = ((IRegressionProblemData)groupRunCollection[0].First().Parameters["ProblemData"]).AllowedInputVariables.ToList();
123
124            var adjMatrix = new DoubleMatrix(variableNames.Length, variableNames.Length);
125
126            for (int i = 0; i < adjMatrix.Rows; ++i)
127            {
128                int inputIndex = allowedInputs.FindIndex(x => x == variableNames[i]);
129                vars.Add(new Tuple<int, string>(inputIndex, variableNames[i]));
130            }
131
132            vars.Sort((a, b) => a.Item1.CompareTo(b.Item1));
133
134            for (int i = 0; i < adjMatrix.Rows; ++i)
135            {
136                variableNames[i] = vars[i].Item2;
137            }
138            adjMatrix.RowNames = variableNames;
139            adjMatrix.ColumnNames = adjMatrix.RowNames;
140
141            for (int j = 0; j < groupRunCollection.Count; ++j)
142            {
143                var g = groupRunCollection[j];
144               
145                var matrix = CalculateAdjacencyRows(g);
146                var variables = new List<double>();
147
148                for (int i = 0; i < matrix.Columns; ++i)
149                {
150                    variables.Add(matrix[0, i]);
151                }
152               
153                for (int i = 0; i < variables.Count; ++i)
154                {
155                    if (i == j)
156                    {
157                        adjMatrix[i, i] = 0;
158                        variables.Insert(i, 0);
159                    }
160                    else
161                        adjMatrix[j, i] = variables[i];
162                }
163            }
164            return adjMatrix;
165        }
166
167        private DoubleMatrix CalculateAdjacencyRows(IEnumerable<IRun> runs)
168        {
169            var runNames = runs.Select(x => x.Name).ToArray();
170            var runsArray = runs.ToArray();
171            DoubleMatrix varImpactMatrix = CalculateVariableImpactMatrix(runsArray, runNames);
172         
173            var targetMatrix = new DoubleMatrix(1, varImpactMatrix.Rows);
174
175            for (int i = 0; i < varImpactMatrix.Rows; ++i)
176            {
177                targetMatrix[0, i] = varImpactMatrix[i, runNames.Length];
178            }
179
180            targetMatrix.RowNames = new[] { "Impacts" };
181            targetMatrix.ColumnNames = varImpactMatrix.RowNames;
182            return targetMatrix;
183        }
184
185        private DoubleMatrix UpdateAdjacencyMatrixByThresholdAndTargetVariable(double threshold, string targetVariable, DoubleMatrix adjMatrix)
186        {
187            var originalMatrix = (DoubleMatrix)viewHost1.Content;
188            var groupRunCollection = Content.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).ToList();
189            string[] targets = adjMatrix.RowNames.ToArray();
190            var targetIndex = Array.IndexOf(targets, targetVariable);
191
192            for (int j = 0; j < groupRunCollection.Count; ++j)
193            {
194                double originalValue = originalMatrix[targetIndex, j];
195                adjMatrix[targetIndex, j] = (originalValue <= Math.Max(threshold, Double.Parse(genThreshold.Text))) ? 0 : originalValue;
196            }
197            return adjMatrix;
198        }
199
200        private DoubleMatrix UpdateAdjacencyMatrixByThreshold(double threshold, DoubleMatrix adjMatrix)
201        {
202            var originalMatrix = (DoubleMatrix)viewHost1.Content;
203            var groupRunCollection = Content.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).ToList();
204
205            for (int i = 0; i < adjMatrix.Rows; ++i)
206            {
207                for (int j = 0; j < adjMatrix.Columns; ++j)
208                {
209                    double originalValue = originalMatrix[i, j];
210                    adjMatrix[i, j] = originalValue <= threshold ? 0 : originalValue;
211                }
212            }
213            return adjMatrix;
214        }
215
216        private double GetMinNonNullElement(DoubleMatrix adjMatrix)
217        {
218            double min = adjMatrix.Max();
219            for (int i = 0; i < adjMatrix.Rows; i++)
220            {
221                for (int j = 0; j < adjMatrix.Columns; j++)
222                {                 
223                    min = (min > adjMatrix[i, j] && adjMatrix[i, j] != 0) ? adjMatrix[i, j] : min;
224                }
225            }
226            return min;
227        }
228
229        private double GetMaxFromRow(int rowIndex, DoubleMatrix adjMatrix)
230        {
231            double max = adjMatrix.Min();
232            for (int j = 0; j < adjMatrix.Columns; ++j)
233            {
234                max = (max < adjMatrix[rowIndex, j] && adjMatrix[rowIndex, j] != 0) ? adjMatrix[rowIndex, j] : max;
235            }
236            return max;
237        }
238
239        private DoubleMatrix CalculateNodeImportance(DoubleMatrix adjMatrix)
240        {
241            DoubleMatrix nodeImportance = new DoubleMatrix(adjMatrix.Rows, 1);
242            var variables = new List<Tuple<string, double>>();
243            var rowNames = adjMatrix.RowNames.ToList();
244            var groupRunCollection = Content.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).ToList();
245            double[] meanQuality = new double[groupRunCollection.Count];
246
247            for (int j = 0; j < groupRunCollection.Count; ++j)
248            {
249                var g = groupRunCollection[j];
250                meanQuality[j] = g.Average(x => ((IRegressionSolution)x.Results[TrainingBestSolutionParameterName]).TrainingRSquared);
251            }
252
253            for (int i = 0; i < adjMatrix.Columns; ++i)
254            {
255                for (int j = 0; j < adjMatrix.Rows; ++j)
256                {
257                    nodeImportance[i, 0] += adjMatrix[j, i] * meanQuality[j];
258                }
259                nodeImportance[i, 0] /= (adjMatrix.Rows - 1);
260                variables.Add(new Tuple<string, double>(rowNames[i], nodeImportance[i, 0]));
261            }
262
263            variables.Sort((b, a) => a.Item2.CompareTo(b.Item2));
264
265            for (int i = 0; i < nodeImportance.Rows; ++i)
266            {
267                nodeImportance[i, 0] = variables[i].Item2;
268                rowNames[i] = variables[i].Item1;
269            }
270
271            nodeImportance.RowNames = rowNames;
272            nodeImportance.ColumnNames = new[] { "Node Importance" };
273            return nodeImportance;
274        }
275
276        //modified from RunCollectionVariableImpactView
277        private DoubleMatrix CalculateVariableImpactMatrix(IRun[] runs, string[] runNames)
278        {
279            IEnumerable<DoubleMatrix> allVariableImpacts = (from run in runs
280                                                            select run.Results[variableImpactResultName]).Cast<DoubleMatrix>();
281            IEnumerable<string> variableNames = (from variableImpact in allVariableImpacts
282                                                 from variableName in variableImpact.RowNames
283                                                 select variableName).Distinct();
284
285            // filter variableNames: only include names that have at least one non-zero value in a run
286            List<string> variableNamesList = (from variableName in variableNames
287                                              where GetVariableImpacts(variableName, allVariableImpacts).Any(x => !x.IsAlmost(0.0))
288                                              select variableName).ToList();
289
290            List<string> columnNames = new List<string>(runNames);
291            columnNames.Add("Mean");
292
293            int numberOfRuns = runs.Length;
294
295            DoubleMatrix matrix = new DoubleMatrix(variableNamesList.Count, numberOfRuns + 1);
296            matrix.SortableView = true;
297            matrix.ColumnNames = columnNames;
298
299            List<List<double>> variableImpactsOverRuns = (from variableName in variableNamesList
300                                                          select GetVariableImpacts(variableName, allVariableImpacts).ToList()).ToList();
301
302            for (int row = 0; row < variableImpactsOverRuns.Count; row++)
303            {
304                matrix[row, numberOfRuns] = Math.Round(variableImpactsOverRuns[row].Average(), 3);
305            }
306
307            // fill matrix with impacts from runs
308            for (int i = 0; i < runs.Length; i++)
309            {
310                IRun run = runs[i];
311                DoubleMatrix runVariableImpacts = (DoubleMatrix)run.Results[variableImpactResultName];
312                for (int j = 0; j < runVariableImpacts.Rows; j++)
313                {
314                    int rowIndex = variableNamesList.FindIndex(s => s == runVariableImpacts.RowNames.ElementAt(j));
315                    if (rowIndex > -1)
316                    {
317                        matrix[rowIndex, i] = Math.Round(runVariableImpacts[j, 0], 3);
318                    }
319                }
320            }
321
322            // sort by median
323            var sortedMatrix = (DoubleMatrix)matrix.Clone();
324            var sortedIndexes = from i in Enumerable.Range(0, sortedMatrix.Rows)
325                                orderby matrix[i, numberOfRuns]
326                                select i;
327
328            int targetIndex = 0;
329            foreach (var sourceIndex in sortedIndexes)
330            {
331                for (int c = 0; c < matrix.Columns; c++)
332                    sortedMatrix[targetIndex, c] = matrix[sourceIndex, c];
333                targetIndex++;
334            }
335            sortedMatrix.RowNames = sortedIndexes.Select(i => variableNamesList[i]);
336
337            var vars = new List<Tuple<int, string, double>>();
338            var rowNames = sortedMatrix.RowNames.ToList();
339
340            var groupRunCollection = Content.GroupBy(x => ((IRegressionProblemData)x.Parameters["ProblemData"]).TargetVariable).ToList();
341            var inputs = ((IRegressionProblemData)groupRunCollection[0].First().Parameters["ProblemData"]).InputVariables.ToList();
342            List<string> inp = (from input in inputs
343                                select (input.ToString())).ToList();
344
345            for (int i = 0; i < sortedMatrix.Rows; ++i)
346            {
347                int inputIndex = inp.FindIndex(x => x == rowNames[i]);
348                vars.Add(new Tuple<int, string, double>(inputIndex, rowNames[i], sortedMatrix[i, runNames.Length]));
349            }
350
351                vars.Sort((a, b) => a.Item1.CompareTo(b.Item1));
352               
353            for (int i = 0; i < sortedMatrix.Rows; ++i)
354            {
355                sortedMatrix[i, runNames.Length] = vars[i].Item3;
356                rowNames[i] = vars[i].Item2;
357            }
358            sortedMatrix.RowNames = rowNames;
359
360            return sortedMatrix;
361        }
362
363        //taken from RunCollectionVariableImpactView
364        private IEnumerable<double> GetVariableImpacts(string variableName, IEnumerable<DoubleMatrix> allVariableImpacts)
365        {
366            foreach (DoubleMatrix runVariableImpacts in allVariableImpacts)
367            {
368                int row = 0;
369                foreach (string rowName in runVariableImpacts.RowNames)
370                {
371                    if (rowName == variableName)
372                        yield return runVariableImpacts[row, 0];
373                    row++;
374                }
375            }
376        }
377
378        private void trackBar1_ValueChanged(object sender, EventArgs e)
379        {
380            genThreshold.Text = (0.001 * trackBar1.Value).ToString();
381            textBox1.Text = (0.001 * trackBar1.Minimum).ToString();
382            textBox2.Text = (0.001 * trackBar1.Maximum).ToString();
383            viewHost3.Content = UpdateAdjacencyMatrixByThreshold(0.001 * trackBar1.Value, (DoubleMatrix)viewHost3.Content);
384        }
385
386        private void mouseDownEvent(TrackBar tb, MouseEventArgs e)
387        {
388                double percentage = (double)e.X / (double)(tb.Width - 6);
389                double clickPos = percentage * (tb.Maximum - tb.Minimum);
390                try
391                {
392                    tb.Value = (int)clickPos + tb.Minimum;
393                }
394                catch
395                {
396                    MessageBox.Show("Value outside range!");
397                    return;
398                }
399        }
400
401        private void trackBar1_MouseDown(object sender, MouseEventArgs e)
402        {
403            mouseDownEvent(trackBar1, e);
404        }
405
406        private void trackBar2_MouseDown(object sender, MouseEventArgs e)
407        {
408            if (targetVariablesCombo.SelectedIndex < 0)
409            {
410                return;
411            }
412            else
413            {
414                mouseDownEvent(trackBar2, e);
415            }
416        }
417
418        private void trackBar2_ValueChanged(object sender, EventArgs e)
419        {
420            targetThreshold.Text = (0.001 * trackBar2.Value).ToString();
421
422            if (targetVariablesCombo.SelectedIndex < 0)
423            {
424                MessageBox.Show("Please select target variable!");
425                return;
426            }
427            else
428            {
429                string selectedItem = (string)targetVariablesCombo.Items[targetVariablesCombo.SelectedIndex];
430                viewHost3.Content = UpdateAdjacencyMatrixByThresholdAndTargetVariable(0.001 * trackBar2.Value, selectedItem, (DoubleMatrix)viewHost3.Content);
431            }
432        }
433
434        private void genThresholdEvent()
435        {
436            this.errorProvider.SetError(genThreshold, "");
437
438            if (genThreshold.Text != "")
439            {
440                if (Double.Parse(genThreshold.Text) >= GetMinNonNullElement((DoubleMatrix)viewHost1.Content) && Double.Parse(genThreshold.Text) <= ((DoubleMatrix)viewHost1.Content).Max())
441                {
442                    genThreshold.Select(genThreshold.Text.Length, 0);
443                    trackBar1.Value = (int)(1000 * Double.Parse(genThreshold.Text));
444                    viewHost3.Content = UpdateAdjacencyMatrixByThreshold(Double.Parse(genThreshold.Text), (DoubleMatrix)viewHost3.Content);
445                }
446                else
447                {
448                    this.errorProvider.SetError(genThreshold, "Value out of range!");
449                }
450            }
451            else
452            {
453                MessageBox.Show("Please select a threshold!");
454                this.errorProvider.SetError(genThreshold, "");
455                return;
456            }
457        }
458
459        private void genThreshold_TextChanged(object sender, EventArgs e)
460        {
461            genThresholdEvent();
462        }
463
464        private void genThreshold_KeyDown(object sender, KeyEventArgs e)
465        {
466            if (e.KeyCode == Keys.Enter)
467                genThresholdEvent();       
468        }
469
470        private void targetThresholdEvent()
471        {
472            this.errorProvider2.SetError(targetThreshold, "");
473
474            if (targetVariablesCombo.SelectedIndex < 0)
475            {
476                return;
477            }
478            else
479            {
480                string selectedItem = (string)targetVariablesCombo.Items[targetVariablesCombo.SelectedIndex];
481                if (Double.Parse(targetThreshold.Text) >= Double.Parse(textBox3.Text) && Double.Parse(targetThreshold.Text) <= Double.Parse(textBox4.Text))
482                {
483                    trackBar2.Value = (int)(1000 * Double.Parse(targetThreshold.Text));
484                }
485                else
486                {
487                    this.errorProvider2.SetError(targetThreshold, "Value out of range!");
488                    return;
489                }
490            }
491        }
492
493        private void targetThreshold_TextChanged(object sender, EventArgs e)
494        {
495            targetThresholdEvent();
496        }
497
498        private void targetThreshold_KeyDown(object sender, KeyEventArgs e)
499        {
500            if (e.KeyCode == Keys.Enter)
501            {
502                targetThresholdEvent();
503            }
504        }
505
506        private void targetVariablesCombo_Dropdown(object sender, System.EventArgs e)
507        {
508            targetVariablesCombo.Items.Clear();
509            string[] targetVariables = ((DoubleMatrix)viewHost3.Content).RowNames.ToArray();
510            targetVariablesCombo.Items.AddRange(targetVariables);
511        }
512
513        private void targetVariablesCombo_SelectedIndexChanged(object sender, System.EventArgs e)
514        {
515            var targetIndex = targetVariablesCombo.SelectedIndex;
516            string selectedItem = (string)targetVariablesCombo.Items[targetIndex];
517            trackBar2.Minimum = 0;
518            trackBar2.Maximum = (int)(1000 * GetMaxFromRow(targetIndex, (DoubleMatrix)viewHost1.Content));
519            textBox3.Text = trackBar2.Minimum.ToString();
520            textBox4.Text = (0.001 * trackBar2.Maximum).ToString();
521            UpdateAdjacencyMatrixByThresholdAndTargetVariable(0.001 * trackBar2.Value, selectedItem, (DoubleMatrix)viewHost3.Content);
522        }
523    }
524}
Note: See TracBrowser for help on using the repository browser.