Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Tests/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs @ 6809

Last change on this file since 6809 was 6809, checked in by gkronber, 13 years ago

#1480 added check if row index lies within the possible range of the dataset and implemented interpretation of time series symbols in the IL emitting interpreter. Added test cases for evaluation of time series symbols.

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