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

Last change on this file since 14480 was 14480, checked in by bburlacu, 4 years ago

#2704: Implement export of expressions as infix strings. Include missing AssemblyInfo.cs.frame file and set language version to C# 4.0.

File size: 7.4 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 (args.Count == 1) {
124                            sb.Append(string.Format("{0}", args[0].PrintInfix()));
125                        } else {
126                            sb.Append("(");
127                            var last = args.Last();
128                            for (int i = 0; i < args.Count - 1; ++i) {
129                                var arg = args[i];
130                                sb.Append(string.Format("{0} {1}", arg.PrintInfix(), Label));
131                            }
132                            sb.Append(string.Format(" {0})", last.PrintInfix()));
133                        }
134                    } else {
135                        sb.Append(string.Format("{0}(", Label));
136                        var last = args.Last();
137                        for (int i = 0; i < args.Count - 1; ++i) {
138                            var arg = args[i];
139                            sb.Append(string.Format("{0}, ", arg.PrintInfix(), Label));
140                        }
141                        sb.Append(string.Format("{0})", last.PrintInfix()));
142                    }
143                    sb.Append(")");
144                    break;
145            }
146            return sb.ToString();
147        }
148
149        public string PrintDot() {
150            var stack = new Stack<Expression>();
151            stack.Push(this);
152
153            var sb = new StringBuilder();
154            sb.AppendLine("digraph g {");
155
156            while (stack.Count > 0) {
157                var top = stack.Pop();
158
159                if (!top.Arguments.Any())
160                    continue;
161
162                foreach (var arg in top.Arguments) {
163                    var from = top.Arguments.Any() ? top.Name : top.ToString();
164                    var to = arg.Arguments.Any() ? arg.Name : arg.ToString();
165                    sb.AppendLine(string.Format("\"{0}\" -> \"{1}\";", from, to));
166                    stack.Push(arg);
167                }
168            }
169
170            sb.AppendLine("}");
171            return sb.ToString();
172        }
173
174        private static string GetStringDescription(IRandom random) {
175            var normal = random as NormalDistributedRandom;
176            if (normal != null)
177                return string.Format("N({0}, {1})", normal.Mu, normal.Sigma);
178
179            var uniform = random as UniformDistributedRandom;
180            if (uniform != null)
181                return string.Format("U({0}, {1})", uniform.Min, uniform.Max);
182
183            var gamma = random as GammaDistributedRandom;
184            if (gamma != null)
185                return string.Format("G({0}, {1})", gamma.Shape, gamma.Rate);
186
187            return random.ToString();
188        }
189    }
190}
Note: See TracBrowser for help on using the repository browser.