Changeset 17825 for branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters
- Timestamp:
- 01/27/21 14:10:56 (4 years ago)
- Location:
- branches/3040_VectorBasedGP
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3040_VectorBasedGP
- Property svn:mergeinfo changed
-
branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic
- Property svn:mergeinfo changed
-
branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs
r17622 r17825 21 21 22 22 using System; 23 using System.Collections.Generic; 23 24 using System.Globalization; 24 25 using System.Linq; 25 26 using System.Text; 27 using HEAL.Attic; 26 28 using HeuristicLab.Common; 27 29 using HeuristicLab.Core; 28 30 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; 29 using HEAL.Attic;30 31 31 32 using DoubleVector = MathNet.Numerics.LinearAlgebra.Vector<double>; 32 33 33 34 namespace HeuristicLab.Problems.DataAnalysis.Symbolic { 35 public static class BaseInfixExpressionFormatter { 36 public static void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder, 37 NumberFormatInfo numberFormat, string formatString, List<KeyValuePair<string, double>> constants = null) { 38 if (node.SubtreeCount > 1) { 39 var token = GetToken(node.Symbol); 40 // operators 41 if (token == "+" || token == "-" || token == "OR" || token == "XOR" || 42 token == "*" || token == "/" || token == "AND") { 43 strBuilder.Append("("); 44 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants); 45 46 foreach (var subtree in node.Subtrees.Skip(1)) { 47 strBuilder.Append(" ").Append(token).Append(" "); 48 FormatRecursively(subtree, strBuilder, numberFormat, formatString, constants); 49 } 50 51 strBuilder.Append(")"); 52 } else if (token == "^") { 53 // handle integer powers directly 54 strBuilder.Append("("); 55 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants); 56 57 var power = node.GetSubtree(1); 58 if (power is ConstantTreeNode constNode && Math.Truncate(constNode.Value) == constNode.Value) { 59 strBuilder.Append(" ").Append(token).Append(" ").Append(constNode.Value.ToString(formatString, numberFormat)); 60 } else { 61 strBuilder.Append(" ").Append(token).Append(" "); 62 FormatRecursively(power, strBuilder, numberFormat, formatString, constants); 63 } 64 65 strBuilder.Append(")"); 66 } else { 67 // function with multiple arguments 68 strBuilder.Append(token).Append("("); 69 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants); 70 foreach (var subtree in node.Subtrees.Skip(1)) { 71 strBuilder.Append(", "); 72 FormatRecursively(subtree, strBuilder, numberFormat, formatString, constants); 73 } 74 75 strBuilder.Append(")"); 76 } 77 } else if (node.SubtreeCount == 1) { 78 var token = GetToken(node.Symbol); 79 if (token == "-" || token == "NOT") { 80 strBuilder.Append("(").Append(token).Append("("); 81 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants); 82 strBuilder.Append("))"); 83 } else if (token == "/") { 84 strBuilder.Append("1/"); 85 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants); 86 } else if (token == "+" || token == "*") { 87 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants); 88 } else { 89 // function with only one argument 90 strBuilder.Append(token).Append("("); 91 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants); 92 strBuilder.Append(")"); 93 } 94 } else { 95 // no subtrees 96 if (node.Symbol is LaggedVariable) { 97 var varNode = node as LaggedVariableTreeNode; 98 if (!varNode.Weight.IsAlmost(1.0)) { 99 strBuilder.Append("("); 100 AppendConstant(strBuilder, constants, varNode.Weight, formatString, numberFormat); 101 strBuilder.Append("*"); 102 } 103 104 strBuilder.Append("LAG("); 105 AppendVariableName(strBuilder, varNode.VariableName); 106 strBuilder.Append(", ") 107 .AppendFormat(numberFormat, "{0}", varNode.Lag) 108 .Append(")"); 109 if (!varNode.Weight.IsAlmost(1.0)) strBuilder.Append(")"); 110 } else if (node.Symbol is Variable) { 111 var varNode = node as VariableTreeNode; 112 if (!varNode.Weight.IsAlmost(1.0)) { 113 strBuilder.Append("("); 114 AppendConstant(strBuilder, constants, varNode.Weight, formatString, numberFormat); 115 strBuilder.Append("*"); 116 } 117 AppendVariableName(strBuilder, varNode.VariableName); 118 if (varNode.DataType == typeof(DoubleVector)) strBuilder.Append("{}"); 119 if (!varNode.Weight.IsAlmost(1.0)) strBuilder.Append(")"); 120 } else if (node.Symbol is FactorVariable) { 121 var factorNode = node as FactorVariableTreeNode; 122 AppendVariableName(strBuilder, factorNode.VariableName); 123 124 strBuilder.Append("["); 125 for (int i = 0; i < factorNode.Weights.Length; i++) { 126 if (i > 0) strBuilder.Append(", "); 127 AppendConstant(strBuilder, constants, factorNode.Weights[i], formatString, numberFormat); 128 } 129 strBuilder.Append("]"); 130 } else if (node.Symbol is BinaryFactorVariable) { 131 var factorNode = node as BinaryFactorVariableTreeNode; 132 if (!factorNode.Weight.IsAlmost(1.0)) { 133 strBuilder.Append("("); 134 AppendConstant(strBuilder, constants, factorNode.Weight, formatString, numberFormat); 135 136 strBuilder.Append("*"); 137 } 138 139 AppendVariableName(strBuilder, factorNode.VariableName); 140 strBuilder.Append(" = "); 141 AppendVariableName(strBuilder, factorNode.VariableValue); 142 143 if (!factorNode.Weight.IsAlmost(1.0)) strBuilder.Append(")"); 144 } else if (node.Symbol is Constant) { 145 var constNode = node as ConstantTreeNode; 146 if (constants == null && constNode.Value < 0) { 147 strBuilder.Append("(").Append(constNode.Value.ToString(formatString, numberFormat)) 148 .Append(")"); // (-1 149 } else { 150 AppendConstant(strBuilder, constants, constNode.Value, formatString, numberFormat); 151 } 152 } 153 } 154 } 155 156 private static void AppendConstant(StringBuilder strBuilder, List<KeyValuePair<string, double>> constants, double value, string formatString, NumberFormatInfo numberFormat) { 157 if (constants != null) { 158 string constantKey = $"c_{constants.Count}"; 159 strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", constantKey); 160 constants.Add(new KeyValuePair<string, double>(constantKey, value)); 161 } else { 162 strBuilder.Append(value.ToString(formatString, numberFormat)); 163 } 164 } 165 166 private static void AppendVariableName(StringBuilder strBuilder, string name) { 167 if (name.Contains("'")) 168 strBuilder.AppendFormat("\"{0}\"", name); 169 else 170 strBuilder.AppendFormat("'{0}'", name); 171 } 172 173 private static string GetToken(ISymbol symbol) { 174 var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).FirstOrDefault(); 175 if (tok == null) 176 throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name)); 177 return tok; 178 } 179 } 180 34 181 /// <summary> 35 182 /// Formats mathematical expressions in infix form. E.g. x1 * (3.0 * x2 + x3) 36 183 /// </summary> 37 184 [StorableType("6FE2C83D-A594-4ABF-B101-5AEAEA6D3E3D")] 38 [Item("Infix Symbolic Expression Tree Formatter", "A string formatter that converts symbolic expression trees to infix expressions.")]39 185 [Item("Infix Symbolic Expression Tree Formatter", 186 "A string formatter that converts symbolic expression trees to infix expressions.")] 40 187 public sealed class InfixExpressionFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter { 41 42 43 188 [StorableConstructor] 44 189 private InfixExpressionFormatter(StorableConstructorFlag _) : base(_) { } 190 45 191 private InfixExpressionFormatter(InfixExpressionFormatter original, Cloner cloner) : base(original, cloner) { } 192 46 193 public InfixExpressionFormatter() 47 194 : base() { … … 49 196 Description = ItemDescription; 50 197 } 198 51 199 public override IDeepCloneable Clone(Cloner cloner) { 52 200 return new InfixExpressionFormatter(this, cloner); … … 60 208 /// <param name="formatString">The format string for numeric parameters (e.g. \"G4\" to limit to 4 digits, default is \"G\")</param> 61 209 /// <returns>Infix expression</returns> 62 public string Format(ISymbolicExpressionTree symbolicExpressionTree, NumberFormatInfo numberFormat, string formatString = "G") { 210 public string Format(ISymbolicExpressionTree symbolicExpressionTree, NumberFormatInfo numberFormat, 211 string formatString = "G") { 63 212 // skip root and start symbols 64 213 StringBuilder strBuilder = new StringBuilder(); 65 FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), strBuilder, numberFormat, formatString); 214 BaseInfixExpressionFormatter.FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), 215 strBuilder, numberFormat, formatString); 66 216 return strBuilder.ToString(); 67 217 } … … 70 220 return Format(symbolicExpressionTree, NumberFormatInfo.InvariantInfo); 71 221 } 72 73 private static void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder, NumberFormatInfo numberFormat, string formatString) { 74 if (node.SubtreeCount > 1) { 75 var token = GetToken(node.Symbol); 76 // operators 77 if (token == "+" || token == "-" || token == "OR" || token == "XOR" || 78 token == "*" || token == "/" || token == "AND" || 79 token == "^") { 80 strBuilder.Append("("); 81 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString); 82 83 foreach (var subtree in node.Subtrees.Skip(1)) { 84 strBuilder.Append(" ").Append(token).Append(" "); 85 FormatRecursively(subtree, strBuilder, numberFormat, formatString); 86 } 87 strBuilder.Append(")"); 88 } else { 89 // function with multiple arguments 90 strBuilder.Append(token).Append("("); 91 FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString); 92 foreach (var subtree in node.Subtrees.Skip(1)) { 93 strBuilder.Append(", "); 94 FormatRecursively(subtree, strBuilder, numberFormat, formatString); 95 } 96 strBuilder.Append(")"); 97 } 98 } else if (node.SubtreeCount == 1) { 99 var token = GetToken(node.Symbol); 100 if (token == "-" || token == "NOT") { 101 strBuilder.Append("(").Append(token).Append("("); 102 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString); 103 strBuilder.Append("))"); 104 } else if (token == "/") { 105 strBuilder.Append("1/"); 106 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString); 107 } else if (token == "+" || token == "*") { 108 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString); 109 } else { 110 // function with only one argument 111 strBuilder.Append(token).Append("("); 112 FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString); 113 strBuilder.Append(")"); 114 } 115 } else { 116 // no subtrees 117 if (node.Symbol is LaggedVariable) { 118 var varNode = node as LaggedVariableTreeNode; 119 if (!varNode.Weight.IsAlmost(1.0)) { 120 strBuilder.Append("("); 121 strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat)); 122 strBuilder.Append("*"); 123 } 124 strBuilder.Append("LAG("); 125 if (varNode.VariableName.Contains("'")) { 126 strBuilder.AppendFormat("\"{0}\"", varNode.VariableName); 127 } else { 128 strBuilder.AppendFormat("'{0}'", varNode.VariableName); 129 } 130 strBuilder.Append(", ") 131 .AppendFormat(numberFormat, "{0}", varNode.Lag) 132 .Append(")"); 133 } else if (node.Symbol is Variable) { 134 var varNode = node as VariableTreeNode; 135 if (!varNode.Weight.IsAlmost(1.0)) { 136 strBuilder.Append("("); 137 strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat)); 138 strBuilder.Append("*"); 139 } 140 if (varNode.VariableName.Contains("'")) { 141 strBuilder.AppendFormat("\"{0}\"", varNode.VariableName); 142 } else { 143 strBuilder.AppendFormat("'{0}'", varNode.VariableName); 144 } 145 if (varNode.DataType == typeof(DoubleVector)) 146 strBuilder.Append("{}"); 147 if (!varNode.Weight.IsAlmost(1.0)) { 148 strBuilder.Append(")"); 149 } 150 } else if (node.Symbol is FactorVariable) { 151 var factorNode = node as FactorVariableTreeNode; 152 if (factorNode.VariableName.Contains("'")) { 153 strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName); 154 } else { 155 strBuilder.AppendFormat("'{0}'", factorNode.VariableName); 156 } 157 strBuilder.AppendFormat("[{0}]", 158 string.Join(", ", factorNode.Weights.Select(w => w.ToString(formatString, numberFormat)))); 159 } else if (node.Symbol is BinaryFactorVariable) { 160 var factorNode = node as BinaryFactorVariableTreeNode; 161 if (!factorNode.Weight.IsAlmost(1.0)) { 162 strBuilder.Append("("); 163 strBuilder.Append(factorNode.Weight.ToString(formatString, numberFormat)); 164 strBuilder.Append("*"); 165 } 166 if (factorNode.VariableName.Contains("'")) { 167 strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName); 168 } else { 169 strBuilder.AppendFormat("'{0}'", factorNode.VariableName); 170 } 171 strBuilder.Append(" = "); 172 if (factorNode.VariableValue.Contains("'")) { 173 strBuilder.AppendFormat("\"{0}\"", factorNode.VariableValue); 174 } else { 175 strBuilder.AppendFormat("'{0}'", factorNode.VariableValue); 176 } 177 178 if (!factorNode.Weight.IsAlmost(1.0)) { 179 strBuilder.Append(")"); 180 } 181 182 } else if (node.Symbol is Constant) { 183 var constNode = node as ConstantTreeNode; 184 if (constNode.Value >= 0.0) 185 strBuilder.Append(constNode.Value.ToString(formatString, numberFormat)); 186 else 187 strBuilder.Append("(").Append(constNode.Value.ToString(formatString, numberFormat)).Append(")"); // (-1 188 } 222 } 223 224 [StorableType("54D917E8-134E-4066-9A60-2737C12D81DC")] 225 [Item("Infix String Formater", "Formatter for symbolic expressions, which produces an infix expression " + 226 "as well as a list of all coefficient values")] 227 public sealed class InfixExpressionStringFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter { 228 [StorableConstructor] 229 private InfixExpressionStringFormatter(StorableConstructorFlag _) : base(_) { } 230 231 private InfixExpressionStringFormatter(InfixExpressionStringFormatter original, Cloner cloner) : base(original, cloner) { } 232 233 public InfixExpressionStringFormatter() : base() { 234 Name = ItemName; 235 Description = ItemDescription; 236 } 237 238 public override IDeepCloneable Clone(Cloner cloner) { 239 return new InfixExpressionStringFormatter(this, cloner); 240 } 241 242 public string Format(ISymbolicExpressionTree symbolicExpressionTree) { 243 StringBuilder strBuilder = new StringBuilder(); 244 var constants = new List<KeyValuePair<string, double>>(); 245 BaseInfixExpressionFormatter.FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), 246 strBuilder, NumberFormatInfo.InvariantInfo, "G", constants); 247 strBuilder.Append($"{Environment.NewLine}{Environment.NewLine}"); 248 249 int maxDigits = GetDigits(constants.Count); 250 int padding = constants.Max(x => x.Value.ToString("F12", CultureInfo.InvariantCulture).Length); 251 foreach (var constant in constants) { 252 int digits = GetDigits(Int32.Parse(constant.Key.Substring(2))); 253 strBuilder.Append($"{constant.Key}{new String(' ', maxDigits - digits)} = " + 254 string.Format($"{{0,{padding}:F12}}", constant.Value, CultureInfo.InvariantCulture) + 255 Environment.NewLine); 189 256 } 190 } 191 192 private static string GetToken(ISymbol symbol) {193 var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).FirstOrDefault(); 194 if (tok == null)195 throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name));196 return tok;257 258 return strBuilder.ToString(); 259 } 260 261 private int GetDigits(int x) { 262 if (x == 0) return 1; 263 return (int)Math.Floor(Math.Log10(x) + 1); 197 264 } 198 265 } -
branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionCSharpFormatter.cs
r17180 r17825 154 154 strBuilder.Append(" / Math.Sqrt(1 + Math.Pow("); 155 155 FormatRecursively(node.GetSubtree(1), strBuilder); 156 strBuilder.Append(" , 2) ) ");156 strBuilder.Append(" , 2) ) )"); 157 157 } else { 158 158 throw new NotSupportedException("Formatting of symbol: " + node.Symbol + " not supported for C# symbolic expression tree formatter."); -
branches/3040_VectorBasedGP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs
r17630 r17825 542 542 543 543 private void FormatStartSymbol(StringBuilder strBuilder) { 544 strBuilder.Append( targetVariable ?? "target_" + (targetCount++));544 strBuilder.Append(EscapeLatexString(targetVariable) ?? "target_{" + targetCount++ + "}"); 545 545 if (containsTimeSeriesSymbol) 546 546 strBuilder.Append("(t)");
Note: See TracChangeset
for help on using the changeset viewer.