#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.Common; using HeuristicLab.Core; using HeuristicLab.Random; namespace HeuristicLab.ExpressionGenerator { public abstract class ExpressionTemplate { protected List> arguments; protected readonly Func, double> transform; public string Label { get; set; } protected Expression Instantiate(string name, IRandom random, int n, bool sampleWithRepetition = false) { var func = Expression.Function(name, transform, SampleArguments(random, n, sampleWithRepetition)); func.Label = Label; return func; } protected IEnumerable SampleArguments(IRandom random, int n, bool sampleWithRepetition = false) { var weights = arguments.Select(x => x.Item2); var args = sampleWithRepetition ? arguments.SampleProportional(random, n, weights).Select(x => x.Item1) : arguments.SampleProportionalWithoutRepetition(random, n, weights).Select(x => x.Item1); return args; } public abstract Expression Instantiate(string name, IRandom random, bool sampleWithRepetition = false); protected ExpressionTemplate(Func, double> transform) { this.transform = transform; } public void AddArgument(Expression expression, double weight = 1d) { arguments = arguments ?? new List>(); arguments.Add(Tuple.Create(expression, weight)); } public void AddArguments(IEnumerable expressions) { arguments = arguments ?? new List>(); arguments.AddRange(expressions.Select(x => Tuple.Create(x, 1d))); } public void AddArguments(IEnumerable expressions, IEnumerable weights) { arguments = arguments ?? new List>(); arguments.AddRange(expressions.Zip(weights, Tuple.Create)); } } public class RandomArityTemplate : ExpressionTemplate { private readonly IRandom arityDistribution; public RandomArityTemplate(Func, double> transform, IRandom arityDistribution) : base(transform) { this.arityDistribution = arityDistribution; } public override Expression Instantiate(string name, IRandom random, bool sampleWithRepetition = false) { var arity = (int)Math.Round(arityDistribution.NextDouble()); return Instantiate(name, random, arity, sampleWithRepetition); } } public class FixedArityTemplate : ExpressionTemplate { private readonly int arity; public FixedArityTemplate(Func, double> transform, int arity) : base(transform) { this.arity = arity; } public override Expression Instantiate(string name, IRandom random, bool sampleWithRepetition = false) { return Instantiate(name, random, arity, sampleWithRepetition); } } public class ScalingTemplate : ExpressionTemplate { private readonly IRandom scaledVariance; // w * expr public ScalingTemplate(IRandom scaledVariance = null) : base(ExpressionGenerator.Product) { this.scaledVariance = scaledVariance; } public override Expression Instantiate(string name, IRandom random, bool sampleWithRepetition = false) { var expr = SampleArguments(random, 1, sampleWithRepetition).First(); // use the evaluator to determine variance of the sampled expression and initialize the constant accordingly to reach the target variance var @const = 1.0; if (scaledVariance != null) { var evaluator = new ExpressionEvaluator(); var data = evaluator.GenerateData(expr, 10000); var variance = data[expr].VariancePop(); @const = scaledVariance.NextDouble() / variance; } var func = Expression.Function(name, transform, new Expression[] { Expression.Constant(name, @const), expr }); func.Label = "*"; return func; } } public class OffsetTemplate : ExpressionTemplate { private readonly IRandom offset; // expr + offset public OffsetTemplate(IRandom offset = null) : base(ExpressionGenerator.Sum) { this.offset = offset; } public override Expression Instantiate(string name, IRandom random, bool sampleWithRepetition = false) { var expr = SampleArguments(random, 1, sampleWithRepetition).First(); // use the evaluator to determine variance of the sampled expression and initialize the constant accordingly to reach the target offset var @const = 0.0; if (offset != null) { var evaluator = new ExpressionEvaluator(); var data = evaluator.GenerateData(expr, 10000); var average = data[expr].Average(); @const = offset.NextDouble() - average; } var func = Expression.Function(name, transform, new Expression[] { Expression.Constant(name, @const), expr }); func.Label = "+"; return func; } } public class RangeTemplate : ExpressionTemplate { private readonly IRandom minValue; private readonly IRandom valueRange; // expr + offset public RangeTemplate(IRandom minValue = null, IRandom valueRange = null) : base(null) { this.minValue = minValue; this.valueRange = valueRange; } public override Expression Instantiate(string name, IRandom random, bool sampleWithRepetition = false) { var expr = SampleArguments(random, 1, sampleWithRepetition).First(); // use the evaluator to determine variance of the sampled expression and initialize the constant accordingly to reach the target offset var mult = 1.0; var add = 0.0; if (minValue != null || valueRange != null) { var evaluator = new ExpressionEvaluator(); var data = evaluator.GenerateData(expr, 10000); if (valueRange != null) { var targetRange = valueRange.NextDouble(); var min = data[expr].Min(); var max = data[expr].Max(); var range = max - min; mult = targetRange / range; add = -min + min / mult; } if (minValue != null) { var targetMin = minValue.NextDouble(); var min = data[expr].Min(); add += (targetMin - min) / mult; } expr = Expression.Function(name + "-toZero", ExpressionGenerator.Sum, new Expression[] { Expression.Constant("name-add0", add), expr }); expr.Label = "+"; expr = Expression.Function(name + "-mult", ExpressionGenerator.Product, new Expression[] { Expression.Constant("name-mult", mult), expr }); expr.Label = "*"; } return expr; } } }