#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.Linq; using HeuristicLab.Core; using HeuristicLab.Random; namespace HeuristicLab.ExpressionGenerator { public static class ExpressionGenerator { public static IEnumerable GenerateRandomDistributedVariables(int numberOfVariables, string variablePrefix, IRandom randomDistribution) { return Enumerable.Range(1, numberOfVariables).Select(x => Expression.RandomVariable(string.Format("{0}{1}", variablePrefix, x), randomDistribution)); } public static Expression NonlinearExpression(IRandom uniformRandom, Expression[] variables, bool useLog, bool useExp) { var scalingTemplate = ScaledExpression(uniformRandom, variables, varianceRandom: new UniformDistributedRandom(uniformRandom, 1, 10)); var scaledVars = Instantiate(scalingTemplate, uniformRandom, 100, "scaledVar"); var sumTemplate = new RandomArityTemplate(Sum, new UniformDistributedRandom(uniformRandom, 1, 3)) { Label = "+" }; sumTemplate.AddArguments(scaledVars); var prodTemplate = new RandomArityTemplate(Product, new UniformDistributedRandom(uniformRandom, 1, 3)) { Label = "*" }; prodTemplate.AddArguments(variables); var logTemplate = LogOfScaledExpression(uniformRandom, Instantiate(sumTemplate, uniformRandom, 100, "sumOfScaledVars"), minValue: new UniformDistributedRandom(uniformRandom, 0.1, 2), valueRange: new UniformDistributedRandom(uniformRandom, 1, 10)); var expTemplate = ExpOfScaledExpression(uniformRandom, Instantiate(prodTemplate, uniformRandom, 100, "prodOfVars"), minValue: new PointDistribution(-3), valueRange: new UniformDistributedRandom(uniformRandom, 4, 6)); var scaledExprTemplate = new ScalingTemplate(new UniformDistributedRandom(uniformRandom, 1, 10)) { Label = "*" }; if (useLog) scaledExprTemplate.AddArguments(Instantiate(logTemplate, uniformRandom, 100, "log")); if (useExp) scaledExprTemplate.AddArguments(Instantiate(expTemplate, uniformRandom, 100, "exp")); var mainTemplate = new RandomArityTemplate(Sum, new UniformDistributedRandom(uniformRandom, 3, 5)); mainTemplate.AddArguments(scaledVars); if (useLog || useExp) { mainTemplate.AddArguments(Instantiate(scaledExprTemplate, uniformRandom, 100, "scaledExpr")); } mainTemplate.Label = "+"; return mainTemplate.Instantiate("main", uniformRandom, false); } public static Expression Polynomial(IRandom uniformRandom, Expression[] variables, bool useLog, bool useExp) { const int count = 10; // how many instances of each template should be produce? int i = 1; // the main template var template = new RandomArityTemplate(Sum, new UniformDistributedRandom(uniformRandom, 2, count)) { Label = "+" }; template.AddArguments(variables); var sumTemplate = new RandomArityTemplate(Sum, new UniformDistributedRandom(uniformRandom, 1, variables.Length)) { Label = "+" }; sumTemplate.AddArguments(variables); var productTemplate = new RandomArityTemplate(Product, new UniformDistributedRandom(uniformRandom, 1, variables.Length)) { Label = "*" }; productTemplate.AddArguments(variables); var inverseTemplate = new FixedArityTemplate(Division, 1) { Label = "/" }; inverseTemplate.AddArguments(variables); inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => sumTemplate.Instantiate(string.Format("sum{0}", i++), uniformRandom))); inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => productTemplate.Instantiate(string.Format("prod{0}", i++), uniformRandom))); if (useLog) { var logTemplate = new FixedArityTemplate(Log, 1) { Label = "log" }; logTemplate.AddArguments(variables); logTemplate.AddArguments(Enumerable.Range(1, count).Select(x => sumTemplate.Instantiate(string.Format("sum{0}", i++), uniformRandom))); template.AddArguments(Enumerable.Range(1, count).Select(x => logTemplate.Instantiate(string.Format("log{0}", i++), uniformRandom))); inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => logTemplate.Instantiate(string.Format("log{0}", i++), uniformRandom))); } if (useExp) { var expTemplate = new FixedArityTemplate(Exp, 1) { Label = "exp" }; expTemplate.AddArguments(variables); expTemplate.AddArguments(Enumerable.Range(1, count).Select(x => productTemplate.Instantiate(string.Format("prod{0}", i++), uniformRandom))); template.AddArguments(Enumerable.Range(1, count).Select(x => expTemplate.Instantiate(string.Format("exp{0}", i++), uniformRandom))); inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => expTemplate.Instantiate(string.Format("exp{0}", i++), uniformRandom))); } template.AddArguments(Enumerable.Range(1, count).Select(x => inverseTemplate.Instantiate(string.Format("inv{0}", i++), uniformRandom))); return template.Instantiate("polynomial", uniformRandom); } // variance random must have support only positive numbers private static ExpressionTemplate ScaledExpression(IRandom uniformRandom, IEnumerable arguments, IRandom varianceRandom) { var scalingTemplate = new ScalingTemplate(scaledVariance: varianceRandom); scalingTemplate.AddArguments(arguments); scalingTemplate.Label = "*"; return scalingTemplate; } /// template scales and translates the argument expression first to guarantee positive values private static ExpressionTemplate LogOfScaledExpression(IRandom uniformRandom, IEnumerable arguments, IRandom minValue = null, IRandom valueRange = null) { var limitToRangeTemplate = new RangeTemplate(minValue, valueRange); limitToRangeTemplate.AddArguments(arguments); var logTemplate = new FixedArityTemplate(Log, 1) { Label = "log" }; logTemplate.AddArguments(Enumerable.Range(1, 100).Select(i => limitToRangeTemplate.Instantiate(string.Format("log{0}", i), uniformRandom, false))); return logTemplate; } /// template scales the argument expression first to guarantee reasonable values private static ExpressionTemplate ExpOfScaledExpression(IRandom uniformRandom, IEnumerable arguments, IRandom minValue = null, IRandom valueRange = null) { var limitToRangeTemplate = new RangeTemplate(minValue, valueRange); limitToRangeTemplate.AddArguments(arguments); var expTemplate = new FixedArityTemplate(Exp, 1) { Label = "exp" }; expTemplate.AddArguments(Enumerable.Range(1, 100).Select(i => limitToRangeTemplate.Instantiate(string.Format("exp{0}", i), uniformRandom, false))); return expTemplate; } public static IEnumerable Instantiate(ExpressionTemplate template, IRandom random, int count, string name) { return Enumerable.Range(1, count).Select(i => template.Instantiate(name + i, random, false)); } #region static functions public static double Sum(IEnumerable args) { return args.Sum(); } public static double Product(IEnumerable args) { return args.Aggregate((x, y) => x * y); } public static double Division(IEnumerable args) { if (args.Count() == 1) return 1 / args.First(); return args.Aggregate((x, y) => x / y); } public static double Subtraction(IEnumerable args) { if (args.Count() == 1) return -args.First(); return args.Aggregate((x, y) => x - y); } public static double Exp(IEnumerable args) { return Math.Exp(args.Single()); } public static double Log(IEnumerable args) { return Math.Log(args.Single()); } public static double Square(IEnumerable args) { var v = args.Single(); return v * v; } #endregion } }