Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
06/04/20 15:55:13 (4 years ago)
Author:
mkommend
Message:

#2521: Merged trunk changes into problem refactoring branch.

Location:
branches/2521_ProblemRefactoring
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/2521_ProblemRefactoring

  • branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic

  • branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs

    r17226 r17586  
    2121
    2222using System;
     23using System.Collections.Generic;
    2324using System.Globalization;
    2425using System.Linq;
    2526using System.Text;
     27using HEAL.Attic;
    2628using HeuristicLab.Common;
    2729using HeuristicLab.Core;
    2830using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    29 using HEAL.Attic;
    3031
    3132namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    32   /// <summary>
    33   /// Formats mathematical expressions in infix form. E.g. x1 * (3.0 * x2 + x3)
    34   /// </summary>
    35   [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 
    38   public sealed class InfixExpressionFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
    39 
    40 
    41     [StorableConstructor]
    42     private InfixExpressionFormatter(StorableConstructorFlag _) : base(_) { }
    43     private InfixExpressionFormatter(InfixExpressionFormatter original, Cloner cloner) : base(original, cloner) { }
    44     public InfixExpressionFormatter()
    45       : base() {
    46       Name = ItemName;
    47       Description = ItemDescription;
    48     }
    49     public override IDeepCloneable Clone(Cloner cloner) {
    50       return new InfixExpressionFormatter(this, cloner);
    51     }
    52 
    53     /// <summary>
    54     /// Produces an infix expression for a given expression tree.
    55     /// </summary>
    56     /// <param name="symbolicExpressionTree">The tree representation of the expression.</param>
    57     /// <param name="numberFormat">Number format that should be used for numeric parameters (e.g. NumberFormatInfo.InvariantInfo (default)).</param>
    58     /// <param name="formatString">The format string for numeric parameters (e.g. \"G4\" to limit to 4 digits, default is \"G\")</param>
    59     /// <returns>Infix expression</returns>
    60     public string Format(ISymbolicExpressionTree symbolicExpressionTree, NumberFormatInfo numberFormat, string formatString="G") {
    61       // skip root and start symbols
    62       StringBuilder strBuilder = new StringBuilder();
    63       FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), strBuilder, numberFormat, formatString);
    64       return strBuilder.ToString();
    65     }
    66 
    67     public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
    68       return Format(symbolicExpressionTree, NumberFormatInfo.InvariantInfo);
    69     }
    70 
    71     private static void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder, NumberFormatInfo numberFormat, string formatString) {
     33  public static class BaseInfixExpressionFormatter {
     34    public static void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder,
     35                                          NumberFormatInfo numberFormat, string formatString, List<KeyValuePair<string, double>> constants = null) {
    7236      if (node.SubtreeCount > 1) {
    7337        var token = GetToken(node.Symbol);
     
    7741            token == "^") {
    7842          strBuilder.Append("(");
    79           FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString);
     43          FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants);
    8044
    8145          foreach (var subtree in node.Subtrees.Skip(1)) {
    8246            strBuilder.Append(" ").Append(token).Append(" ");
    83             FormatRecursively(subtree, strBuilder, numberFormat, formatString);
    84           }
     47            FormatRecursively(subtree, strBuilder, numberFormat, formatString, constants);
     48          }
     49
    8550          strBuilder.Append(")");
    8651        } else {
    8752          // function with multiple arguments
    8853          strBuilder.Append(token).Append("(");
    89           FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString);
     54          FormatRecursively(node.Subtrees.First(), strBuilder, numberFormat, formatString, constants);
    9055          foreach (var subtree in node.Subtrees.Skip(1)) {
    9156            strBuilder.Append(", ");
    92             FormatRecursively(subtree, strBuilder, numberFormat, formatString);
    93           }
     57            FormatRecursively(subtree, strBuilder, numberFormat, formatString, constants);
     58          }
     59
    9460          strBuilder.Append(")");
    9561        }
     
    9864        if (token == "-" || token == "NOT") {
    9965          strBuilder.Append("(").Append(token).Append("(");
    100           FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
     66          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
    10167          strBuilder.Append("))");
    10268        } else if (token == "/") {
    10369          strBuilder.Append("1/");
    104           FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
     70          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
    10571        } else if (token == "+" || token == "*") {
    106           FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
     72          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
    10773        } else {
    10874          // function with only one argument
    10975          strBuilder.Append(token).Append("(");
    110           FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString);
     76          FormatRecursively(node.GetSubtree(0), strBuilder, numberFormat, formatString, constants);
    11177          strBuilder.Append(")");
    11278        }
     
    11783          if (!varNode.Weight.IsAlmost(1.0)) {
    11884            strBuilder.Append("(");
    119             strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat));
     85            if (constants != null) {
     86              strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Weight);
     87            } else {
     88              strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat));
     89            }
    12090            strBuilder.Append("*");
    12191          }
     92
    12293          strBuilder.Append("LAG(");
    123           if (varNode.VariableName.Contains("'")) {
     94          if (varNode.VariableName.Contains("'"))
    12495            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
    125           } else {
     96          else
    12697            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
    127           }
     98
    12899          strBuilder.Append(", ")
    129             .AppendFormat(numberFormat, "{0}", varNode.Lag)
    130             .Append(")");
     100                    .AppendFormat(numberFormat, "{0}", varNode.Lag)
     101                    .Append(")");
    131102        } else if (node.Symbol is Variable) {
    132103          var varNode = node as VariableTreeNode;
    133104          if (!varNode.Weight.IsAlmost(1.0)) {
    134105            strBuilder.Append("(");
    135             strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat));
     106            if (constants != null) {
     107              string constantKey = $"c_{constants.Count}";
     108              strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", constantKey);
     109              constants.Add(new KeyValuePair<string, double>(constantKey, varNode.Weight));
     110            } else {
     111              strBuilder.Append(varNode.Weight.ToString(formatString, numberFormat));
     112            }
     113
    136114            strBuilder.Append("*");
    137115          }
    138           if (varNode.VariableName.Contains("'")) {
     116
     117          if (varNode.VariableName.Contains("'"))
    139118            strBuilder.AppendFormat("\"{0}\"", varNode.VariableName);
    140           } else {
     119          else
    141120            strBuilder.AppendFormat("'{0}'", varNode.VariableName);
    142           }
    143           if (!varNode.Weight.IsAlmost(1.0)) {
    144             strBuilder.Append(")");
    145           }
     121
     122          if (!varNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");
    146123        } else if (node.Symbol is FactorVariable) {
    147124          var factorNode = node as FactorVariableTreeNode;
    148           if (factorNode.VariableName.Contains("'")) {
     125          if (factorNode.VariableName.Contains("'"))
    149126            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
    150           } else {
     127          else
    151128            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
    152           }
     129
    153130          strBuilder.AppendFormat("[{0}]",
    154131            string.Join(", ", factorNode.Weights.Select(w => w.ToString(formatString, numberFormat))));
     
    157134          if (!factorNode.Weight.IsAlmost(1.0)) {
    158135            strBuilder.Append("(");
    159             strBuilder.Append(factorNode.Weight.ToString(formatString, numberFormat));
     136            if (constants != null) {
     137              strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", factorNode.Weight);
     138            } else {
     139              strBuilder.Append(factorNode.Weight.ToString(formatString, numberFormat));
     140            }
     141
    160142            strBuilder.Append("*");
    161143          }
    162           if (factorNode.VariableName.Contains("'")) {
     144
     145          if (factorNode.VariableName.Contains("'"))
    163146            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
    164           } else {
     147          else
    165148            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
    166           }
     149
    167150          strBuilder.Append(" = ");
    168           if (factorNode.VariableValue.Contains("'")) {
     151          if (factorNode.VariableValue.Contains("'"))
    169152            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableValue);
    170           } else {
     153          else
    171154            strBuilder.AppendFormat("'{0}'", factorNode.VariableValue);
    172           }
    173 
    174           if (!factorNode.Weight.IsAlmost(1.0)) {
    175             strBuilder.Append(")");
    176           }
    177 
     155
     156          if (!factorNode.Weight.IsAlmost(1.0)) strBuilder.Append(")");
    178157        } else if (node.Symbol is Constant) {
    179158          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
     159          if (constants != null) {
     160            string constantKey = $"c_{constants.Count}";
     161
     162            strBuilder.AppendFormat(CultureInfo.InvariantCulture, constantKey);
     163            constants.Add(new KeyValuePair<string, double>(constantKey, constNode.Value));
     164          } else {
     165            if (constNode.Value >= 0.0)
     166              strBuilder.Append(constNode.Value.ToString(formatString, numberFormat));
     167            else
     168              strBuilder.Append("(").Append(constNode.Value.ToString(formatString, numberFormat))
     169                        .Append(")"); // (-1
     170          }
    184171        }
    185172      }
     
    193180    }
    194181  }
     182
     183  /// <summary>
     184  /// Formats mathematical expressions in infix form. E.g. x1 * (3.0 * x2 + x3)
     185  /// </summary>
     186  [StorableType("6FE2C83D-A594-4ABF-B101-5AEAEA6D3E3D")]
     187  [Item("Infix Symbolic Expression Tree Formatter",
     188    "A string formatter that converts symbolic expression trees to infix expressions.")]
     189  public sealed class InfixExpressionFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
     190    [StorableConstructor]
     191    private InfixExpressionFormatter(StorableConstructorFlag _) : base(_) { }
     192
     193    private InfixExpressionFormatter(InfixExpressionFormatter original, Cloner cloner) : base(original, cloner) { }
     194
     195    public InfixExpressionFormatter()
     196      : base() {
     197      Name = ItemName;
     198      Description = ItemDescription;
     199    }
     200
     201    public override IDeepCloneable Clone(Cloner cloner) {
     202      return new InfixExpressionFormatter(this, cloner);
     203    }
     204
     205    /// <summary>
     206    /// Produces an infix expression for a given expression tree.
     207    /// </summary>
     208    /// <param name="symbolicExpressionTree">The tree representation of the expression.</param>
     209    /// <param name="numberFormat">Number format that should be used for numeric parameters (e.g. NumberFormatInfo.InvariantInfo (default)).</param>
     210    /// <param name="formatString">The format string for numeric parameters (e.g. \"G4\" to limit to 4 digits, default is \"G\")</param>
     211    /// <returns>Infix expression</returns>
     212    public string Format(ISymbolicExpressionTree symbolicExpressionTree, NumberFormatInfo numberFormat,
     213                         string formatString = "G") {
     214      // skip root and start symbols
     215      StringBuilder strBuilder = new StringBuilder();
     216      BaseInfixExpressionFormatter.FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0),
     217        strBuilder, numberFormat, formatString);
     218      return strBuilder.ToString();
     219    }
     220
     221    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
     222      return Format(symbolicExpressionTree, NumberFormatInfo.InvariantInfo);
     223    }
     224  }
     225
     226  [StorableType("54D917E8-134E-4066-9A60-2737C12D81DC")]
     227  [Item("Infix String Formater", "Formatter for symbolic expressions, which produces an infix expression " +
     228                                 "as well as a list of all coefficient values")]
     229  public sealed class InfixExpressionStringFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
     230    [StorableConstructor]
     231    private InfixExpressionStringFormatter(StorableConstructorFlag _) : base(_) { }
     232
     233    private InfixExpressionStringFormatter(InfixExpressionStringFormatter original, Cloner cloner) : base(original, cloner) { }
     234
     235    public InfixExpressionStringFormatter() : base() {
     236      Name = ItemName;
     237      Description = ItemDescription;
     238    }
     239
     240    public override IDeepCloneable Clone(Cloner cloner) {
     241      return new InfixExpressionStringFormatter(this, cloner);
     242    }
     243
     244    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
     245      StringBuilder strBuilder = new StringBuilder();
     246      var constants = new List<KeyValuePair<string, double>>();
     247      BaseInfixExpressionFormatter.FormatRecursively(symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0),
     248        strBuilder, NumberFormatInfo.InvariantInfo, "G", constants);
     249      strBuilder.Append($"{Environment.NewLine}{Environment.NewLine}");
     250
     251      int maxDigits = GetDigits(constants.Count);
     252      int padding = constants.Max(x => x.Value.ToString("F12", CultureInfo.InvariantCulture).Length);
     253      foreach (var constant in constants) {
     254        int digits = GetDigits(Int32.Parse(constant.Key.Substring(2)));
     255        strBuilder.Append($"{constant.Key}{new String(' ', maxDigits - digits)} = " +
     256                          string.Format($"{{0,{padding}:F12}}", constant.Value, CultureInfo.InvariantCulture) +
     257                          Environment.NewLine);
     258      }
     259
     260      return strBuilder.ToString();
     261    }
     262
     263    private int GetDigits(int x) {
     264      if (x == 0) return 1;
     265      return (int)Math.Floor(Math.Log10(x) + 1);
     266    }
     267  }
    195268}
  • branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs

    r17226 r17586  
    2323using System.Collections.Generic;
    2424using System.Linq;
     25using HEAL.Attic;
    2526using HeuristicLab.Common;
    2627using HeuristicLab.Core;
    2728using HeuristicLab.Data;
    2829using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    29 using HEAL.Attic;
    3030using HeuristicLab.Parameters;
    3131
     
    8080    }
    8181
    82     public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IDictionary<string, Interval> variableRanges) {
     82    public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
    8383      lock (syncRoot) {
    8484        EvaluatedSolutions++;
     
    9797
    9898    public Interval GetSymbolicExpressionTreeIntervals(ISymbolicExpressionTree tree,
    99       IDictionary<string, Interval> variableRanges, out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals) {
     99      IReadOnlyDictionary<string, Interval> variableRanges, out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals) {
    100100      lock (syncRoot) {
    101101        EvaluatedSolutions++;
     
    124124
    125125
    126     private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, IDictionary<string, Interval> variableRanges) {
     126    private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
    127127      if (variableRanges == null)
    128128        throw new ArgumentNullException("No variablew ranges are present!", nameof(variableRanges));
     
    234234            break;
    235235          }
    236         case OpCodes.Power: {
    237             result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    238             for (int i = 1; i < currentInstr.nArguments; i++) {
    239               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    240               result = Interval.Power(result, argumentInterval);
    241             }
    242             break;
    243           }
    244236        case OpCodes.Square: {
    245237            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     
    247239            break;
    248240          }
    249         case OpCodes.Root: {
    250             result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    251             for (int i = 1; i < currentInstr.nArguments; i++) {
    252               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    253               result = Interval.Root(result, argumentInterval);
    254             }
    255             break;
    256           }
    257241        case OpCodes.SquareRoot: {
    258242            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    259243            result = Interval.SquareRoot(argumentInterval);
     244            break;
     245          }
     246        case OpCodes.Cube: {
     247            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     248            result = Interval.Cube(argumentInterval);
     249            break;
     250          }
     251        case OpCodes.CubeRoot: {
     252            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     253            result = Interval.CubicRoot(argumentInterval);
     254            break;
     255          }
     256        case OpCodes.Absolute: {
     257            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     258            result = Interval.Absolute(argumentInterval);
     259            break;
     260          }
     261        case OpCodes.AnalyticQuotient: {
     262            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     263            for (var i = 1; i < currentInstr.nArguments; i++) {
     264              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     265              result = Interval.AnalyticalQuotient(result, argumentInterval);
     266            }
     267
    260268            break;
    261269          }
     
    274282        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
    275283        where
     284          !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) &&
     285          !(n.Symbol is Constant) &&
    276286          !(n.Symbol is StartSymbol) &&
    277287          !(n.Symbol is Addition) &&
     
    284294          !(n.Symbol is Logarithm) &&
    285295          !(n.Symbol is Exponential) &&
    286           !(n.Symbol is Power) &&
    287296          !(n.Symbol is Square) &&
    288           !(n.Symbol is Root) &&
    289297          !(n.Symbol is SquareRoot) &&
    290           !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) &&
    291           !(n.Symbol is Constant)
     298          !(n.Symbol is Cube) &&
     299          !(n.Symbol is CubeRoot) &&
     300          !(n.Symbol is Absolute) &&
     301          !(n.Symbol is AnalyticQuotient)
    292302        select n).Any();
    293303      return !containsUnknownSyumbol;
Note: See TracChangeset for help on using the changeset viewer.