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

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

#2704: Fix infix formatting bug, refactored generation of polynomial to respect user choices (with or without exp/log).

File size: 6.5 KB
Line 
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 {
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; }
36
37    public ExpressionType Type { get; private set; }
38
39    private readonly List<Expression> arguments;
40    public IEnumerable<Expression> Arguments {
41      get { return arguments ?? Enumerable.Empty<Expression>(); }
42    }
43
44    public IRandom Distribution { get; private set; }
45
46    public Func<IEnumerable<double>, double> Transform { get; private set; }
47
48    public double Value { get; private set; }
49
50    public Expression(string name, double value) {
51      Type = ExpressionType.Constant;
52      Value = value;
53      Name = name;
54    }
55
56    public Expression(string name, IRandom distribution) {
57      Type = ExpressionType.RandomVariable;
58      Distribution = distribution;
59      Name = name;
60    }
61
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    }
69
70    public static Expression Constant(string name, double value) {
71      return new Expression(name, value);
72    }
73
74    public static Expression RandomVariable(string name, IRandom distribution) {
75      return new Expression(name, distribution);
76    }
77
78    public static Expression Function(string name, Func<IEnumerable<double>, double> transform, IEnumerable<Expression> arguments) {
79      return new Expression(name, transform, arguments);
80    }
81
82    public override string ToString() {
83      var sb = new StringBuilder();
84
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      }
101
102      return sb.ToString();
103    }
104
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          sb.Append("(");
121          // the Label should be known to the infix parser
122          if (Label == "+" || Label == "-" || Label == "*" || Label == "/") {
123            if (Label == "/")
124              sb.Append("1 / ");
125            if (args.Count == 1) {
126              sb.Append(string.Format("{0}", args[0].PrintInfix()));
127            } else {
128              sb.Append("(");
129              var last = args.Last();
130              for (int i = 0; i < args.Count - 1; ++i) {
131                var arg = args[i];
132                sb.Append(string.Format("{0} {1} ", arg.PrintInfix(), Label));
133              }
134              sb.Append(string.Format("{0})", last.PrintInfix()));
135            }
136          } else {
137            sb.Append(string.Format("{0}(", Label));
138            var last = args.Last();
139            for (int i = 0; i < args.Count - 1; ++i) {
140              var arg = args[i];
141              sb.Append(string.Format("{0}, ", arg.PrintInfix(), Label));
142            }
143            sb.Append(string.Format("{0})", last.PrintInfix()));
144          }
145          sb.Append(")");
146          break;
147      }
148      return sb.ToString();
149    }
150
151    public string PrintDot() {
152      var stack = new Stack<Expression>();
153      stack.Push(this);
154
155      var sb = new StringBuilder();
156      sb.AppendLine("digraph g {");
157
158      while (stack.Count > 0) {
159        var top = stack.Pop();
160
161        if (!top.Arguments.Any())
162          continue;
163
164        foreach (var arg in top.Arguments) {
165          var from = top.Arguments.Any() ? top.Name : top.ToString();
166          var to = arg.Arguments.Any() ? arg.Name : arg.ToString();
167          sb.AppendLine(string.Format("\"{0}\" -> \"{1}\";", from, to));
168          stack.Push(arg);
169        }
170      }
171
172      sb.AppendLine("}");
173      return sb.ToString();
174    }
175
176    private static string GetStringDescription(IRandom random) {
177      var normal = random as NormalDistributedRandom;
178      if (normal != null)
179        return string.Format("N({0}, {1})", normal.Mu, normal.Sigma);
180
181      var uniform = random as UniformDistributedRandom;
182      if (uniform != null)
183        return string.Format("U({0}, {1})", uniform.Min, uniform.Max);
184
185      var gamma = random as GammaDistributedRandom;
186      if (gamma != null)
187        return string.Format("G({0}, {1})", gamma.Shape, gamma.Rate);
188
189      return random.ToString();
190    }
191  }
192}
Note: See TracBrowser for help on using the repository browser.