Changeset 17687 for branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs
- Timestamp:
- 07/19/20 19:07:40 (4 years ago)
- Location:
- branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic
- Property svn:mergeinfo changed
-
branches/1837_Sliding Window GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs
r9708 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.Linq; 25 25 using System.Text; 26 using HEAL.Attic; 26 27 using HeuristicLab.Common; 27 28 using HeuristicLab.Core; 28 29 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; 29 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;30 30 31 31 namespace HeuristicLab.Problems.DataAnalysis.Symbolic { 32 32 [Item("LaTeX String Formatter", "Formatter for symbolic expression trees for import into LaTeX documents.")] 33 [Storable Class]33 [StorableType("D7186DFF-1596-4A58-B27D-974DF0D93E4F")] 34 34 public sealed class SymbolicDataAnalysisExpressionLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter { 35 private readonly List<double> constants; 35 private readonly List<KeyValuePair<string, double>> constants; 36 private int constIndex; 36 37 private int targetCount; 37 38 private int currentLag; 39 private string targetVariable; 40 private bool containsTimeSeriesSymbol; 38 41 39 42 [StorableConstructor] 40 private SymbolicDataAnalysisExpressionLatexFormatter( bool deserializing) : base(deserializing) { }43 private SymbolicDataAnalysisExpressionLatexFormatter(StorableConstructorFlag _) : base(_) { } 41 44 private SymbolicDataAnalysisExpressionLatexFormatter(SymbolicDataAnalysisExpressionLatexFormatter original, Cloner cloner) 42 45 : base(original, cloner) { 43 constants = new List<double>(original.constants); 46 constants = new List<KeyValuePair<string, double>>(original.constants); 47 constIndex = original.constIndex; 48 currentLag = original.currentLag; 49 targetCount = original.targetCount; 44 50 } 45 51 public SymbolicDataAnalysisExpressionLatexFormatter() … … 47 53 Name = ItemName; 48 54 Description = ItemDescription; 49 constants = new List< double>();55 constants = new List<KeyValuePair<string, double>>(); 50 56 } 51 57 … … 55 61 56 62 public string Format(ISymbolicExpressionTree symbolicExpressionTree) { 63 return Format(symbolicExpressionTree, null); 64 } 65 public string Format(ISymbolicExpressionTree symbolicExpressionTree, string targetVariable) { 57 66 try { 58 67 StringBuilder strBuilder = new StringBuilder(); 59 68 constants.Clear(); 69 constIndex = 0; 70 this.targetVariable = targetVariable; 71 containsTimeSeriesSymbol = symbolicExpressionTree.IterateNodesBreadth().Any(n => IsTimeSeriesSymbol(n.Symbol)); 60 72 strBuilder.AppendLine(FormatRecursively(symbolicExpressionTree.Root)); 61 73 return strBuilder.ToString(); 62 } 63 catch (NotImplementedException ex) { 74 } catch (NotImplementedException ex) { 64 75 return ex.Message + Environment.NewLine + ex.StackTrace; 65 76 } 77 } 78 static bool IsTimeSeriesSymbol(ISymbol s) { 79 return s is TimeLag || s is Integral || s is Derivative || s is LaggedVariable; 66 80 } 67 81 … … 75 89 } 76 90 int i = 1; 77 foreach ( SymbolicExpressionTreeNodesubTree in node.Subtrees.Skip(1)) {91 foreach (var subTree in node.Subtrees.Skip(1)) { 78 92 FormatSep(node, strBuilder, i); 79 93 // format the whole subtree … … 99 113 } else if (node.Symbol is Division) { 100 114 if (node.SubtreeCount == 1) { 101 strBuilder.Append(@" \cfrac{1 ");115 strBuilder.Append(@" \cfrac{1}{"); 102 116 } else { 103 117 strBuilder.Append(@" \cfrac{ "); 104 118 } 119 } else if (node.Symbol is Absolute) { 120 strBuilder.Append(@"\operatorname{abs} \left( "); 121 } else if (node.Symbol is AnalyticQuotient) { 122 strBuilder.Append(@" \frac { "); 105 123 } else if (node.Symbol is Average) { 106 124 // skip output of (1/1) if only one subtree … … 117 135 } else if (node.Symbol is SquareRoot) { 118 136 strBuilder.Append(@"\sqrt{"); 137 } else if (node.Symbol is Cube) { 138 strBuilder.Append(@"\left("); 139 } else if (node.Symbol is CubeRoot) { 140 strBuilder.Append(@"\operatorname{cbrt}\left("); 119 141 } else if (node.Symbol is Sine) { 120 142 strBuilder.Append(@"\sin \left( "); … … 123 145 } else if (node.Symbol is Tangent) { 124 146 strBuilder.Append(@"\tan \left( "); 147 } else if (node.Symbol is HyperbolicTangent) { 148 strBuilder.Append(@"\tanh \left( "); 125 149 } else if (node.Symbol is AiryA) { 126 150 strBuilder.Append(@"\operatorname{airy}_a \left( "); … … 166 190 strBuilder.Append(@" \operatorname{if} \left( "); 167 191 } else if (node.Symbol is Constant) { 168 strBuilder.Append("c_{" + constants.Count + "} "); 192 var constName = "c_{" + constIndex + "}"; 193 constIndex++; 169 194 var constNode = node as ConstantTreeNode; 170 constants.Add(constNode.Value); 195 if (constNode.Value.IsAlmost(1.0)) { 196 strBuilder.Append("1 "); 197 } else { 198 strBuilder.Append(constName); 199 constants.Add(new KeyValuePair<string, double>(constName, constNode.Value)); 200 } 201 202 } else if (node.Symbol is FactorVariable) { 203 var factorNode = node as FactorVariableTreeNode; 204 var constName = "c_{" + constIndex + "}"; 205 strBuilder.Append(constName + " "); 206 foreach (var e in factorNode.Symbol.GetVariableValues(factorNode.VariableName) 207 .Zip(factorNode.Weights, Tuple.Create)) { 208 constants.Add(new KeyValuePair<string, double>("c_{" + constIndex + ", " + EscapeLatexString(factorNode.VariableName) + "=" + EscapeLatexString(e.Item1) + "}", e.Item2)); 209 } 210 constIndex++; 211 } else if (node.Symbol is BinaryFactorVariable) { 212 var binFactorNode = node as BinaryFactorVariableTreeNode; 213 if (!binFactorNode.Weight.IsAlmost((1.0))) { 214 var constName = "c_{" + constIndex + "}"; 215 strBuilder.Append(constName + " \\cdot"); 216 constants.Add(new KeyValuePair<string, double>(constName, binFactorNode.Weight)); 217 constIndex++; 218 } 219 strBuilder.Append("(" + EscapeLatexString(binFactorNode.VariableName)); 220 strBuilder.Append(LagToString(currentLag)); 221 strBuilder.Append(" = " + EscapeLatexString(binFactorNode.VariableValue) + " )"); 171 222 } else if (node.Symbol is LaggedVariable) { 172 223 var laggedVarNode = node as LaggedVariableTreeNode; 173 224 if (!laggedVarNode.Weight.IsAlmost(1.0)) { 174 strBuilder.Append("c_{" + constants.Count + "} \\cdot "); 175 constants.Add(laggedVarNode.Weight); 225 var constName = "c_{" + constIndex + "}"; 226 strBuilder.Append(constName + " \\cdot"); 227 constants.Add(new KeyValuePair<string, double>(constName, laggedVarNode.Weight)); 228 constIndex++; 176 229 } 177 230 strBuilder.Append(EscapeLatexString(laggedVarNode.VariableName)); … … 181 234 var varNode = node as VariableTreeNode; 182 235 if (!varNode.Weight.IsAlmost((1.0))) { 183 strBuilder.Append("c_{" + constants.Count + "} \\cdot "); 184 constants.Add(varNode.Weight); 236 var constName = "c_{" + constIndex + "}"; 237 strBuilder.Append(constName + " \\cdot"); 238 constants.Add(new KeyValuePair<string, double>(constName, varNode.Weight)); 239 constIndex++; 185 240 } 186 241 strBuilder.Append(EscapeLatexString(varNode.VariableName)); … … 197 252 strBuilder.Append(invokeNode.Symbol.FunctionName + @" \left( "); 198 253 } else if (node.Symbol is StartSymbol) { 199 strBuilder.Append("target_" + (targetCount++) + "(t) & = ");254 FormatStartSymbol(strBuilder); 200 255 } else if (node.Symbol is Argument) { 201 256 var argSym = node.Symbol as Argument; … … 216 271 } else if (node.Symbol is VariableCondition) { 217 272 var conditionTreeNode = node as VariableConditionTreeNode; 218 string p = @"1 / 1 + \exp - c_{" + constants.Count + "} "; 219 constants.Add(conditionTreeNode.Slope); 220 p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - c_{" + constants.Count + @"} "; 221 constants.Add(conditionTreeNode.Threshold); 273 var constName = "c_{" + constants.Count + "}"; 274 string p = @"1 / 1 + \exp - " + constName + " "; 275 constants.Add(new KeyValuePair<string, double>(constName, conditionTreeNode.Slope)); 276 constIndex++; 277 var const2Name = "c_{" + constants.Count + @"}"; 278 p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - " + const2Name + " "; 279 constants.Add(new KeyValuePair<string, double>(const2Name, conditionTreeNode.Threshold)); 280 constIndex++; 222 281 strBuilder.Append(@" \left( " + p + @"\cdot "); 223 282 } else { … … 238 297 else 239 298 strBuilder.Append(@" }{ \cfrac{ "); 299 } else if (node.Symbol is Absolute) { 300 throw new InvalidOperationException(); 301 } else if (node.Symbol is AnalyticQuotient) { 302 strBuilder.Append(@"}{\sqrt{1 + \left( "); 240 303 } else if (node.Symbol is Average) { 241 304 strBuilder.Append(@" + "); … … 248 311 } else if (node.Symbol is SquareRoot) { 249 312 throw new InvalidOperationException(); 313 } else if (node.Symbol is Cube) { 314 throw new InvalidOperationException(); 315 } else if (node.Symbol is CubeRoot) { 316 throw new InvalidOperationException(); 250 317 } else if (node.Symbol is Sine) { 251 318 throw new InvalidOperationException(); … … 253 320 throw new InvalidOperationException(); 254 321 } else if (node.Symbol is Tangent) { 322 throw new InvalidOperationException(); 323 } else if (node.Symbol is HyperbolicTangent) { 255 324 throw new InvalidOperationException(); 256 325 } else if (node.Symbol is AiryA) { … … 303 372 } else if (node.Symbol is StartSymbol) { 304 373 strBuilder.Append(@"\\" + Environment.NewLine); 305 strBuilder.Append("target_" + (targetCount++) + "(t) & = ");374 FormatStartSymbol(strBuilder); 306 375 } else if (node.Symbol is Power) { 307 376 strBuilder.Append(@"\right) ^ { \operatorname{round} \left("); … … 310 379 } else if (node.Symbol is VariableCondition) { 311 380 var conditionTreeNode = node as VariableConditionTreeNode; 312 string p = @"1 / \left( 1 + \exp \left( - c_{" + constants.Count + "} "; 313 constants.Add(conditionTreeNode.Slope); 314 p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - c_{" + constants.Count + @"} \right) \right) \right) "; 315 constants.Add(conditionTreeNode.Threshold); 381 var const1Name = "c_{" + constants.Count + "}"; 382 string p = @"1 / \left( 1 + \exp \left( - " + const1Name + " "; 383 constants.Add(new KeyValuePair<string, double>(const1Name, conditionTreeNode.Slope)); 384 constIndex++; 385 var const2Name = "c_{" + constants.Count + "}"; 386 p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - " + const2Name + " \right) \right) \right) "; 387 constants.Add(new KeyValuePair<string, double>(const2Name, conditionTreeNode.Threshold)); 388 constIndex++; 316 389 strBuilder.Append(@" + \left( 1 - " + p + @" \right) \cdot "); 317 390 } else { … … 330 403 for (int i = 2; i < node.SubtreeCount; i++) 331 404 strBuilder.Append(" } "); 405 } else if (node.Symbol is Absolute) { 406 strBuilder.Append(@" \right)"); 407 } else if (node.Symbol is AnalyticQuotient) { 408 strBuilder.Append(@" \right)^2}}"); 332 409 } else if (node.Symbol is Average) { 333 410 strBuilder.Append(@" \right) "); … … 340 417 } else if (node.Symbol is SquareRoot) { 341 418 strBuilder.Append(@"}"); 419 } else if (node.Symbol is Cube) { 420 strBuilder.Append(@"\right)^3"); 421 } else if (node.Symbol is CubeRoot) { 422 strBuilder.Append(@"\right)"); 342 423 } else if (node.Symbol is Sine) { 343 424 strBuilder.Append(@" \right) "); … … 345 426 strBuilder.Append(@" \right) "); 346 427 } else if (node.Symbol is Tangent) { 428 strBuilder.Append(@" \right) "); 429 } else if (node.Symbol is HyperbolicTangent) { 347 430 strBuilder.Append(@" \right) "); 348 431 } else if (node.Symbol is AiryA) { … … 391 474 } else if (node.Symbol is LaggedVariable) { 392 475 } else if (node.Symbol is Variable) { 476 } else if (node.Symbol is FactorVariable) { 477 } else if (node.Symbol is BinaryFactorVariable) { 393 478 } else if (node.Symbol is ProgramRootSymbol) { 394 479 strBuilder … … 398 483 // output all constant values 399 484 if (constants.Count > 0) { 400 int i = 0;401 485 foreach (var constant in constants) { 402 486 // replace "." with ".&" to align decimal points 403 var constStr = string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:G5}", constant );487 var constStr = string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:G5}", constant.Value); 404 488 if (!constStr.Contains(".")) constStr = constStr + ".0"; 405 constStr = constStr.Replace(".", " \\negthickspace&."); // fix problem in rendering of aligned expressions406 strBuilder.Append( "c_{" + i + "}& = & " + constStr);489 constStr = constStr.Replace(".", "&."); // fix problem in rendering of aligned expressions 490 strBuilder.Append(constant.Key + "& = & " + constStr); 407 491 strBuilder.Append(@"\\"); 408 i++;409 492 } 410 493 } … … 433 516 } 434 517 518 private void FormatStartSymbol(StringBuilder strBuilder) { 519 strBuilder.Append(targetVariable ?? "target_" + (targetCount++)); 520 if (containsTimeSeriesSymbol) 521 strBuilder.Append("(t)"); 522 strBuilder.Append(" & = "); 523 } 524 435 525 private string LagToString(int lag) { 436 526 if (lag < 0) {
Note: See TracChangeset
for help on using the changeset viewer.