Changeset 17687 for branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs
- Timestamp:
- 07/19/20 19:07:40 (4 years ago)
- Location:
- branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Views
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Views
- Property svn:mergeinfo changed
-
branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs
r10681 r17687 1 1 #region License Information 2 2 /* HeuristicLab 3 * Copyright (C) 2002-2013Heuristic and Evolutionary Algorithms Laboratory (HEAL)3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL) 4 4 * 5 5 * This file is part of HeuristicLab. … … 24 24 using System.Drawing; 25 25 using System.Linq; 26 using System.Threading; 27 using System.Threading.Tasks; 26 28 using System.Windows.Forms; 27 29 using HeuristicLab.Common; 28 30 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; 29 31 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views; 32 using HeuristicLab.MainForm; 30 33 using HeuristicLab.MainForm.WindowsForms; 31 34 32 35 namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views { 33 36 public abstract partial class InteractiveSymbolicDataAnalysisSolutionSimplifierView : AsynchronousContentView { 34 private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> foldedNodes; 35 private Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts; 37 private readonly Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); 38 private readonly Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> changedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); 39 private readonly Dictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>(); 40 private readonly Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>(); 41 42 private readonly ISymbolicDataAnalysisSolutionImpactValuesCalculator impactCalculator; 43 44 private readonly Progress progress = new Progress(); 45 private CancellationTokenSource cancellationTokenSource; 46 36 47 private enum TreeState { Valid, Invalid } 37 38 public InteractiveSymbolicDataAnalysisSolutionSimplifierView() { 48 private TreeState treeState; 49 50 protected InteractiveSymbolicDataAnalysisSolutionSimplifierView(ISymbolicDataAnalysisSolutionImpactValuesCalculator impactCalculator) { 39 51 InitializeComponent(); 40 foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();41 nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>();42 52 this.Caption = "Interactive Solution Simplifier"; 53 this.impactCalculator = impactCalculator; 54 55 // initialize the tree modifier that will be used to perform edit operations over the tree 56 treeChart.ModifyTree = Modify; 57 } 58 59 /// <summary> 60 /// Remove, Replace or Insert subtrees 61 /// </summary> 62 /// <param name="tree">The symbolic expression tree</param> 63 /// <param name="parent">The insertion point (ie, the parent node who will receive a new child)</param> 64 /// <param name="oldChild">The subtree to be replaced</param> 65 /// <param name="newChild">The replacement subtree</param> 66 /// <param name="removeSubtree">Flag used to indicate if whole subtrees should be removed (default behavior), or just the subtree root</param> 67 private void Modify(ISymbolicExpressionTree tree, ISymbolicExpressionTreeNode parent, 68 ISymbolicExpressionTreeNode oldChild, ISymbolicExpressionTreeNode newChild, bool removeSubtree = true) { 69 if (oldChild == null && newChild == null) 70 throw new ArgumentNullException("Cannot deduce operation type from the arguments. Please provide non null operands."); 71 if (oldChild == null) { 72 // insertion operation 73 parent.AddSubtree(newChild); 74 newChild.Parent = parent; 75 } else if (newChild == null) { 76 // removal operation 77 parent.RemoveSubtree(parent.IndexOfSubtree(oldChild)); 78 if (!removeSubtree) { 79 for (int i = oldChild.SubtreeCount - 1; i >= 0; --i) { 80 var subtree = oldChild.GetSubtree(i); 81 oldChild.RemoveSubtree(i); 82 parent.AddSubtree(subtree); 83 } 84 } 85 } else { 86 // replacement operation 87 var replacementIndex = parent.IndexOfSubtree(oldChild); 88 parent.RemoveSubtree(replacementIndex); 89 parent.InsertSubtree(replacementIndex, newChild); 90 newChild.Parent = parent; 91 if (changedNodes.ContainsKey(oldChild)) { 92 changedNodes.Add(newChild, changedNodes[oldChild]); // so that on double click the original node is restored 93 changedNodes.Remove(oldChild); 94 } else { 95 changedNodes.Add(newChild, oldChild); 96 } 97 } 98 treeState = IsValid(tree) ? TreeState.Valid : TreeState.Invalid; 99 switch (treeState) { 100 case TreeState.Valid: 101 this.grpViewHost.Enabled = true; 102 UpdateModel(Content.Model.SymbolicExpressionTree); 103 break; 104 case TreeState.Invalid: 105 this.grpViewHost.Enabled = false; 106 break; 107 } 108 } 109 110 // the optimizer always assumes 2 children for multiplication and addition nodes 111 // thus, we enforce that the tree stays valid so that the constant optimization won't throw an exception 112 // by returning 2 as the minimum allowed arity for addition and multiplication symbols 113 private readonly Func<ISymbol, int> GetMinArity = symbol => { 114 var min = symbol.MinimumArity; 115 if (symbol is Multiplication || symbol is Division) return Math.Max(2, min); 116 return min; 117 }; 118 private bool IsValid(ISymbolicExpressionTree tree) { 119 treeChart.Tree = tree; 120 treeChart.Repaint(); 121 // check if all nodes have a legal arity 122 var nodes = tree.IterateNodesPostfix().ToList(); 123 bool valid = !nodes.Any(node => node.SubtreeCount < GetMinArity(node.Symbol) || node.SubtreeCount > node.Symbol.MaximumArity); 124 125 if (valid) { 126 // check if all variables are contained in the dataset 127 var variables = new HashSet<string>(Content.ProblemData.Dataset.DoubleVariables); 128 valid = nodes.OfType<VariableTreeNode>().All(x => variables.Contains(x.VariableName)); 129 } 130 131 if (valid) { 132 btnOptimizeConstants.Enabled = true; 133 btnSimplify.Enabled = true; 134 treeStatusValue.Visible = false; 135 } else { 136 btnOptimizeConstants.Enabled = false; 137 btnSimplify.Enabled = false; 138 treeStatusValue.Visible = true; 139 } 140 this.Refresh(); 141 return valid; 43 142 } 44 143 … … 53 152 Content.ProblemDataChanged += Content_Changed; 54 153 treeChart.Repainted += treeChart_Repainted; 154 Progress.ShowOnControl(grpSimplify, progress); 155 progress.StopRequested += progress_StopRequested; 55 156 } 56 157 protected override void DeregisterContentEvents() { … … 59 160 Content.ProblemDataChanged -= Content_Changed; 60 161 treeChart.Repainted -= treeChart_Repainted; 162 Progress.HideFromControl(grpSimplify, false); 163 progress.StopRequested -= progress_StopRequested; 61 164 } 62 165 63 166 private void Content_Changed(object sender, EventArgs e) { 64 167 UpdateView(); 168 SetEnabledStateOfControls(); 65 169 } 66 170 67 171 protected override void OnContentChanged() { 68 172 base.OnContentChanged(); 69 foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); 173 foldedNodes.Clear(); 174 changedNodes.Clear(); 175 nodeIntervals.Clear(); 176 nodeImpacts.Clear(); 70 177 UpdateView(); 71 178 viewHost.Content = this.Content; … … 77 184 } 78 185 79 private void UpdateView() { 186 private void progress_StopRequested(object sender, EventArgs e) { 187 cancellationTokenSource.Cancel(); 188 } 189 190 private async void UpdateView() { 80 191 if (Content == null || Content.Model == null || Content.ProblemData == null) return; 81 192 var tree = Content.Model.SymbolicExpressionTree; 82 193 treeChart.Tree = tree.Root.SubtreeCount > 1 ? new SymbolicExpressionTree(tree.Root) : new SymbolicExpressionTree(tree.Root.GetSubtree(0).GetSubtree(0)); 83 194 84 var impactAndReplacementValues = CalculateImpactAndReplacementValues(tree); 85 nodeImpacts = impactAndReplacementValues.ToDictionary(x => x.Key, x => x.Value.Item1); 86 var replacementValues = impactAndReplacementValues.ToDictionary(x => x.Key, x => x.Value.Item2); 87 foreach (var pair in replacementValues.Where(pair => !(pair.Key is ConstantTreeNode))) { 88 foldedNodes[pair.Key] = MakeConstantTreeNode(pair.Value); 89 } 195 progress.Start("Calculate Impact and Replacement Values ..."); 196 cancellationTokenSource = new CancellationTokenSource(); 197 progress.CanBeStopped = true; 198 try { 199 var impactAndReplacementValues = await Task.Run(() => CalculateImpactAndReplacementValues(tree)); 200 try { 201 await Task.Delay(300, cancellationTokenSource.Token); // wait for progressbar to finish animation 202 } catch (OperationCanceledException) { } 203 204 var replacementValues = impactAndReplacementValues.ToDictionary(x => x.Key, x => x.Value.Item2); 205 foreach (var pair in replacementValues.Where(pair => !(pair.Key is ConstantTreeNode))) { 206 foldedNodes[pair.Key] = MakeConstantTreeNode(pair.Value); 207 } 208 209 foreach (var pair in impactAndReplacementValues) { 210 nodeImpacts[pair.Key] = pair.Value.Item1; 211 } 212 213 if (IntervalInterpreter.IsCompatible(tree)) { 214 var regressionProblemData = Content.ProblemData as IRegressionProblemData; 215 if (regressionProblemData != null) { 216 var interpreter = new IntervalInterpreter(); 217 var variableRanges = regressionProblemData.VariableRanges.GetReadonlyDictionary(); 218 IDictionary<ISymbolicExpressionTreeNode, Interval> intervals; 219 interpreter.GetSymbolicExpressionTreeIntervals(tree, variableRanges, out intervals); 220 foreach (var kvp in intervals) { 221 nodeIntervals[kvp.Key] = kvp.Value; 222 } 223 } 224 } 225 } finally { 226 progress.Finish(); 227 } 228 229 progress.CanBeStopped = false; 90 230 PaintNodeImpacts(); 91 231 } 92 232 93 protected abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateReplacementValues(ISymbolicExpressionTree tree); 94 protected abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateImpactValues(ISymbolicExpressionTree tree); 95 protected abstract Dictionary<ISymbolicExpressionTreeNode, Tuple<double, double>> CalculateImpactAndReplacementValues(ISymbolicExpressionTree tree); 233 protected virtual Dictionary<ISymbolicExpressionTreeNode, Tuple<double, double>> CalculateImpactAndReplacementValues(ISymbolicExpressionTree tree) { 234 var impactAndReplacementValues = new Dictionary<ISymbolicExpressionTreeNode, Tuple<double, double>>(); 235 foreach (var node in tree.Root.GetSubtree(0).GetSubtree(0).IterateNodesPrefix()) { 236 if (progress.ProgressState == ProgressState.StopRequested) continue; 237 double impactValue, replacementValue, newQualityForImpactsCalculation; 238 impactCalculator.CalculateImpactAndReplacementValues(Content.Model, node, Content.ProblemData, Content.ProblemData.TrainingIndices, out impactValue, out replacementValue, out newQualityForImpactsCalculation); 239 double newProgressValue = progress.ProgressValue + 1.0 / (tree.Length - 2); 240 progress.ProgressValue = Math.Min(newProgressValue, 1); 241 impactAndReplacementValues.Add(node, new Tuple<double, double>(impactValue, replacementValue)); 242 } 243 return impactAndReplacementValues; 244 } 245 96 246 protected abstract void UpdateModel(ISymbolicExpressionTree tree); 247 248 protected virtual ISymbolicExpressionTree OptimizeConstants(ISymbolicExpressionTree tree, IProgress progress) { 249 return tree; 250 } 97 251 98 252 private static ConstantTreeNode MakeConstantTreeNode(double value) { … … 104 258 105 259 private void treeChart_SymbolicExpressionTreeNodeDoubleClicked(object sender, MouseEventArgs e) { 260 if (treeState == TreeState.Invalid) return; 106 261 var visualNode = (VisualTreeNode<ISymbolicExpressionTreeNode>)sender; 262 if (visualNode.Content == null) { throw new Exception("VisualNode content cannot be null."); } 107 263 var symbExprTreeNode = (SymbolicExpressionTreeNode)visualNode.Content; 108 if (symbExprTreeNode == null) return;109 264 var tree = Content.Model.SymbolicExpressionTree; 110 265 var parent = symbExprTreeNode.Parent; 111 266 int indexOfSubtree = parent.IndexOfSubtree(symbExprTreeNode); 112 if (foldedNodes.ContainsKey(symbExprTreeNode)) { 267 if (changedNodes.ContainsKey(symbExprTreeNode)) { 268 // undo node change 269 parent.RemoveSubtree(indexOfSubtree); 270 var originalNode = changedNodes[symbExprTreeNode]; 271 parent.InsertSubtree(indexOfSubtree, originalNode); 272 changedNodes.Remove(symbExprTreeNode); 273 } else if (foldedNodes.ContainsKey(symbExprTreeNode)) { 113 274 // undo node folding 114 275 SwitchNodeWithReplacementNode(parent, indexOfSubtree); … … 119 280 private void SwitchNodeWithReplacementNode(ISymbolicExpressionTreeNode parent, int subTreeIndex) { 120 281 ISymbolicExpressionTreeNode subTree = parent.GetSubtree(subTreeIndex); 121 parent.RemoveSubtree(subTreeIndex);122 282 if (foldedNodes.ContainsKey(subTree)) { 283 parent.RemoveSubtree(subTreeIndex); 123 284 var replacementNode = foldedNodes[subTree]; 124 285 parent.InsertSubtree(subTreeIndex, replacementNode); … … 133 294 double max = impacts.Max(); 134 295 double min = impacts.Min(); 135 foreach ( vartreeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) {296 foreach (ISymbolicExpressionTreeNode treeNode in Content.Model.SymbolicExpressionTree.IterateNodesPostfix()) { 136 297 VisualTreeNode<ISymbolicExpressionTreeNode> visualTree = treeChart.GetVisualSymbolicExpressionTreeNode(treeNode); 137 298 138 299 if (!(treeNode is ConstantTreeNode) && nodeImpacts.ContainsKey(treeNode)) { 300 visualTree.ToolTip = visualTree.Content.ToString(); 139 301 double impact = nodeImpacts[treeNode]; 140 302 … … 157 319 } 158 320 } 159 if (visualTree != null) 160 if (treeNode is ConstantTreeNode && foldedNodes.ContainsKey(treeNode)) { 321 if (visualTree != null) { 322 if (nodeIntervals.ContainsKey(treeNode)) 323 visualTree.ToolTip += String.Format($"{Environment.NewLine}Intervals: [{nodeIntervals[treeNode].LowerBound:G5} ... {nodeIntervals[treeNode].UpperBound:G5}]"); 324 if (changedNodes.ContainsKey(treeNode)) { 325 visualTree.LineColor = Color.DodgerBlue; 326 } else if (treeNode is ConstantTreeNode && foldedNodes.ContainsKey(treeNode)) { 161 327 visualTree.LineColor = Color.DarkOrange; 162 328 } 329 } 163 330 } 164 331 treeChart.RepaintNodes(); … … 166 333 167 334 private void btnSimplify_Click(object sender, EventArgs e) { 168 var simplifier = new SymbolicDataAnalysisExpressionTreeSimplifier(); 169 var simplifiedExpressionTree = simplifier.Simplify(Content.Model.SymbolicExpressionTree); 335 var simplifiedExpressionTree = TreeSimplifier.Simplify(Content.Model.SymbolicExpressionTree); 170 336 UpdateModel(simplifiedExpressionTree); 171 337 } 172 338 173 protected abstract void btnOptimizeConstants_Click(object sender, EventArgs e); 339 private async void btnOptimizeConstants_Click(object sender, EventArgs e) { 340 progress.Start("Optimizing Constants ..."); 341 cancellationTokenSource = new CancellationTokenSource(); 342 progress.CanBeStopped = true; 343 try { 344 var tree = (ISymbolicExpressionTree)Content.Model.SymbolicExpressionTree.Clone(); 345 346 var newTree = await Task.Run(() => OptimizeConstants(tree, progress)); 347 try { 348 await Task.Delay(300, cancellationTokenSource.Token); // wait for progressbar to finish animation 349 } catch (OperationCanceledException) { } 350 UpdateModel(newTree); // triggers progress.Finish after calculating the node impacts when model is changed 351 } catch { 352 progress.Finish(); 353 } 354 } 174 355 } 175 356 }
Note: See TracChangeset
for help on using the changeset viewer.