Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs @ 17097

Last change on this file since 17097 was 17097, checked in by mkommend, 5 years ago

#2520: Merged 16565 - 16579 into stable.

File size: 17.9 KB
RevLine 
[8798]1#region License Information
2/* HeuristicLab
[17097]3 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[8798]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.Globalization;
25using System.Linq;
26using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[9885]27using HeuristicLab.Problems.DataAnalysis.Symbolic.Tests;
[8798]28using HeuristicLab.Random;
29using Microsoft.VisualStudio.TestTools.UnitTesting;
[9885]30namespace HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis.Tests {
[8798]31
32  [TestClass()]
33  public class SymbolicTimeSeriesPrognosisInterpreterTest {
34    private const int N = 1000;
35    private const int Rows = 100;
36    private const int Columns = 50;
37
38    [TestMethod]
[9976]39    [TestCategory("Problems.DataAnalysis.Symbolic")]
[9885]40    [TestProperty("Time", "long")]
[9976]41    public void TimeSeriesPrognosisInterpreterTestTypeCoherentGrammarPerformance() {
42      TestTypeCoherentGrammarPerformance(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
[8798]43    }
[9885]44
[8798]45    [TestMethod]
[9976]46    [TestCategory("Problems.DataAnalysis.Symbolic")]
[9885]47    [TestProperty("Time", "long")]
[9976]48    public void TimeSeriesPrognosisInterpreterTestFullGrammarPerformance() {
49      TestFullGrammarPerformance(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
[8798]50    }
[9885]51
[8798]52    [TestMethod]
[9976]53    [TestCategory("Problems.DataAnalysis.Symbolic")]
[9885]54    [TestProperty("Time", "long")]
[9976]55    public void TimeSeriesPrognosisInterpreterTestArithmeticGrammarPerformance() {
56      TestArithmeticGrammarPerformance(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
[8798]57    }
58
[9976]59    private void TestTypeCoherentGrammarPerformance(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
[8798]60      var twister = new MersenneTwister(31415);
61      var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
62      var grammar = new TypeCoherentExpressionGrammar();
63      grammar.ConfigureAsDefaultRegressionGrammar();
64      grammar.MaximumFunctionArguments = 0;
65      grammar.MaximumFunctionDefinitions = 0;
66      grammar.MinimumFunctionArguments = 0;
67      grammar.MinimumFunctionDefinitions = 0;
68      var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 100, 0, 0);
69      foreach (ISymbolicExpressionTree tree in randomTrees) {
70        Util.InitTree(tree, twister, new List<string>(dataset.VariableNames));
71      }
72      double nodesPerSec = Util.CalculateEvaluatedNodesPerSec(randomTrees, interpreter, dataset, 3);
[9322]73      //mkommend: commented due to performance issues on the builder
74      //Assert.IsTrue(nodesPerSec > nodesPerSecThreshold); // evaluated nodes per seconds must be larger than 15mNodes/sec
[8798]75    }
76
[9976]77    private void TestFullGrammarPerformance(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
[8798]78      var twister = new MersenneTwister(31415);
79      var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
80      var grammar = new FullFunctionalExpressionGrammar();
81      grammar.MaximumFunctionArguments = 0;
82      grammar.MaximumFunctionDefinitions = 0;
83      grammar.MinimumFunctionArguments = 0;
84      grammar.MinimumFunctionDefinitions = 0;
85      var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 100, 0, 0);
86      foreach (ISymbolicExpressionTree tree in randomTrees) {
87        Util.InitTree(tree, twister, new List<string>(dataset.VariableNames));
88      }
89      double nodesPerSec = Util.CalculateEvaluatedNodesPerSec(randomTrees, interpreter, dataset, 3);
[9322]90      //mkommend: commented due to performance issues on the builder
91      //Assert.IsTrue(nodesPerSec > nodesPerSecThreshold); // evaluated nodes per seconds must be larger than 15mNodes/sec
[8798]92    }
93
[9976]94    private void TestArithmeticGrammarPerformance(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
[8798]95      var twister = new MersenneTwister(31415);
96      var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
97      var grammar = new ArithmeticExpressionGrammar();
98      grammar.MaximumFunctionArguments = 0;
99      grammar.MaximumFunctionDefinitions = 0;
100      grammar.MinimumFunctionArguments = 0;
101      grammar.MinimumFunctionDefinitions = 0;
102      var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 100, 0, 0);
103      foreach (SymbolicExpressionTree tree in randomTrees) {
104        Util.InitTree(tree, twister, new List<string>(dataset.VariableNames));
105      }
106
107      double nodesPerSec = Util.CalculateEvaluatedNodesPerSec(randomTrees, interpreter, dataset, 3);
[9322]108      //mkommend: commented due to performance issues on the builder
109      //Assert.IsTrue(nodesPerSec > nodesPerSecThreshold); // evaluated nodes per seconds must be larger than 15mNodes/sec
[8798]110    }
111
112
113    /// <summary>
114    ///A test for Evaluate
115    ///</summary>
116    [TestMethod]
[9976]117    [TestCategory("Problems.DataAnalysis.Symbolic")]
[9885]118    [TestProperty("Time", "short")]
[9976]119    public void TimeSeriesPrognosisInterpreterTestEvaluation() {
[8798]120      Dataset ds = new Dataset(new string[] { "Y", "A", "B" }, new double[,] {
121        { 1.0, 1.0, 1.0 },
122        { 2.0, 2.0, 2.0 },
123        { 3.0, 1.0, 2.0 },
124        { 4.0, 1.0, 1.0 },
125        { 5.0, 2.0, 2.0 },
126        { 6.0, 1.0, 2.0 },
127        { 7.0, 1.0, 1.0 },
128        { 8.0, 2.0, 2.0 },
129        { 9.0, 1.0, 2.0 },
130        { 10.0, 1.0, 1.0 },
131        { 11.0, 2.0, 2.0 },
132        { 12.0, 1.0, 2.0 }
133      });
134
135      var interpreter = new SymbolicDataAnalysisExpressionTreeInterpreter();
136      EvaluateTerminals(interpreter, ds);
137      EvaluateOperations(interpreter, ds);
138      EvaluateAdf(interpreter, ds);
139    }
140
141    private void EvaluateTerminals(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
142      // constants
143      Evaluate(interpreter, ds, "(+ 1.5 3.5)", 0, 5.0);
144
145      // variables
146      Evaluate(interpreter, ds, "(variable 2.0 a)", 0, 2.0);
147      Evaluate(interpreter, ds, "(variable 2.0 a)", 1, 4.0);
148    }
149
150    private void EvaluateAdf(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
151
152      // ADF     
153      Evaluate(interpreter, ds, @"(PROG
154                                    (MAIN
155                                      (CALL ADF0))
156                                    (defun ADF0 1.0))", 1, 1.0);
157      Evaluate(interpreter, ds, @"(PROG
158                                    (MAIN
159                                      (* (CALL ADF0) (CALL ADF0)))
160                                    (defun ADF0 2.0))", 1, 4.0);
161      Evaluate(interpreter, ds, @"(PROG
162                                    (MAIN
163                                      (CALL ADF0 2.0 3.0))
164                                    (defun ADF0
165                                      (+ (ARG 0) (ARG 1))))", 1, 5.0);
166      Evaluate(interpreter, ds, @"(PROG
167                                    (MAIN (CALL ADF1 2.0 3.0))
168                                    (defun ADF0
169                                      (- (ARG 1) (ARG 0)))
170                                    (defun ADF1
171                                      (+ (CALL ADF0 (ARG 1) (ARG 0))
172                                         (CALL ADF0 (ARG 0) (ARG 1)))))", 1, 0.0);
173      Evaluate(interpreter, ds, @"(PROG
174                                    (MAIN (CALL ADF1 (variable 2.0 a) 3.0))
175                                    (defun ADF0
176                                      (- (ARG 1) (ARG 0)))
177                                    (defun ADF1                                                                             
178                                      (CALL ADF0 (ARG 1) (ARG 0))))", 1, 1.0);
179      Evaluate(interpreter, ds,
180               @"(PROG
181                                    (MAIN (CALL ADF1 (variable 2.0 a) 3.0))
182                                    (defun ADF0
183                                      (- (ARG 1) (ARG 0)))
184                                    (defun ADF1                                                                             
185                                      (+ (CALL ADF0 (ARG 1) (ARG 0))
186                                         (CALL ADF0 (ARG 0) (ARG 1)))))", 1, 0.0);
187    }
188
189    private void EvaluateOperations(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
190      // addition
191      Evaluate(interpreter, ds, "(+ (variable 2.0 a ))", 1, 4.0);
192      Evaluate(interpreter, ds, "(+ (variable 2.0 a ) (variable 3.0 b ))", 0, 5.0);
193      Evaluate(interpreter, ds, "(+ (variable 2.0 a ) (variable 3.0 b ))", 1, 10.0);
194      Evaluate(interpreter, ds, "(+ (variable 2.0 a) (variable 3.0 b ))", 2, 8.0);
195      Evaluate(interpreter, ds, "(+ 8.0 2.0 2.0)", 0, 12.0);
196
197      // subtraction
198      Evaluate(interpreter, ds, "(- (variable 2.0 a ))", 1, -4.0);
199      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b))", 0, -1.0);
200      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b ))", 1, -2.0);
201      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b ))", 2, -4.0);
202      Evaluate(interpreter, ds, "(- 8.0 2.0 2.0)", 0, 4.0);
203
204      // multiplication
205      Evaluate(interpreter, ds, "(* (variable 2.0 a ))", 0, 2.0);
206      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 0, 6.0);
207      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 1, 24.0);
208      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 2, 12.0);
209      Evaluate(interpreter, ds, "(* 8.0 2.0 2.0)", 0, 32.0);
210
211      // division
212      Evaluate(interpreter, ds, "(/ (variable 2.0 a ))", 1, 1.0 / 4.0);
213      Evaluate(interpreter, ds, "(/ (variable 2.0 a ) 2.0)", 0, 1.0);
214      Evaluate(interpreter, ds, "(/ (variable 2.0 a ) 2.0)", 1, 2.0);
215      Evaluate(interpreter, ds, "(/ (variable 3.0 b ) 2.0)", 2, 3.0);
216      Evaluate(interpreter, ds, "(/ 8.0 2.0 2.0)", 0, 2.0);
217
218      // gt
219      Evaluate(interpreter, ds, "(> (variable 2.0 a) 2.0)", 0, -1.0);
220      Evaluate(interpreter, ds, "(> 2.0 (variable 2.0 a))", 0, -1.0);
221      Evaluate(interpreter, ds, "(> (variable 2.0 a) 1.9)", 0, 1.0);
222      Evaluate(interpreter, ds, "(> 1.9 (variable 2.0 a))", 0, -1.0);
223      Evaluate(interpreter, ds, "(> (log -1.0) (log -1.0))", 0, -1.0); // (> nan nan) should be false
224
225      // lt
226      Evaluate(interpreter, ds, "(< (variable 2.0 a) 2.0)", 0, -1.0);
227      Evaluate(interpreter, ds, "(< 2.0 (variable 2.0 a))", 0, -1.0);
228      Evaluate(interpreter, ds, "(< (variable 2.0 a) 1.9)", 0, -1.0);
229      Evaluate(interpreter, ds, "(< 1.9 (variable 2.0 a))", 0, 1.0);
230      Evaluate(interpreter, ds, "(< (log -1.0) (log -1.0))", 0, -1.0); // (< nan nan) should be false
231
232      // If
233      Evaluate(interpreter, ds, "(if -10.0 2.0 3.0)", 0, 3.0);
234      Evaluate(interpreter, ds, "(if -1.0 2.0 3.0)", 0, 3.0);
235      Evaluate(interpreter, ds, "(if 0.0 2.0 3.0)", 0, 3.0);
236      Evaluate(interpreter, ds, "(if 1.0 2.0 3.0)", 0, 2.0);
237      Evaluate(interpreter, ds, "(if 10.0 2.0 3.0)", 0, 2.0);
238      Evaluate(interpreter, ds, "(if (log -1.0) 2.0 3.0)", 0, 3.0); // if(nan) should return the else branch
239
240      // NOT
241      Evaluate(interpreter, ds, "(not -1.0)", 0, 1.0);
242      Evaluate(interpreter, ds, "(not -2.0)", 0, 1.0);
243      Evaluate(interpreter, ds, "(not 1.0)", 0, -1.0);
244      Evaluate(interpreter, ds, "(not 2.0)", 0, -1.0);
245      Evaluate(interpreter, ds, "(not 0.0)", 0, 1.0);
246      Evaluate(interpreter, ds, "(not (log -1.0))", 0, 1.0);
247
248      // AND
249      Evaluate(interpreter, ds, "(and -1.0 -2.0)", 0, -1.0);
250      Evaluate(interpreter, ds, "(and -1.0 2.0)", 0, -1.0);
251      Evaluate(interpreter, ds, "(and 1.0 -2.0)", 0, -1.0);
252      Evaluate(interpreter, ds, "(and 1.0 0.0)", 0, -1.0);
253      Evaluate(interpreter, ds, "(and 0.0 0.0)", 0, -1.0);
254      Evaluate(interpreter, ds, "(and 1.0 2.0)", 0, 1.0);
255      Evaluate(interpreter, ds, "(and 1.0 2.0 3.0)", 0, 1.0);
256      Evaluate(interpreter, ds, "(and 1.0 -2.0 3.0)", 0, -1.0);
257      Evaluate(interpreter, ds, "(and (log -1.0))", 0, -1.0); // (and NaN)
258      Evaluate(interpreter, ds, "(and (log -1.0)  1.0)", 0, -1.0); // (and NaN 1.0)
259
260
261      // OR
262      Evaluate(interpreter, ds, "(or -1.0 -2.0)", 0, -1.0);
263      Evaluate(interpreter, ds, "(or -1.0 2.0)", 0, 1.0);
264      Evaluate(interpreter, ds, "(or 1.0 -2.0)", 0, 1.0);
265      Evaluate(interpreter, ds, "(or 1.0 2.0)", 0, 1.0);
266      Evaluate(interpreter, ds, "(or 0.0 0.0)", 0, -1.0);
267      Evaluate(interpreter, ds, "(or -1.0 -2.0 -3.0)", 0, -1.0);
268      Evaluate(interpreter, ds, "(or -1.0 -2.0 3.0)", 0, 1.0);
269      Evaluate(interpreter, ds, "(or (log -1.0))", 0, -1.0); // (or NaN)
270      Evaluate(interpreter, ds, "(or (log -1.0)  1.0)", 0, -1.0); // (or NaN 1.0)
271
272      // sin, cos, tan
273      Evaluate(interpreter, ds, "(sin " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, 0.0);
274      Evaluate(interpreter, ds, "(sin 0.0)", 0, 0.0);
275      Evaluate(interpreter, ds, "(cos " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, -1.0);
276      Evaluate(interpreter, ds, "(cos 0.0)", 0, 1.0);
277      Evaluate(interpreter, ds, "(tan " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, Math.Tan(Math.PI));
278      Evaluate(interpreter, ds, "(tan 0.0)", 0, Math.Tan(Math.PI));
279
280      // exp, log
281      Evaluate(interpreter, ds, "(log (exp 7.0))", 0, Math.Log(Math.Exp(7)));
282      Evaluate(interpreter, ds, "(exp (log 7.0))", 0, Math.Exp(Math.Log(7)));
283      Evaluate(interpreter, ds, "(log -3.0)", 0, Math.Log(-3));
284
285      // power
286      Evaluate(interpreter, ds, "(pow 2.0 3.0)", 0, 8.0);
287      Evaluate(interpreter, ds, "(pow 4.0 0.5)", 0, 1.0); // interpreter should round to the nearest integer value value (.5 is rounded to the even number)
288      Evaluate(interpreter, ds, "(pow 4.0 2.5)", 0, 16.0); // interpreter should round to the nearest integer value value (.5 is rounded to the even number)
289      Evaluate(interpreter, ds, "(pow -2.0 3.0)", 0, -8.0);
290      Evaluate(interpreter, ds, "(pow 2.0 -3.0)", 0, 1.0 / 8.0);
291      Evaluate(interpreter, ds, "(pow -2.0 -3.0)", 0, -1.0 / 8.0);
292
293      // root
294      Evaluate(interpreter, ds, "(root 9.0 2.0)", 0, 3.0);
295      Evaluate(interpreter, ds, "(root 27.0 3.0)", 0, 3.0);
296      Evaluate(interpreter, ds, "(root 2.0 -3.0)", 0, Math.Pow(2.0, -1.0 / 3.0));
297
298      // mean
299      Evaluate(interpreter, ds, "(mean -1.0 1.0 -1.0)", 0, -1.0 / 3.0);
300
301      // lag
302      Evaluate(interpreter, ds, "(lagVariable 1.0 a -1) ", 1, ds.GetDoubleValue("A", 0));
303      Evaluate(interpreter, ds, "(lagVariable 1.0 a -1) ", 2, ds.GetDoubleValue("A", 1));
304      Evaluate(interpreter, ds, "(lagVariable 1.0 a 0) ", 2, ds.GetDoubleValue("A", 2));
305      Evaluate(interpreter, ds, "(lagVariable 1.0 a 1) ", 0, ds.GetDoubleValue("A", 1));
306
307      // integral
308      Evaluate(interpreter, ds, "(integral -1.0 (variable 1.0 a)) ", 1, ds.GetDoubleValue("A", 0) + ds.GetDoubleValue("A", 1));
309      Evaluate(interpreter, ds, "(integral -1.0 (lagVariable 1.0 a 1)) ", 1, ds.GetDoubleValue("A", 1) + ds.GetDoubleValue("A", 2));
310      Evaluate(interpreter, ds, "(integral -2.0 (variable 1.0 a)) ", 2, ds.GetDoubleValue("A", 0) + ds.GetDoubleValue("A", 1) + ds.GetDoubleValue("A", 2));
311      Evaluate(interpreter, ds, "(integral -1.0 (* (variable 1.0 a) (variable 1.0 b)))", 1, ds.GetDoubleValue("A", 0) * ds.GetDoubleValue("B", 0) + ds.GetDoubleValue("A", 1) * ds.GetDoubleValue("B", 1));
312      Evaluate(interpreter, ds, "(integral -2.0 3.0)", 1, 9.0);
313
314      // derivative
315      // (f_0 + 2 * f_1 - 2 * f_3 - f_4) / 8; // h = 1
316      Evaluate(interpreter, ds, "(diff (variable 1.0 a)) ", 5, (ds.GetDoubleValue("A", 5) + 2 * ds.GetDoubleValue("A", 4) - 2 * ds.GetDoubleValue("A", 2) - ds.GetDoubleValue("A", 1)) / 8.0);
317      Evaluate(interpreter, ds, "(diff (variable 1.0 b)) ", 5, (ds.GetDoubleValue("B", 5) + 2 * ds.GetDoubleValue("B", 4) - 2 * ds.GetDoubleValue("B", 2) - ds.GetDoubleValue("B", 1)) / 8.0);
318      Evaluate(interpreter, ds, "(diff (* (variable 1.0 a) (variable 1.0 b)))", 5, +
319        (ds.GetDoubleValue("A", 5) * ds.GetDoubleValue("B", 5) +
320        2 * ds.GetDoubleValue("A", 4) * ds.GetDoubleValue("B", 4) -
321        2 * ds.GetDoubleValue("A", 2) * ds.GetDoubleValue("B", 2) -
322        ds.GetDoubleValue("A", 1) * ds.GetDoubleValue("B", 1)) / 8.0);
323      Evaluate(interpreter, ds, "(diff -2.0 3.0)", 5, 0.0);
324
325      // timelag
326      Evaluate(interpreter, ds, "(lag -1.0 (lagVariable 1.0 a 2)) ", 1, ds.GetDoubleValue("A", 2));
327      Evaluate(interpreter, ds, "(lag -2.0 (lagVariable 1.0 a 2)) ", 2, ds.GetDoubleValue("A", 2));
328      Evaluate(interpreter, ds, "(lag -1.0 (* (lagVariable 1.0 a 1) (lagVariable 1.0 b 2)))", 1, ds.GetDoubleValue("A", 1) * ds.GetDoubleValue("B", 2));
329      Evaluate(interpreter, ds, "(lag -2.0 3.0)", 1, 3.0);
330    }
331
332    private void Evaluate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds, string expr, int index, double expected) {
333      var importer = new SymbolicExpressionImporter();
334      ISymbolicExpressionTree tree = importer.Import(expr);
335
336      double actual = interpreter.GetSymbolicExpressionTreeValues(tree, ds, Enumerable.Range(index, 1)).First();
337
338      Assert.IsFalse(double.IsNaN(actual) && !double.IsNaN(expected));
339      Assert.IsFalse(!double.IsNaN(actual) && double.IsNaN(expected));
[11534]340      if (!double.IsNaN(actual) && !double.IsNaN(expected))
341        Assert.AreEqual(expected, actual, 1.0E-12, expr);
[8798]342    }
343  }
344}
Note: See TracBrowser for help on using the repository browser.