#region License Information /* HeuristicLab * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using HeuristicLab.Core; using HeuristicLab.Random; namespace HeuristicLab.ExpressionGenerator { public class Expression : IExpression { // unique name for each expression public string Name { get; set; } // optional label (non-unique) - useful for string (infix) representations public string Label { get; set; } public ExpressionType Type { get; private set; } private readonly List arguments; public IEnumerable Arguments { get { return arguments ?? Enumerable.Empty(); } } public IRandom Distribution { get; private set; } public Func, double> Transform { get; private set; } public double Value { get; private set; } public Expression(string name, double value) { Type = ExpressionType.Constant; Value = value; Name = name; } public Expression(string name, IRandom distribution) { Type = ExpressionType.RandomVariable; Distribution = distribution; Name = name; } public Expression(string name, Func, double> transform, IEnumerable arguments) { Type = ExpressionType.Function; Transform = transform; this.arguments = this.arguments ?? new List(); this.arguments.AddRange(arguments); Name = name; } public static Expression Constant(string name, double value) { return new Expression(name, value); } public static Expression RandomVariable(string name, IRandom distribution) { return new Expression(name, distribution); } public static Expression Function(string name, Func, double> transform, IEnumerable arguments) { return new Expression(name, transform, arguments); } public override string ToString() { var sb = new StringBuilder(); switch (Type) { case ExpressionType.Constant: sb.Append(Value.ToString("0.000", CultureInfo.CurrentCulture)); break; case ExpressionType.RandomVariable: sb.Append(string.Format("{0} ~ {1}", Name, GetStringDescription(Distribution))); break; case ExpressionType.Function: sb.Append(string.Format("{0} = f(", Name)); if (Arguments.Any()) { for (int i = 0; i < arguments.Count - 1; ++i) sb.Append(string.Format("{0}, ", arguments[i].Name)); sb.Append(string.Format("{0})", arguments.Last().Name)); } break; } return sb.ToString(); } public string PrintInfix() { var sb = new StringBuilder(); switch (Type) { case ExpressionType.Constant: sb.Append(Value < 0 ? string.Format("(- {0})", Math.Abs(Value).ToString("0.000", CultureInfo.CurrentCulture)) : Value.ToString("0.000", CultureInfo.CurrentCulture)); break; case ExpressionType.RandomVariable: sb.Append(Name); break; case ExpressionType.Function: if (!Arguments.Any()) break; var args = Arguments.ToList(); // the Label should be known to the infix parser if (Label == "+" || Label == "-" || Label == "*" || Label == "/") { if (args.Count == 1) { sb.Append(string.Format(Label == "/" ? "1 / {0}" : "{0}", args[0].PrintInfix())); } else { if (Label == "/") { sb.Append(string.Format("{0} / ", args[0].PrintInfix())); var remaining = args.Count - 1; if (remaining == 1) sb.Append(args[1].PrintInfix()); else { sb.Append("("); var last = args.Last(); for (int i = 1; i < args.Count - 1; ++i) { var arg = args[i]; sb.Append(string.Format("{0} {1} ", arg.PrintInfix(), "*")); } sb.Append(string.Format("{0})", last.PrintInfix())); } } else { sb.Append("("); var last = args.Last(); for (int i = 0; i < args.Count - 1; ++i) { var arg = args[i]; sb.Append(string.Format("{0} {1} ", arg.PrintInfix(), Label)); } sb.Append(string.Format("{0})", last.PrintInfix())); } } } else { sb.Append(string.Format("{0}(", Label)); var last = args.Last(); for (int i = 0; i < args.Count - 1; ++i) { var arg = args[i]; sb.Append(string.Format("{0}, ", arg.PrintInfix())); } sb.Append(string.Format("{0})", last.PrintInfix())); } break; } return sb.ToString(); } public string PrintDot() { var stack = new Stack(); stack.Push(this); var sb = new StringBuilder(); sb.AppendLine("digraph g {"); while (stack.Count > 0) { var top = stack.Pop(); if (!top.Arguments.Any()) continue; foreach (var arg in top.Arguments) { var from = top.Arguments.Any() ? top.Name : top.ToString(); var to = arg.Arguments.Any() ? arg.Name : arg.ToString(); sb.AppendLine(string.Format("\"{0}\" -> \"{1}\";", from, to)); stack.Push(arg); } } sb.AppendLine("}"); return sb.ToString(); } private static string GetStringDescription(IRandom random) { var normal = random as NormalDistributedRandom; if (normal != null) return string.Format("N({0}, {1})", normal.Mu, normal.Sigma); var uniform = random as UniformDistributedRandom; if (uniform != null) return string.Format("U({0}, {1})", uniform.Min, uniform.Max); var gamma = random as GammaDistributedRandom; if (gamma != null) return string.Format("G({0}, {1})", gamma.Shape, gamma.Rate); return random.ToString(); } } }