Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1640 fixed a bug in the interpretation of lagged variables introduced with r6740.

File size: 14.9 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      });
114
115      var interpreter = new SymbolicDataAnalysisExpressionTreeInterpreter();
116      EvaluateTerminals(interpreter, ds);
117      EvaluateOperations(interpreter, ds);
118      EvaluateAdf(interpreter, ds);
119    }
120
121    [TestMethod]
122    public void SymbolicDataAnalysisExpressionILEmittingTreeInterpreterEvaluateTest() {
123      Dataset ds = new Dataset(new string[] { "Y", "A", "B" }, new double[,] {
124        { 1.0, 1.0, 1.0 },
125        { 2.0, 2.0, 2.0 },
126        { 3.0, 1.0, 2.0 }
127      });
128
129      var interpreter = new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter();
130      EvaluateTerminals(interpreter, ds);
131      EvaluateOperations(interpreter, ds);
132    }
133
134    private void EvaluateTerminals(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
135      // constants
136      Evaluate(interpreter, ds, "(+ 1.5 3.5)", 0, 5.0);
137
138      // variables
139      Evaluate(interpreter, ds, "(variable 2.0 a)", 0, 2.0);
140      Evaluate(interpreter, ds, "(variable 2.0 a)", 1, 4.0);
141    }
142
143    private void EvaluateAdf(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
144
145      // ADF     
146      Evaluate(interpreter, ds, @"(PROG
147                                    (MAIN
148                                      (CALL ADF0))
149                                    (defun ADF0 1.0))", 1, 1.0);
150      Evaluate(interpreter, ds, @"(PROG
151                                    (MAIN
152                                      (* (CALL ADF0) (CALL ADF0)))
153                                    (defun ADF0 2.0))", 1, 4.0);
154      Evaluate(interpreter, ds, @"(PROG
155                                    (MAIN
156                                      (CALL ADF0 2.0 3.0))
157                                    (defun ADF0
158                                      (+ (ARG 0) (ARG 1))))", 1, 5.0);
159      Evaluate(interpreter, ds, @"(PROG
160                                    (MAIN (CALL ADF1 2.0 3.0))
161                                    (defun ADF0
162                                      (- (ARG 1) (ARG 0)))
163                                    (defun ADF1
164                                      (+ (CALL ADF0 (ARG 1) (ARG 0))
165                                         (CALL ADF0 (ARG 0) (ARG 1)))))", 1, 0.0);
166      Evaluate(interpreter, ds, @"(PROG
167                                    (MAIN (CALL ADF1 (variable 2.0 a) 3.0))
168                                    (defun ADF0
169                                      (- (ARG 1) (ARG 0)))
170                                    (defun ADF1                                                                             
171                                      (CALL ADF0 (ARG 1) (ARG 0))))", 1, 1.0);
172      Evaluate(interpreter, ds,
173               @"(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))
179                                         (CALL ADF0 (ARG 0) (ARG 1)))))", 1, 0.0);
180    }
181
182    private void EvaluateOperations(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
183      // addition
184      Evaluate(interpreter, ds, "(+ (variable 2.0 a ))", 1, 4.0);
185      Evaluate(interpreter, ds, "(+ (variable 2.0 a ) (variable 3.0 b ))", 0, 5.0);
186      Evaluate(interpreter, ds, "(+ (variable 2.0 a ) (variable 3.0 b ))", 1, 10.0);
187      Evaluate(interpreter, ds, "(+ (variable 2.0 a) (variable 3.0 b ))", 2, 8.0);
188      Evaluate(interpreter, ds, "(+ 8.0 2.0 2.0)", 0, 12.0);
189
190      // subtraction
191      Evaluate(interpreter, ds, "(- (variable 2.0 a ))", 1, -4.0);
192      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b))", 0, -1.0);
193      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b ))", 1, -2.0);
194      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b ))", 2, -4.0);
195      Evaluate(interpreter, ds, "(- 8.0 2.0 2.0)", 0, 4.0);
196
197      // multiplication
198      Evaluate(interpreter, ds, "(* (variable 2.0 a ))", 0, 2.0);
199      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 0, 6.0);
200      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 1, 24.0);
201      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 2, 12.0);
202      Evaluate(interpreter, ds, "(* 8.0 2.0 2.0)", 0, 32.0);
203
204      // division
205      Evaluate(interpreter, ds, "(/ (variable 2.0 a ))", 1, 1.0 / 4.0);
206      Evaluate(interpreter, ds, "(/ (variable 2.0 a ) 2.0)", 0, 1.0);
207      Evaluate(interpreter, ds, "(/ (variable 2.0 a ) 2.0)", 1, 2.0);
208      Evaluate(interpreter, ds, "(/ (variable 3.0 b ) 2.0)", 2, 3.0);
209      Evaluate(interpreter, ds, "(/ 8.0 2.0 2.0)", 0, 2.0);
210
211      // gt
212      Evaluate(interpreter, ds, "(> (variable 2.0 a) 2.0)", 0, -1.0);
213      Evaluate(interpreter, ds, "(> 2.0 (variable 2.0 a))", 0, -1.0);
214      Evaluate(interpreter, ds, "(> (variable 2.0 a) 1.9)", 0, 1.0);
215      Evaluate(interpreter, ds, "(> 1.9 (variable 2.0 a))", 0, -1.0);
216      Evaluate(interpreter, ds, "(> (log -1.0) (log -1.0))", 0, -1.0); // (> nan nan) should be false
217
218      // lt
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      // If
226      Evaluate(interpreter, ds, "(if -10.0 2.0 3.0)", 0, 3.0);
227      Evaluate(interpreter, ds, "(if -1.0 2.0 3.0)", 0, 3.0);
228      Evaluate(interpreter, ds, "(if 0.0 2.0 3.0)", 0, 3.0);
229      Evaluate(interpreter, ds, "(if 1.0 2.0 3.0)", 0, 2.0);
230      Evaluate(interpreter, ds, "(if 10.0 2.0 3.0)", 0, 2.0);
231      Evaluate(interpreter, ds, "(if (log -1.0) 2.0 3.0)", 0, 3.0); // if(nan) should return the else branch
232
233      // NOT
234      Evaluate(interpreter, ds, "(not -1.0)", 0, 1.0);
235      Evaluate(interpreter, ds, "(not -2.0)", 0, 1.0);
236      Evaluate(interpreter, ds, "(not 1.0)", 0, -1.0);
237      Evaluate(interpreter, ds, "(not 2.0)", 0, -1.0);
238      Evaluate(interpreter, ds, "(not 0.0)", 0, 1.0);
239      Evaluate(interpreter, ds, "(not (log -1.0))", 0, 1.0);
240
241      // AND
242      Evaluate(interpreter, ds, "(and -1.0 -2.0)", 0, -1.0);
243      Evaluate(interpreter, ds, "(and -1.0 2.0)", 0, -1.0);
244      Evaluate(interpreter, ds, "(and 1.0 -2.0)", 0, -1.0);
245      Evaluate(interpreter, ds, "(and 1.0 0.0)", 0, -1.0);
246      Evaluate(interpreter, ds, "(and 0.0 0.0)", 0, -1.0);
247      Evaluate(interpreter, ds, "(and 1.0 2.0)", 0, 1.0);
248      Evaluate(interpreter, ds, "(and 1.0 2.0 3.0)", 0, 1.0);
249      Evaluate(interpreter, ds, "(and 1.0 -2.0 3.0)", 0, -1.0);
250      Evaluate(interpreter, ds, "(and (log -1.0))", 0, -1.0); // (and NaN)
251      Evaluate(interpreter, ds, "(and (log -1.0)  1.0)", 0, -1.0); // (and NaN 1.0)
252
253
254      // OR
255      Evaluate(interpreter, ds, "(or -1.0 -2.0)", 0, -1.0);
256      Evaluate(interpreter, ds, "(or -1.0 2.0)", 0, 1.0);
257      Evaluate(interpreter, ds, "(or 1.0 -2.0)", 0, 1.0);
258      Evaluate(interpreter, ds, "(or 1.0 2.0)", 0, 1.0);
259      Evaluate(interpreter, ds, "(or 0.0 0.0)", 0, -1.0);
260      Evaluate(interpreter, ds, "(or -1.0 -2.0 -3.0)", 0, -1.0);
261      Evaluate(interpreter, ds, "(or -1.0 -2.0 3.0)", 0, 1.0);
262      Evaluate(interpreter, ds, "(or (log -1.0))", 0, -1.0); // (or NaN)
263      Evaluate(interpreter, ds, "(or (log -1.0)  1.0)", 0, -1.0); // (or NaN 1.0)
264
265      // sin, cos, tan
266      Evaluate(interpreter, ds, "(sin " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, 0.0);
267      Evaluate(interpreter, ds, "(sin 0.0)", 0, 0.0);
268      Evaluate(interpreter, ds, "(cos " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, -1.0);
269      Evaluate(interpreter, ds, "(cos 0.0)", 0, 1.0);
270      Evaluate(interpreter, ds, "(tan " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, Math.Tan(Math.PI));
271      Evaluate(interpreter, ds, "(tan 0.0)", 0, Math.Tan(Math.PI));
272
273      // exp, log
274      Evaluate(interpreter, ds, "(log (exp 7.0))", 0, Math.Log(Math.Exp(7)));
275      Evaluate(interpreter, ds, "(exp (log 7.0))", 0, Math.Exp(Math.Log(7)));
276      Evaluate(interpreter, ds, "(log -3.0)", 0, Math.Log(-3));
277
278      // power
279      Evaluate(interpreter, ds, "(pow 2.0 3.0)", 0, 8.0);
280      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)
281      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)
282      Evaluate(interpreter, ds, "(pow -2.0 3.0)", 0, -8.0);
283      Evaluate(interpreter, ds, "(pow 2.0 -3.0)", 0, 1.0 / 8.0);
284      Evaluate(interpreter, ds, "(pow -2.0 -3.0)", 0, -1.0 / 8.0);
285
286      // root
287      Evaluate(interpreter, ds, "(root 9.0 2.0)", 0, 3.0);
288      Evaluate(interpreter, ds, "(root 27.0 3.0)", 0, 3.0);
289      Evaluate(interpreter, ds, "(root 2.0 -3.0)", 0, Math.Pow(2.0, -1.0 / 3.0));
290
291      // mean
292      Evaluate(interpreter, ds, "(mean -1.0 1.0 -1.0)", 0, -1.0 / 3.0);
293
294      // lag
295      Evaluate(interpreter, ds, "(lagVariable 1.0 a -1) ", 1, ds.GetDoubleValue("A", 0));
296      Evaluate(interpreter, ds, "(lagVariable 1.0 a -1) ", 2, ds.GetDoubleValue("A", 1));
297      Evaluate(interpreter, ds, "(lagVariable 1.0 a 0) ", 2, ds.GetDoubleValue("A", 2));
298      Evaluate(interpreter, ds, "(lagVariable 1.0 a 1) ", 0, ds.GetDoubleValue("A", 1));
299    }
300
301    private void Evaluate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds, string expr, int index, double expected) {
302      var importer = new SymbolicExpressionImporter();
303      ISymbolicExpressionTree tree = importer.Import(expr);
304
305      double actual = interpreter.GetSymbolicExpressionTreeValues(tree, ds, Enumerable.Range(index, 1)).First();
306
307      Assert.AreEqual(expected, actual, 1.0E-12, expr);
308    }
309  }
310}
Note: See TracBrowser for help on using the repository browser.