Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.ExpressionGenerator/HeuristicLab.ExpressionGenerator/3.4/ExpressionGenerator.cs @ 14880

Last change on this file since 14880 was 14880, checked in by gkronber, 7 years ago

#2704: added more expression templates

File size: 16.0 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.Linq;
25using HeuristicLab.Core;
26using HeuristicLab.ExpressionGenerator.Interfaces;
27using HeuristicLab.Random;
28
29namespace HeuristicLab.ExpressionGenerator {
30  public static class ExpressionGenerator {
31    public static IEnumerable<Expression> GenerateRandomDistributedVariables(int numberOfVariables, string variablePrefix, IRandom randomDistribution) {
32      return Enumerable.Range(1, numberOfVariables).Select(x => Expression.RandomVariable(string.Format("{0}{1}", variablePrefix, x), randomDistribution));
33    }
34
35    public static Expression RationalExpression(IRandom uniformRandom, Expression[] variables, bool useLog, bool useExp) {
36      var numerators =
37        Enumerable.Range(0, 20)
38          .Select(
39            i =>
40              NonlinearExpressionTemplate(uniformRandom, variables, useLog, useExp, false)
41                .Instantiate("numerator" + i, uniformRandom, sampleWithRepetition: false))
42          .ToArray();
43      var denominators =
44        Enumerable.Range(0, 20)
45          .Select(
46            i =>
47              NonlinearExpressionTemplate(uniformRandom, variables, useLog, useExp, false)
48                .Instantiate("denominator" + i, uniformRandom, sampleWithRepetition: false))
49          .ToArray();
50
51
52      var scaledNumeratorTemplate = new ScalingTemplate(new PointDistribution<double>(1.0));
53      scaledNumeratorTemplate.AddArguments(numerators);
54
55      var scaledDenominatorTemplate = new RangeTemplate(
56        minValue: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 0.01, 1)),
57        valueRange: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 2, 10)));
58      scaledDenominatorTemplate.AddArguments(denominators);
59
60
61      var scaledNumerators =
62        Enumerable.Range(0, 20)
63          .Select(i => scaledNumeratorTemplate.Instantiate("scaledNumerator" + i, uniformRandom, false));
64
65      var scaledDenominators =
66        Enumerable.Range(0, 20)
67          .Select(i => scaledDenominatorTemplate.Instantiate("scaledDenom" + i, uniformRandom, false));
68
69      var template = new BinaryOperatorTemplate(Division) { Label = "/" };
70      template.AddLeftArguments(scaledNumerators);
71      template.AddRightArguments(scaledDenominators);
72
73      return template.Instantiate("rational", uniformRandom, false);
74    }
75
76    public static Expression SumOfCompactNonlinearTerms(IRandom uniformRandom, Expression[] variables, bool useLog,
77      bool useExp, bool useFrac) {
78      var numInstances = 2 * variables.Length;
79
80      var scalingVarsTemplate = new ScalingTemplate(new DoublePrngDistribution(new GammaDistributedRandom(uniformRandom, 2, 2))); // exp(x) = 1, var(x) = 8
81      scalingVarsTemplate.AddArguments(variables);
82      var scaledVars = Instantiate(scalingVarsTemplate, uniformRandom, numInstances, "scaledVar");
83
84      var sumOfScaledVarsTemplate = new RandomArityTemplate(Sum, new DiscreteUniformDistribution(uniformRandom, 1, 3)) { Label = "+" };
85      sumOfScaledVarsTemplate.AddArguments(scaledVars);
86      var sumOfScaledVars = Instantiate(sumOfScaledVarsTemplate, uniformRandom, numInstances, "sumOfScaledVars");
87
88      var prodTemplate = new RandomArityTemplate(Product, new DiscreteUniformDistribution(uniformRandom, 1, 3)) { Label = "*" };
89      prodTemplate.AddArguments(variables);
90
91      var logTermsTemplate = LogOfScaledExpression(uniformRandom, sumOfScaledVars,
92      minValue: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 0.1, 2)),
93      valueRange: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 1, 10)));
94      var logTerms = Instantiate(logTermsTemplate, uniformRandom, numInstances, "log");
95
96      var expTemplate = ExpOfScaledExpression(uniformRandom, Instantiate(prodTemplate, uniformRandom, numInstances, "prodOfVars"),
97                           minValue: new PointDistribution<double>(-2.0),
98                           valueRange: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 4, 6)));
99      var expTerms = Instantiate(expTemplate, uniformRandom, numInstances, "exp");
100
101      var fracTemplate = new BinaryOperatorTemplate(Division) { Label = "/" };
102      fracTemplate.AddLeftArgument(Expression.Constant("const", 1.0), variables.Length);
103      fracTemplate.AddLeftArguments(variables);
104      fracTemplate.AddRightArguments(sumOfScaledVars);
105      var fracTerms = Enumerable.Range(1, numInstances).Select(i => fracTemplate.Instantiate("frac" + i, uniformRandom, false));
106
107      var prodOfFactorsTemplate = new RandomArityTemplate(Product, new DiscreteUniformDistribution(uniformRandom, 1, 4)) { Label = "*" };
108      prodOfFactorsTemplate.AddArguments(variables, variables.Select(_ => 1.0));
109      if (useLog) prodOfFactorsTemplate.AddArguments(logTerms, logTerms.Select(_ => .3));
110      if (useExp) prodOfFactorsTemplate.AddArguments(expTerms, expTerms.Select(_ => .3));
111      if (useFrac) prodOfFactorsTemplate.AddArguments(fracTerms, fracTerms.Select(_ => .3));
112      var prodFactors = Instantiate(prodOfFactorsTemplate, uniformRandom, numInstances, "prod");
113
114      var scaledTermsTemplate =
115        new ScalingTemplate(new DoublePrngDistribution(new GammaDistributedRandom(uniformRandom, 2, 2))); // exp(x) = 1, var(x) = 8
116      scaledTermsTemplate.AddArguments(variables, variables.Select(_ => 1.0));
117      if (useLog) scaledTermsTemplate.AddArguments(logTerms, logTerms.Select(_ => 1.0));
118      if (useExp) scaledTermsTemplate.AddArguments(expTerms, expTerms.Select(_ => 1.0));
119      if (useFrac) scaledTermsTemplate.AddArguments(fracTerms, fracTerms.Select(_ => 1.0));
120      scaledTermsTemplate.AddArguments(prodFactors, prodFactors.Select(_ => 4.0));
121
122      var scaledTerms = Instantiate(scaledTermsTemplate, uniformRandom, 100, "scaledTerm");
123
124      var sumTemplate = new RandomArityTemplate(Sum, arityDistribution: new DiscreteUniformDistribution(uniformRandom, 5, 25)) { Label = "+" };
125      sumTemplate.AddArguments(scaledTerms);
126
127      return sumTemplate.Instantiate("sum", uniformRandom, false);
128    }
129
130    public static Expression NonlinearExpression(IRandom uniformRandom, Expression[] variables, bool useLog, bool useExp, bool useFrac) {
131      return NonlinearExpressionTemplate(uniformRandom, variables, useLog, useExp, useFrac)
132        .Instantiate("nonlinearexpr", uniformRandom, sampleWithRepetition: false);
133    }
134
135    public static ExpressionTemplate NonlinearExpressionTemplate(IRandom uniformRandom, Expression[] variables, bool useLog, bool useExp, bool useFrac) {
136      var scalingTemplate = ScaledExpression(uniformRandom, variables, varianceDistribution: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 1, 10)));
137      var scaledVars = Instantiate(scalingTemplate, uniformRandom, variables.Length, "scaledVar");
138
139      var sumTemplate = new RandomArityTemplate(Sum, new DiscreteUniformDistribution(uniformRandom, 1, 3)) { Label = "+" };
140      sumTemplate.AddArguments(scaledVars);
141      var prodTemplate = new RandomArityTemplate(Product, new DiscreteUniformDistribution(uniformRandom, 1, 3)) { Label = "*" };
142      prodTemplate.AddArguments(variables);
143
144      var logTemplate = LogOfScaledExpression(uniformRandom, Instantiate(sumTemplate, uniformRandom, scaledVars.Count(), "sumOfScaledVars"),
145        minValue: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 0.1, 2)),
146        valueRange: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 1, 10)));
147
148      var expTemplate = ExpOfScaledExpression(uniformRandom, Instantiate(prodTemplate, uniformRandom, variables.Length, "prodOfVars"),
149        minValue: new PointDistribution<double>(-3.0),
150        valueRange: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 4, 6)));
151
152      var variableSumTemplate = new RandomArityTemplate(Sum, new DiscreteUniformDistribution(uniformRandom, 1, 4)) { Label = "+" };
153      variableSumTemplate.AddArguments(variables);
154      var variableSums = Instantiate(variableSumTemplate, uniformRandom, variables.Length * 2, "varsum");
155
156      var scaledVariableSumTemplate =
157        new RangeTemplate(minValue: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 0.1, 1)),
158          valueRange: new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 1, 5))) { Label = "*" };
159      scaledVariableSumTemplate.AddArguments(variableSums);
160      var scaledVariableSums = Instantiate(scaledVariableSumTemplate, uniformRandom, variables.Length * 2,
161        "scaledvarsum");
162
163      var fracTemplate = new BinaryOperatorTemplate(Division) { Label = "/" };
164      fracTemplate.AddLeftArguments(variables);
165      fracTemplate.AddRightArguments(scaledVariableSums);
166
167      var scaledExprTemplate = new ScalingTemplate(new DoublePrngDistribution(new UniformDistributedRandom(uniformRandom, 1, 10))) { Label = "*" };
168      if (useLog) scaledExprTemplate.AddArguments(Instantiate(logTemplate, uniformRandom, scaledVars.Count(), "log"));
169      if (useExp) scaledExprTemplate.AddArguments(Instantiate(expTemplate, uniformRandom, variables.Length, "exp"));
170      if (useFrac) scaledExprTemplate.AddArguments(Enumerable.Range(0, 20).Select(i => fracTemplate.Instantiate("frac" + i, uniformRandom, false)));
171
172      var mainTemplate = new RandomArityTemplate(Sum, arityDistribution: new DiscreteUniformDistribution(uniformRandom, 3, 5));
173      mainTemplate.AddArguments(scaledVars);
174      if (useLog || useExp) {
175        mainTemplate.AddArguments(Instantiate(scaledExprTemplate, uniformRandom, 20, "scaledExpr"));
176      }
177      mainTemplate.Label = "+";
178
179      return mainTemplate;
180    }
181
182    public static Expression Polynomial(IRandom uniformRandom, Expression[] variables, bool useLog, bool useExp) {
183      const int count = 10; // how many instances of each template should be produce?
184      int i = 1;
185      // the main template
186      var template = new RandomArityTemplate(Sum, arityDistribution: new DiscreteUniformDistribution(uniformRandom, 2, count)) { Label = "+" };
187      template.AddArguments(variables);
188
189      var sumTemplate = new RandomArityTemplate(Sum, arityDistribution: new DiscreteUniformDistribution(uniformRandom, 1, variables.Length)) { Label = "+" };
190      sumTemplate.AddArguments(variables);
191
192      var productTemplate = new RandomArityTemplate(Product, arityDistribution: new DiscreteUniformDistribution(uniformRandom, 1, variables.Length)) { Label = "*" };
193      productTemplate.AddArguments(variables);
194
195      var inverseTemplate = new FixedArityTemplate(Division, 1) { Label = "/" };
196      inverseTemplate.AddArguments(variables);
197      inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => sumTemplate.Instantiate(string.Format("sum{0}", i++), uniformRandom)));
198      inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => productTemplate.Instantiate(string.Format("prod{0}", i++), uniformRandom)));
199
200      if (useLog) {
201        var logTemplate = new FixedArityTemplate(Log, 1) { Label = "log" };
202        logTemplate.AddArguments(variables);
203        logTemplate.AddArguments(Enumerable.Range(1, count).Select(x => sumTemplate.Instantiate(string.Format("sum{0}", i++), uniformRandom)));
204        template.AddArguments(Enumerable.Range(1, count).Select(x => logTemplate.Instantiate(string.Format("log{0}", i++), uniformRandom)));
205        inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => logTemplate.Instantiate(string.Format("log{0}", i++), uniformRandom)));
206      }
207
208      if (useExp) {
209        var expTemplate = new FixedArityTemplate(Exp, 1) { Label = "exp" };
210        expTemplate.AddArguments(variables);
211        expTemplate.AddArguments(Enumerable.Range(1, count).Select(x => productTemplate.Instantiate(string.Format("prod{0}", i++), uniformRandom)));
212        template.AddArguments(Enumerable.Range(1, count).Select(x => expTemplate.Instantiate(string.Format("exp{0}", i++), uniformRandom)));
213        inverseTemplate.AddArguments(Enumerable.Range(1, count).Select(x => expTemplate.Instantiate(string.Format("exp{0}", i++), uniformRandom)));
214      }
215
216      template.AddArguments(Enumerable.Range(1, count).Select(x => inverseTemplate.Instantiate(string.Format("inv{0}", i++), uniformRandom)));
217      return template.Instantiate("polynomial", uniformRandom);
218    }
219
220    // variance random must have support only positive numbers
221    private static ExpressionTemplate ScaledExpression(IRandom uniformRandom, IEnumerable<Expression> arguments, IDistribution<double> varianceDistribution) {
222      var scalingTemplate = new ScalingTemplate(scaledVariance: varianceDistribution);
223      scalingTemplate.AddArguments(arguments);
224      scalingTemplate.Label = "*";
225      return scalingTemplate;
226    }
227
228    /// template scales and translates the argument expression first to guarantee positive values
229    private static ExpressionTemplate LogOfScaledExpression(IRandom uniformRandom, IEnumerable<Expression> arguments,
230      IDistribution<double> minValue = null, IDistribution<double> valueRange = null) {
231      var limitToRangeTemplate = new RangeTemplate(minValue, valueRange);
232      limitToRangeTemplate.AddArguments(arguments);
233
234      var logTemplate = new FixedArityTemplate(Log, 1) { Label = "log" };
235      logTemplate.AddArguments(Enumerable.Range(1, arguments.Count()).Select(i => limitToRangeTemplate.Instantiate(string.Format("log{0}", i), uniformRandom, false)));
236      return logTemplate;
237    }
238
239    /// template scales the argument expression first to guarantee reasonable values
240    private static ExpressionTemplate ExpOfScaledExpression(IRandom uniformRandom, IEnumerable<Expression> arguments,
241      IDistribution<double> minValue = null,
242      IDistribution<double> valueRange = null) {
243      var limitToRangeTemplate = new RangeTemplate(minValue, valueRange);
244      limitToRangeTemplate.AddArguments(arguments);
245
246      var expTemplate = new FixedArityTemplate(Exp, 1) { Label = "exp" };
247      expTemplate.AddArguments(Enumerable.Range(1, arguments.Count()).Select(i => limitToRangeTemplate.Instantiate(string.Format("exp{0}", i), uniformRandom, false)));
248      return expTemplate;
249    }
250
251    public static IEnumerable<Expression> Instantiate(ExpressionTemplate template, IRandom random, int count, string name) {
252      return Enumerable.Range(1, count).Select(i => template.Instantiate(name + i, random, false));
253    }
254
255    #region static functions
256    public static double Sum(IEnumerable<double> args) {
257      return args.Sum();
258    }
259
260    public static double Product(IEnumerable<double> args) {
261      return args.Aggregate((x, y) => x * y);
262    }
263
264    public static double Division(IEnumerable<double> args) {
265      if (args.Count() == 1)
266        return 1 / args.First();
267
268      return args.Aggregate((x, y) => x / y);
269    }
270
271    public static double Subtraction(IEnumerable<double> args) {
272      if (args.Count() == 1)
273        return -args.First();
274
275      return args.Aggregate((x, y) => x - y);
276    }
277
278    public static double Exp(IEnumerable<double> args) {
279      return Math.Exp(args.Single());
280    }
281
282    public static double Log(IEnumerable<double> args) {
283      return Math.Log(args.Single());
284    }
285
286    public static double Square(IEnumerable<double> args) {
287      var v = args.Single();
288      return v * v;
289    }
290    #endregion
291  }
292}
Note: See TracBrowser for help on using the repository browser.