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