#region License Information /* HeuristicLab * Copyright (C) 2002-2013 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.Analysis; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using Irony.Interpreter; using Irony.Parsing; namespace HeuristicLab.BenchmarkGenerator { [Item("Benchmark Generator", "Utility class to generate artificial datasets based on custom user-defined formulas.")] public class BenchmarkGenerator : Item { private readonly ExpressionEvaluator evaluator; private Parser Parser { get { return evaluator.Parser; } } private ParseTree Tree { get { return Parser.Context.CurrentParseTree; } } private IDictionary Globals { get { return evaluator.Globals; } } private DataTable table; [StorableConstructor] private BenchmarkGenerator(bool deserializing) : base(deserializing) { } protected BenchmarkGenerator(BenchmarkGenerator original, Cloner cloner) : base(original, cloner) { evaluator = original.evaluator; } public override IDeepCloneable Clone(Cloner cloner) { return new BenchmarkGenerator(this, cloner); } private void AddCustomFunctions() { var runtime = (CustomLanguageRuntime)evaluator.Runtime; runtime.BuiltIns.Clear(); runtime.BuiltIns.AddMethod(Functions.NormalDouble, "normal"); runtime.BuiltIns.AddMethod(Functions.UniformDouble, "uniform"); runtime.BuiltIns.AddMethod(Functions.NormalDistribution, "dnormal"); runtime.BuiltIns.AddMethod(Functions.UniformDistribution, "duniform"); runtime.BuiltIns.AddMethod(Functions.Steps, "steps"); runtime.BuiltIns.AddMethod(Functions.Repeat, "repeat"); runtime.BuiltIns.AddMethod(Functions.Sin, "sin"); runtime.BuiltIns.AddMethod(Functions.Cos, "cos"); runtime.BuiltIns.AddMethod(Functions.Length, "length"); runtime.BuiltIns.AddMethod(Functions.Abs, "abs"); runtime.BuiltIns.AddMethod(Functions.DotProduct, "dot"); } public BenchmarkGenerator() { evaluator = new ExpressionEvaluator(); AddCustomFunctions(); table = new DataTable("Data"); } public DataTable GenerateDataset(string formula, int nSamples) { Globals.Clear(); Parser.Parse(formula); if (Tree.Status == ParseTreeStatus.Error) { throw new Exception("Invalid formula."); } evaluator.Evaluate(Tree); // after the tree is parsed the variables are saved in the global dictionary // because the Globals only grow but never shrink, the values for unused keys are set to null // we check that below in order to remove unused keys from our table foreach (var pair in Globals) { var key = pair.Key; if (pair.Value == null) { table.Rows.Remove(key); continue; } var values = ((object[])Globals[key]).Cast().ToArray(); if (!table.Rows.ContainsKey(key)) { table.Rows.Add(new DataRow(key) { VisualProperties = { StartIndexZero = true } }); } table.Rows[key].Values.Clear(); table.Rows[key].Values.AddRange(values); } return table; } } }