#region License Information /* HeuristicLab * Copyright (C) 2002-2019 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 System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using HeuristicLab.Common; using HeuristicLab.Core.Views; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.MainForm; using HeuristicLab.MainForm.WindowsForms; namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression.Views { [View("Response Function View")] [Content(typeof(ISymbolicRegressionSolution), false)] public partial class SymbolicRegressionSolutionResponseFunctionView : ItemView { private Dictionary> variableNodes; private ISymbolicExpressionTree clonedTree; private Dictionary medianValues; public SymbolicRegressionSolutionResponseFunctionView() { InitializeComponent(); variableNodes = new Dictionary>(); medianValues = new Dictionary(); Caption = "Response Function View"; } public new ISymbolicRegressionSolution Content { get { return (ISymbolicRegressionSolution)base.Content; } set { base.Content = value; } } protected override void RegisterContentEvents() { base.RegisterContentEvents(); Content.ModelChanged += new EventHandler(Content_ModelChanged); Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged); } protected override void DeregisterContentEvents() { base.DeregisterContentEvents(); Content.ModelChanged -= new EventHandler(Content_ModelChanged); Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged); } private void Content_ModelChanged(object sender, EventArgs e) { OnModelChanged(); } private void Content_ProblemDataChanged(object sender, EventArgs e) { OnProblemDataChanged(); } protected virtual void OnModelChanged() { this.UpdateView(); } protected virtual void OnProblemDataChanged() { this.UpdateView(); } protected override void OnContentChanged() { base.OnContentChanged(); this.UpdateView(); } private void UpdateView() { if (Content != null && Content.Model != null && Content.ProblemData != null) { var referencedVariables = (from varNode in Content.Model.SymbolicExpressionTree.IterateNodesPrefix().OfType() select varNode.VariableName) .Distinct() .OrderBy(x => x, new NaturalStringComparer()) .ToList(); medianValues.Clear(); foreach (var variableName in referencedVariables) { medianValues.Add(variableName, Content.ProblemData.Dataset.GetDoubleValues(variableName).Median()); } comboBox.Items.Clear(); comboBox.Items.AddRange(referencedVariables.ToArray()); comboBox.SelectedIndex = 0; } } private void CreateSliders(IEnumerable variableNames) { flowLayoutPanel.Controls.Clear(); foreach (var variableName in variableNames) { var variableTrackbar = new VariableTrackbar(variableName, Content.ProblemData.Dataset.GetDoubleValues(variableName)); variableTrackbar.Size = new Size(variableTrackbar.Size.Width, flowLayoutPanel.Size.Height - 23); variableTrackbar.ValueChanged += TrackBarValueChanged; flowLayoutPanel.Controls.Add(variableTrackbar); } } private void TrackBarValueChanged(object sender, EventArgs e) { var trackBar = (VariableTrackbar)sender; string variableName = trackBar.VariableName; ChangeVariableValue(variableName, trackBar.Value); } private void ChangeVariableValue(string variableName, double value) { foreach (var constNode in variableNodes[variableName].Cast()) constNode.Value = value; UpdateResponseSeries(); } private void UpdateScatterPlot() { string freeVariable = (string)comboBox.SelectedItem; IEnumerable fixedVariables = comboBox.Items.OfType() .Except(new string[] { freeVariable }); // scatter plots for subset of samples that have values near the median values for all variables Func NearMedianValue = (r) => { foreach (var fixedVar in fixedVariables) { double med = medianValues[fixedVar]; if (!(Content.ProblemData.Dataset.GetDoubleValue(fixedVar, r) < med + 0.1 * Math.Abs(med) && Content.ProblemData.Dataset.GetDoubleValue(fixedVar, r) > med - 0.1 * Math.Abs(med))) return false; } return true; }; var mainTrainingIndices = (from row in Content.ProblemData.TrainingIndices where NearMedianValue(row) select row) .ToArray(); var mainTestIndices = (from row in Content.ProblemData.TestIndices where NearMedianValue(row) select row) .ToArray(); var freeVariableValues = Content.ProblemData.Dataset.GetDoubleValues(freeVariable, mainTrainingIndices).ToArray(); var trainingValues = Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable, mainTrainingIndices).ToArray(); Array.Sort(freeVariableValues, trainingValues); responseChart.Series["Training Data"].Points.DataBindXY(freeVariableValues, trainingValues); freeVariableValues = Content.ProblemData.Dataset.GetDoubleValues(freeVariable, mainTestIndices).ToArray(); var testValues = Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable, mainTestIndices).ToArray(); Array.Sort(freeVariableValues, testValues); responseChart.Series["Test Data"].Points.DataBindXY(freeVariableValues, testValues); // draw scatter plots of remaining values freeVariableValues = Content.ProblemData.Dataset.GetDoubleValues(freeVariable, Content.ProblemData.TrainingIndices).ToArray(); trainingValues = Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable, Content.ProblemData.TrainingIndices).ToArray(); Array.Sort(freeVariableValues, trainingValues); responseChart.Series["Training Data (edge)"].Points.DataBindXY(freeVariableValues, trainingValues); freeVariableValues = Content.ProblemData.Dataset.GetDoubleValues(freeVariable, Content.ProblemData.TestIndices).ToArray(); testValues = Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable, Content.ProblemData.TestIndices).ToArray(); Array.Sort(freeVariableValues, testValues); responseChart.Series["Test Data (edge)"].Points.DataBindXY(freeVariableValues, testValues); responseChart.ChartAreas[0].AxisX.Maximum = Math.Ceiling(freeVariableValues.Max()); responseChart.ChartAreas[0].AxisX.Minimum = Math.Floor(freeVariableValues.Min()); responseChart.ChartAreas[0].AxisY.Maximum = Math.Ceiling(Math.Max(testValues.Max(), trainingValues.Max())); responseChart.ChartAreas[0].AxisY.Minimum = Math.Floor(Math.Min(testValues.Min(), trainingValues.Min())); } private void UpdateResponseSeries() { string freeVariable = (string)comboBox.SelectedItem; var freeVariableValues = Content.ProblemData.Dataset.GetDoubleValues(freeVariable, Content.ProblemData.TrainingIndices).ToArray(); var responseValues = Content.Model.Interpreter.GetSymbolicExpressionTreeValues(clonedTree, Content.ProblemData.Dataset, Content.ProblemData.TrainingIndices) .ToArray(); Array.Sort(freeVariableValues, responseValues); responseChart.Series["Model Response"].Points.DataBindXY(freeVariableValues, responseValues); } private void ComboBoxSelectedIndexChanged(object sender, EventArgs e) { string freeVariable = (string)comboBox.SelectedItem; IEnumerable fixedVariables = comboBox.Items.OfType() .Except(new string[] { freeVariable }); variableNodes.Clear(); clonedTree = (ISymbolicExpressionTree)Content.Model.SymbolicExpressionTree.Clone(); foreach (var varNode in clonedTree.IterateNodesPrefix().OfType()) { if (fixedVariables.Contains(varNode.VariableName)) { if (!variableNodes.ContainsKey(varNode.VariableName)) variableNodes.Add(varNode.VariableName, new List()); int childIndex = varNode.Parent.IndexOfSubtree(varNode); var replacementNode = MakeConstantTreeNode(medianValues[varNode.VariableName]); var parent = varNode.Parent; parent.RemoveSubtree(childIndex); parent.InsertSubtree(childIndex, MakeProduct(replacementNode, varNode.Weight)); variableNodes[varNode.VariableName].Add(replacementNode); } } CreateSliders(fixedVariables); UpdateScatterPlot(); UpdateResponseSeries(); } private ISymbolicExpressionTreeNode MakeProduct(ConstantTreeNode c, double weight) { var mul = new Multiplication(); var prod = mul.CreateTreeNode(); prod.AddSubtree(MakeConstantTreeNode(weight)); prod.AddSubtree(c); return prod; } private ConstantTreeNode MakeConstantTreeNode(double value) { Constant constant = new Constant(); constant.MinValue = value - 1; constant.MaxValue = value + 1; ConstantTreeNode constantTreeNode = (ConstantTreeNode)constant.CreateTreeNode(); constantTreeNode.Value = value; return constantTreeNode; } } }