source: branches/HeuristicLab.ExpressionGenerator/HeuristicLab.ExpressionGenerator/3.4/Expression.cs @ 14520

Last change on this file since 14520 was 14520, checked in by bburlacu, 3 years ago

#2704: Improve infix formatting

File size: 7.1 KB
RevLine 
[14409]1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Globalization;
25using System.Linq;
26using System.Text;
27using HeuristicLab.Core;
28using HeuristicLab.Random;
29
30namespace HeuristicLab.ExpressionGenerator {
[14505]31  public class Expression : IExpression {
32    // unique name for each expression
33    public string Name { get; set; }
34    // optional label (non-unique) - useful for string (infix) representations
35    public string Label { get; set; }
[14409]36
[14505]37    public ExpressionType Type { get; private set; }
[14409]38
[14505]39    private readonly List<Expression> arguments;
40    public IEnumerable<Expression> Arguments {
41      get { return arguments ?? Enumerable.Empty<Expression>(); }
42    }
[14409]43
[14505]44    public IRandom Distribution { get; private set; }
[14409]45
[14505]46    public Func<IEnumerable<double>, double> Transform { get; private set; }
[14409]47
[14505]48    public double Value { get; private set; }
[14409]49
[14505]50    public Expression(string name, double value) {
51      Type = ExpressionType.Constant;
52      Value = value;
53      Name = name;
54    }
[14409]55
[14505]56    public Expression(string name, IRandom distribution) {
57      Type = ExpressionType.RandomVariable;
58      Distribution = distribution;
59      Name = name;
60    }
[14409]61
[14505]62    public Expression(string name, Func<IEnumerable<double>, double> transform, IEnumerable<Expression> arguments) {
63      Type = ExpressionType.Function;
64      Transform = transform;
65      this.arguments = this.arguments ?? new List<Expression>();
66      this.arguments.AddRange(arguments);
67      Name = name;
68    }
[14409]69
[14505]70    public static Expression Constant(string name, double value) {
71      return new Expression(name, value);
72    }
[14409]73
[14505]74    public static Expression RandomVariable(string name, IRandom distribution) {
75      return new Expression(name, distribution);
76    }
[14409]77
[14505]78    public static Expression Function(string name, Func<IEnumerable<double>, double> transform, IEnumerable<Expression> arguments) {
79      return new Expression(name, transform, arguments);
80    }
[14409]81
[14505]82    public override string ToString() {
83      var sb = new StringBuilder();
[14409]84
[14505]85      switch (Type) {
86        case ExpressionType.Constant:
87          sb.Append(Value.ToString("0.000", CultureInfo.CurrentCulture));
88          break;
89        case ExpressionType.RandomVariable:
90          sb.Append(string.Format("{0} ~ {1}", Name, GetStringDescription(Distribution)));
91          break;
92        case ExpressionType.Function:
93          sb.Append(string.Format("{0} = f(", Name));
94          if (Arguments.Any()) {
95            for (int i = 0; i < arguments.Count - 1; ++i)
96              sb.Append(string.Format("{0}, ", arguments[i].Name));
97            sb.Append(string.Format("{0})", arguments.Last().Name));
98          }
99          break;
100      }
[14409]101
[14505]102      return sb.ToString();
103    }
[14409]104
[14505]105    public string PrintInfix() {
106      var sb = new StringBuilder();
107      switch (Type) {
108        case ExpressionType.Constant:
109          sb.Append(Value < 0
110              ? string.Format("(- {0})", Math.Abs(Value).ToString("0.000", CultureInfo.CurrentCulture))
111              : Value.ToString("0.000", CultureInfo.CurrentCulture));
112          break;
113        case ExpressionType.RandomVariable:
114          sb.Append(Name);
115          break;
116        case ExpressionType.Function:
117          if (!Arguments.Any())
118            break;
119          var args = Arguments.ToList();
120          // the Label should be known to the infix parser
121          if (Label == "+" || Label == "-" || Label == "*" || Label == "/") {
122            if (args.Count == 1) {
[14520]123              sb.Append(string.Format(Label == "/" ? "1 / {0}" : "{0}", args[0].PrintInfix()));
[14505]124            } else {
[14520]125              if (Label == "/") {
126                sb.Append(string.Format("{0} / ", args[0].PrintInfix()));
127                var remaining = args.Count - 1;
128                if (remaining == 1)
129                  sb.Append(args[1].PrintInfix());
130                else {
131                  sb.Append("(");
132                  var last = args.Last();
133                  for (int i = 1; i < args.Count - 1; ++i) {
134                    var arg = args[i];
135                    sb.Append(string.Format("{0} {1} ", arg.PrintInfix(), "*"));
136                  }
137                  sb.Append(string.Format("{0})", last.PrintInfix()));
138                }
139              } else {
140                sb.Append("(");
141                var last = args.Last();
142                for (int i = 0; i < args.Count - 1; ++i) {
143                  var arg = args[i];
144                  sb.Append(string.Format("{0} {1} ", arg.PrintInfix(), Label));
145                }
146                sb.Append(string.Format("{0})", last.PrintInfix()));
[14505]147              }
[14480]148            }
[14505]149          } else {
150            sb.Append(string.Format("{0}(", Label));
151            var last = args.Last();
152            for (int i = 0; i < args.Count - 1; ++i) {
153              var arg = args[i];
[14520]154              sb.Append(string.Format("{0}, ", arg.PrintInfix()));
[14505]155            }
156            sb.Append(string.Format("{0})", last.PrintInfix()));
157          }
158          break;
159      }
160      return sb.ToString();
161    }
[14448]162
[14505]163    public string PrintDot() {
164      var stack = new Stack<Expression>();
165      stack.Push(this);
[14448]166
[14505]167      var sb = new StringBuilder();
168      sb.AppendLine("digraph g {");
[14410]169
[14505]170      while (stack.Count > 0) {
171        var top = stack.Pop();
[14410]172
[14505]173        if (!top.Arguments.Any())
174          continue;
[14410]175
[14505]176        foreach (var arg in top.Arguments) {
177          var from = top.Arguments.Any() ? top.Name : top.ToString();
178          var to = arg.Arguments.Any() ? arg.Name : arg.ToString();
179          sb.AppendLine(string.Format("\"{0}\" -> \"{1}\";", from, to));
180          stack.Push(arg);
[14410]181        }
[14505]182      }
[14410]183
[14505]184      sb.AppendLine("}");
185      return sb.ToString();
186    }
[14410]187
[14505]188    private static string GetStringDescription(IRandom random) {
189      var normal = random as NormalDistributedRandom;
190      if (normal != null)
191        return string.Format("N({0}, {1})", normal.Mu, normal.Sigma);
[14409]192
[14505]193      var uniform = random as UniformDistributedRandom;
194      if (uniform != null)
195        return string.Format("U({0}, {1})", uniform.Min, uniform.Max);
[14409]196
[14505]197      var gamma = random as GammaDistributedRandom;
198      if (gamma != null)
199        return string.Format("G({0}, {1})", gamma.Shape, gamma.Rate);
200
201      return random.ToString();
[14409]202    }
[14505]203  }
[14409]204}
Note: See TracBrowser for help on using the repository browser.