Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 6732 was 6732, checked in by gkronber, 12 years ago

#1480 added IL emitting tree interpreter for symbolic data analysis and test case. Found and fixed a bug in the existing interpreter for boolean operators OR and AND with NaN arguments. However, this means that the output of previously stored solutions changes. We Probably we should keep the incorrect behavior now and document this accordingly, as changing this would need a version increment of all data analysis plugins.

File size: 13.7 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(), 25e6);
64    }
65    [TestMethod]
66    public void SymbolicDataAnalysisExpressionTreeILEmittingInterpreterArithmeticGrammarPerformanceTest() {
67      FullGrammarPerformanceTest(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 25e6);
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      // mean
279      Evaluate(interpreter, ds, "(mean -1.0 1.0 -1.0)", 0, -1.0 / 3.0);
280
281    }
282
283    private void Evaluate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds, string expr, int index, double expected) {
284      var importer = new SymbolicExpressionImporter();
285      ISymbolicExpressionTree tree = importer.Import(expr);
286
287      double actual = interpreter.GetSymbolicExpressionTreeValues(tree, ds, Enumerable.Range(index, 1)).First();
288
289      Assert.AreEqual(expected, actual, 1.0E-12, expr);
290    }
291  }
292}
Note: See TracBrowser for help on using the repository browser.