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

Last change on this file since 14186 was 14186, checked in by swagner, 3 years ago

#2526: Updated year of copyrights in license headers

File size: 23.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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
38    private static Dataset ds = new Dataset(new string[] { "Y", "A", "B" }, new double[,] {
39        { 1.0, 1.0, 1.0 },
40        { 2.0, 2.0, 2.0 },
41        { 3.0, 1.0, 2.0 },
42        { 4.0, 1.0, 1.0 },
43        { 5.0, 2.0, 2.0 },
44        { 6.0, 1.0, 2.0 },
45        { 7.0, 1.0, 1.0 },
46        { 8.0, 2.0, 2.0 },
47        { 9.0, 1.0, 2.0 },
48        { 10.0, 1.0, 1.0 },
49        { 11.0, 2.0, 2.0 },
50        { 12.0, 1.0, 2.0 }
51      });
52
53    [TestMethod]
54    [TestCategory("Problems.DataAnalysis.Symbolic")]
55    [TestProperty("Time", "long")]
56    public void StandardInterpreterTestTypeCoherentGrammarPerformance() {
57      TestTypeCoherentGrammarPerformance(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
58    }
59    [TestMethod]
60    [TestCategory("Problems.DataAnalysis.Symbolic")]
61    [TestProperty("Time", "long")]
62    public void StandardInterpreterTestFullGrammarPerformance() {
63      TestFullGrammarPerformance(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
64    }
65    [TestMethod]
66    [TestCategory("Problems.DataAnalysis.Symbolic")]
67    [TestProperty("Time", "long")]
68    public void StandardInterpreterTestArithmeticGrammarPerformance() {
69      TestArithmeticGrammarPerformance(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
70    }
71
72
73    [TestMethod]
74    [TestCategory("Problems.DataAnalysis.Symbolic")]
75    [TestProperty("Time", "long")]
76    public void ILEmittingInterpreterTestTypeCoherentGrammarPerformance() {
77      TestTypeCoherentGrammarPerformance(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
78    }
79    [TestMethod]
80    [TestCategory("Problems.DataAnalysis.Symbolic")]
81    [TestProperty("Time", "long")]
82    public void ILEmittingInterpreterTestFullGrammarPerformance() {
83      TestFullGrammarPerformance(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
84    }
85    [TestMethod]
86    [TestCategory("Problems.DataAnalysis.Symbolic")]
87    [TestProperty("Time", "long")]
88    public void ILEmittingInterpreterTestArithmeticGrammarPerformance() {
89      TestArithmeticGrammarPerformance(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
90    }
91
92
93    [TestMethod]
94    [TestCategory("Problems.DataAnalysis.Symbolic")]
95    [TestProperty("Time", "long")]
96    public void LinearInterpreterTestTypeCoherentGrammarPerformance() {
97      TestTypeCoherentGrammarPerformance(new SymbolicDataAnalysisExpressionTreeLinearInterpreter(), 12.5e6);
98    }
99    [TestMethod]
100    [TestCategory("Problems.DataAnalysis.Symbolic")]
101    [TestProperty("Time", "long")]
102    public void LinearInterpreterTestFullGrammarPerformance() {
103      TestFullGrammarPerformance(new SymbolicDataAnalysisExpressionTreeLinearInterpreter(), 12.5e6);
104    }
105    [TestMethod]
106    [TestCategory("Problems.DataAnalysis.Symbolic")]
107    [TestProperty("Time", "long")]
108    public void LinearInterpreterTestArithmeticGrammarPerformance() {
109      TestArithmeticGrammarPerformance(new SymbolicDataAnalysisExpressionTreeLinearInterpreter(), 12.5e6);
110    }
111
112    private void TestTypeCoherentGrammarPerformance(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
113      var twister = new MersenneTwister(31415);
114      var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
115      var grammar = new TypeCoherentExpressionGrammar();
116      grammar.ConfigureAsDefaultRegressionGrammar();
117      grammar.MaximumFunctionArguments = 0;
118      grammar.MaximumFunctionDefinitions = 0;
119      grammar.MinimumFunctionArguments = 0;
120      grammar.MinimumFunctionDefinitions = 0;
121      var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 100, 0, 0);
122      foreach (ISymbolicExpressionTree tree in randomTrees) {
123        Util.InitTree(tree, twister, new List<string>(dataset.VariableNames));
124      }
125      double nodesPerSec = Util.CalculateEvaluatedNodesPerSec(randomTrees, interpreter, dataset, 3);
126      //mkommend: commented due to performance issues on the builder
127      // Assert.IsTrue(nodesPerSec > nodesPerSecThreshold); // evaluated nodes per seconds must be larger than 15mNodes/sec
128    }
129
130    private void TestFullGrammarPerformance(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
131      var twister = new MersenneTwister(31415);
132      var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
133      var grammar = new FullFunctionalExpressionGrammar();
134      grammar.MaximumFunctionArguments = 0;
135      grammar.MaximumFunctionDefinitions = 0;
136      grammar.MinimumFunctionArguments = 0;
137      grammar.MinimumFunctionDefinitions = 0;
138      var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 100, 0, 0);
139      foreach (ISymbolicExpressionTree tree in randomTrees) {
140        Util.InitTree(tree, twister, new List<string>(dataset.VariableNames));
141      }
142      double nodesPerSec = Util.CalculateEvaluatedNodesPerSec(randomTrees, interpreter, dataset, 3);
143      //mkommend: commented due to performance issues on the builder
144      //Assert.IsTrue(nodesPerSec > nodesPerSecThreshold); // evaluated nodes per seconds must be larger than 15mNodes/sec
145    }
146
147    private void TestArithmeticGrammarPerformance(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
148      var twister = new MersenneTwister(31415);
149      var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
150      var grammar = new ArithmeticExpressionGrammar();
151      //grammar.Symbols.OfType<Variable>().First().Enabled = false;
152      grammar.MaximumFunctionArguments = 0;
153      grammar.MaximumFunctionDefinitions = 0;
154      grammar.MinimumFunctionArguments = 0;
155      grammar.MinimumFunctionDefinitions = 0;
156      var randomTrees = Util.CreateRandomTrees(twister, dataset, grammar, N, 1, 100, 0, 0);
157      foreach (SymbolicExpressionTree tree in randomTrees) {
158        Util.InitTree(tree, twister, new List<string>(dataset.VariableNames));
159      }
160
161      double nodesPerSec = Util.CalculateEvaluatedNodesPerSec(randomTrees, interpreter, dataset, 3);
162      //mkommend: commented due to performance issues on the builder
163      //Assert.IsTrue(nodesPerSec > nodesPerSecThreshold); // evaluated nodes per seconds must be larger than 15mNodes/sec
164    }
165
166
167    /// <summary>
168    ///A test for Evaluate
169    ///</summary>
170    [TestMethod]
171    [TestCategory("Problems.DataAnalysis.Symbolic")]
172    [TestProperty("Time", "short")]
173    public void StandardInterpreterTestEvaluation() {
174      var interpreter = new SymbolicDataAnalysisExpressionTreeInterpreter();
175      EvaluateTerminals(interpreter, ds);
176      EvaluateOperations(interpreter, ds);
177      EvaluateAdf(interpreter, ds);
178    }
179
180    [TestMethod]
181    [TestCategory("Problems.DataAnalysis.Symbolic")]
182    [TestProperty("Time", "short")]
183    public void ILEmittingInterpreterTestEvaluation() {
184      var interpreter = new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter();
185      EvaluateTerminals(interpreter, ds);
186      EvaluateOperations(interpreter, ds);
187    }
188
189    [TestMethod]
190    [TestCategory("Problems.DataAnalysis.Symbolic")]
191    [TestProperty("Time", "short")]
192    public void LinearInterpreterTestEvaluation() {
193      var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
194
195      //ADFs are not supported by the linear interpreter
196      EvaluateTerminals(interpreter, ds);
197      EvaluateOperations(interpreter, ds);
198    }
199
200    private void EvaluateTerminals(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
201      // constants
202      Evaluate(interpreter, ds, "(+ 1.5 3.5)", 0, 5.0);
203
204      // variables
205      Evaluate(interpreter, ds, "(variable 2.0 a)", 0, 2.0);
206      Evaluate(interpreter, ds, "(variable 2.0 a)", 1, 4.0);
207    }
208
209    private void EvaluateAdf(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
210
211      // ADF     
212      Evaluate(interpreter, ds, @"(PROG
213                                    (MAIN
214                                      (CALL ADF0))
215                                    (defun ADF0 1.0))", 1, 1.0);
216      Evaluate(interpreter, ds, @"(PROG
217                                    (MAIN
218                                      (* (CALL ADF0) (CALL ADF0)))
219                                    (defun ADF0 2.0))", 1, 4.0);
220      Evaluate(interpreter, ds, @"(PROG
221                                    (MAIN
222                                      (CALL ADF0 2.0 3.0))
223                                    (defun ADF0
224                                      (+ (ARG 0) (ARG 1))))", 1, 5.0);
225      Evaluate(interpreter, ds, @"(PROG
226                                    (MAIN (CALL ADF1 2.0 3.0))
227                                    (defun ADF0
228                                      (- (ARG 1) (ARG 0)))
229                                    (defun ADF1
230                                      (+ (CALL ADF0 (ARG 1) (ARG 0))
231                                         (CALL ADF0 (ARG 0) (ARG 1)))))", 1, 0.0);
232      Evaluate(interpreter, ds, @"(PROG
233                                    (MAIN (CALL ADF1 (variable 2.0 a) 3.0))
234                                    (defun ADF0
235                                      (- (ARG 1) (ARG 0)))
236                                    (defun ADF1                                                                             
237                                      (CALL ADF0 (ARG 1) (ARG 0))))", 1, 1.0);
238      Evaluate(interpreter, ds,
239               @"(PROG
240                                    (MAIN (CALL ADF1 (variable 2.0 a) 3.0))
241                                    (defun ADF0
242                                      (- (ARG 1) (ARG 0)))
243                                    (defun ADF1                                                                             
244                                      (+ (CALL ADF0 (ARG 1) (ARG 0))
245                                         (CALL ADF0 (ARG 0) (ARG 1)))))", 1, 0.0);
246    }
247
248    private void EvaluateOperations(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds) {
249      // addition
250      Evaluate(interpreter, ds, "(+ (variable 2.0 a ))", 1, 4.0);
251      Evaluate(interpreter, ds, "(+ (variable 2.0 a ) (variable 3.0 b ))", 0, 5.0);
252      Evaluate(interpreter, ds, "(+ (variable 2.0 a ) (variable 3.0 b ))", 1, 10.0);
253      Evaluate(interpreter, ds, "(+ (variable 2.0 a) (variable 3.0 b ))", 2, 8.0);
254      Evaluate(interpreter, ds, "(+ 8.0 2.0 2.0)", 0, 12.0);
255
256      // subtraction
257      Evaluate(interpreter, ds, "(- (variable 2.0 a ))", 1, -4.0);
258      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b))", 0, -1.0);
259      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b ))", 1, -2.0);
260      Evaluate(interpreter, ds, "(- (variable 2.0 a ) (variable 3.0 b ))", 2, -4.0);
261      Evaluate(interpreter, ds, "(- 8.0 2.0 2.0)", 0, 4.0);
262
263      // multiplication
264      Evaluate(interpreter, ds, "(* (variable 2.0 a ))", 0, 2.0);
265      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 0, 6.0);
266      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 1, 24.0);
267      Evaluate(interpreter, ds, "(* (variable 2.0 a ) (variable 3.0 b ))", 2, 12.0);
268      Evaluate(interpreter, ds, "(* 8.0 2.0 2.0)", 0, 32.0);
269
270      // division
271      Evaluate(interpreter, ds, "(/ (variable 2.0 a ))", 1, 1.0 / 4.0);
272      Evaluate(interpreter, ds, "(/ (variable 2.0 a ) 2.0)", 0, 1.0);
273      Evaluate(interpreter, ds, "(/ (variable 2.0 a ) 2.0)", 1, 2.0);
274      Evaluate(interpreter, ds, "(/ (variable 3.0 b ) 2.0)", 2, 3.0);
275      Evaluate(interpreter, ds, "(/ 8.0 2.0 2.0)", 0, 2.0);
276
277      // gt
278      Evaluate(interpreter, ds, "(> (variable 2.0 a) 2.0)", 0, -1.0);
279      Evaluate(interpreter, ds, "(> 2.0 (variable 2.0 a))", 0, -1.0);
280      Evaluate(interpreter, ds, "(> (variable 2.0 a) 1.9)", 0, 1.0);
281      Evaluate(interpreter, ds, "(> 1.9 (variable 2.0 a))", 0, -1.0);
282      Evaluate(interpreter, ds, "(> (log -1.0) (log -1.0))", 0, -1.0); // (> nan nan) should be false
283
284      // lt
285      Evaluate(interpreter, ds, "(< (variable 2.0 a) 2.0)", 0, -1.0);
286      Evaluate(interpreter, ds, "(< 2.0 (variable 2.0 a))", 0, -1.0);
287      Evaluate(interpreter, ds, "(< (variable 2.0 a) 1.9)", 0, -1.0);
288      Evaluate(interpreter, ds, "(< 1.9 (variable 2.0 a))", 0, 1.0);
289      Evaluate(interpreter, ds, "(< (log -1.0) (log -1.0))", 0, -1.0); // (< nan nan) should be false
290
291      // If
292      Evaluate(interpreter, ds, "(if -10.0 2.0 3.0)", 0, 3.0);
293      Evaluate(interpreter, ds, "(if -1.0 2.0 3.0)", 0, 3.0);
294      Evaluate(interpreter, ds, "(if 0.0 2.0 3.0)", 0, 3.0);
295      Evaluate(interpreter, ds, "(if 1.0 2.0 3.0)", 0, 2.0);
296      Evaluate(interpreter, ds, "(if 10.0 2.0 3.0)", 0, 2.0);
297      Evaluate(interpreter, ds, "(if (log -1.0) 2.0 3.0)", 0, 3.0); // if(nan) should return the else branch
298
299      // NOT
300      Evaluate(interpreter, ds, "(not -1.0)", 0, 1.0);
301      Evaluate(interpreter, ds, "(not -2.0)", 0, 1.0);
302      Evaluate(interpreter, ds, "(not 1.0)", 0, -1.0);
303      Evaluate(interpreter, ds, "(not 2.0)", 0, -1.0);
304      Evaluate(interpreter, ds, "(not 0.0)", 0, 1.0);
305      Evaluate(interpreter, ds, "(not (log -1.0))", 0, 1.0);
306
307      // AND
308      Evaluate(interpreter, ds, "(and -1.0 -2.0)", 0, -1.0);
309      Evaluate(interpreter, ds, "(and -1.0 2.0)", 0, -1.0);
310      Evaluate(interpreter, ds, "(and 1.0 -2.0)", 0, -1.0);
311      Evaluate(interpreter, ds, "(and 1.0 0.0)", 0, -1.0);
312      Evaluate(interpreter, ds, "(and 0.0 0.0)", 0, -1.0);
313      Evaluate(interpreter, ds, "(and 1.0 2.0)", 0, 1.0);
314      Evaluate(interpreter, ds, "(and 1.0 2.0 3.0)", 0, 1.0);
315      Evaluate(interpreter, ds, "(and 1.0 -2.0 3.0)", 0, -1.0);
316      Evaluate(interpreter, ds, "(and (log -1.0))", 0, -1.0); // (and NaN)
317      Evaluate(interpreter, ds, "(and (log -1.0)  1.0)", 0, -1.0); // (and NaN 1.0)
318
319      // OR
320      Evaluate(interpreter, ds, "(or -1.0 -2.0)", 0, -1.0);
321      Evaluate(interpreter, ds, "(or -1.0 2.0)", 0, 1.0);
322      Evaluate(interpreter, ds, "(or 1.0 -2.0)", 0, 1.0);
323      Evaluate(interpreter, ds, "(or 1.0 2.0)", 0, 1.0);
324      Evaluate(interpreter, ds, "(or 0.0 0.0)", 0, -1.0);
325      Evaluate(interpreter, ds, "(or -1.0 -2.0 -3.0)", 0, -1.0);
326      Evaluate(interpreter, ds, "(or -1.0 -2.0 3.0)", 0, 1.0);
327      Evaluate(interpreter, ds, "(or (log -1.0))", 0, -1.0); // (or NaN)
328      Evaluate(interpreter, ds, "(or (log -1.0)  1.0)", 0, -1.0); // (or NaN 1.0)
329
330      // XOR
331      Evaluate(interpreter, ds, "(xor -1.0 -2.0)", 0, -1.0);
332      Evaluate(interpreter, ds, "(xor -1.0 2.0)", 0, 1.0);
333      Evaluate(interpreter, ds, "(xor 1.0 -2.0)", 0, 1.0);
334      Evaluate(interpreter, ds, "(xor 1.0 2.0)", 0, -1.0);
335      Evaluate(interpreter, ds, "(xor 0.0 0.0)", 0, -1.0);
336      Evaluate(interpreter, ds, "(xor -1.0 -2.0 -3.0)", 0, -1.0);
337      Evaluate(interpreter, ds, "(xor -1.0 -2.0 3.0)", 0, 1.0);
338      Evaluate(interpreter, ds, "(xor -1.0 2.0 3.0)", 0, -1.0);
339      Evaluate(interpreter, ds, "(xor 1.0 2.0 3.0)", 0, 1.0);
340      Evaluate(interpreter, ds, "(xor (log -1.0))", 0, -1.0);
341      Evaluate(interpreter, ds, "(xor (log -1.0)  1.0)", 0, 1.0);
342
343      // sin, cos, tan
344      Evaluate(interpreter, ds, "(sin " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, 0.0);
345      Evaluate(interpreter, ds, "(sin 0.0)", 0, 0.0);
346      Evaluate(interpreter, ds, "(cos " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, -1.0);
347      Evaluate(interpreter, ds, "(cos 0.0)", 0, 1.0);
348      Evaluate(interpreter, ds, "(tan " + Math.PI.ToString(NumberFormatInfo.InvariantInfo) + ")", 0, Math.Tan(Math.PI));
349      Evaluate(interpreter, ds, "(tan 0.0)", 0, Math.Tan(Math.PI));
350
351      // exp, log
352      Evaluate(interpreter, ds, "(log (exp 7.0))", 0, Math.Log(Math.Exp(7)));
353      Evaluate(interpreter, ds, "(exp (log 7.0))", 0, Math.Exp(Math.Log(7)));
354      Evaluate(interpreter, ds, "(log -3.0)", 0, Math.Log(-3));
355
356      // power
357      Evaluate(interpreter, ds, "(pow 2.0 3.0)", 0, 8.0);
358      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)
359      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)
360      Evaluate(interpreter, ds, "(pow -2.0 3.0)", 0, -8.0);
361      Evaluate(interpreter, ds, "(pow 2.0 -3.0)", 0, 1.0 / 8.0);
362      Evaluate(interpreter, ds, "(pow -2.0 -3.0)", 0, -1.0 / 8.0);
363
364      // root
365      Evaluate(interpreter, ds, "(root 9.0 2.0)", 0, 3.0);
366      Evaluate(interpreter, ds, "(root 27.0 3.0)", 0, 3.0);
367      Evaluate(interpreter, ds, "(root 2.0 -3.0)", 0, Math.Pow(2.0, -1.0 / 3.0));
368
369      // mean
370      Evaluate(interpreter, ds, "(mean -1.0 1.0 -1.0)", 0, -1.0 / 3.0);
371
372      // lag
373      Evaluate(interpreter, ds, "(lagVariable 1.0 a -1) ", 1, ds.GetDoubleValue("A", 0));
374      Evaluate(interpreter, ds, "(lagVariable 1.0 a -1) ", 2, ds.GetDoubleValue("A", 1));
375      Evaluate(interpreter, ds, "(lagVariable 1.0 a 0) ", 2, ds.GetDoubleValue("A", 2));
376      Evaluate(interpreter, ds, "(lagVariable 1.0 a 1) ", 0, ds.GetDoubleValue("A", 1));
377
378      // integral
379      Evaluate(interpreter, ds, "(integral -1.0 (variable 1.0 a)) ", 1, ds.GetDoubleValue("A", 0) + ds.GetDoubleValue("A", 1));
380      Evaluate(interpreter, ds, "(integral -1.0 (lagVariable 1.0 a 1)) ", 1, ds.GetDoubleValue("A", 1) + ds.GetDoubleValue("A", 2));
381      Evaluate(interpreter, ds, "(integral -2.0 (variable 1.0 a)) ", 2, ds.GetDoubleValue("A", 0) + ds.GetDoubleValue("A", 1) + ds.GetDoubleValue("A", 2));
382      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));
383      Evaluate(interpreter, ds, "(integral -2.0 3.0)", 1, 9.0);
384
385      // derivative
386      // (f_0 + 2 * f_1 - 2 * f_3 - f_4) / 8; // h = 1
387      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);
388      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);
389      Evaluate(interpreter, ds, "(diff (* (variable 1.0 a) (variable 1.0 b)))", 5, +
390        (ds.GetDoubleValue("A", 5) * ds.GetDoubleValue("B", 5) +
391        2 * ds.GetDoubleValue("A", 4) * ds.GetDoubleValue("B", 4) -
392        2 * ds.GetDoubleValue("A", 2) * ds.GetDoubleValue("B", 2) -
393        ds.GetDoubleValue("A", 1) * ds.GetDoubleValue("B", 1)) / 8.0);
394      Evaluate(interpreter, ds, "(diff -2.0 3.0)", 5, 0.0);
395
396      // timelag
397      Evaluate(interpreter, ds, "(lag -1.0 (lagVariable 1.0 a 2)) ", 1, ds.GetDoubleValue("A", 2));
398      Evaluate(interpreter, ds, "(lag -2.0 (lagVariable 1.0 a 2)) ", 2, ds.GetDoubleValue("A", 2));
399      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));
400      Evaluate(interpreter, ds, "(lag -2.0 3.0)", 1, 3.0);
401
402      {
403        // special functions
404        Action<double> checkAiry = (x) => {
405          double ai, aip, bi, bip;
406          alglib.airy(x, out ai, out aip, out bi, out bip);
407          Evaluate(interpreter, ds, "(airya " + x + ")", 0, ai);
408          Evaluate(interpreter, ds, "(airyb " + x + ")", 0, bi);
409        };
410
411        Action<double> checkBessel = (x) => {
412          Evaluate(interpreter, ds, "(bessel " + x + ")", 0, alglib.besseli0(x));
413        };
414
415        Action<double> checkSinCosIntegrals = (x) => {
416          double si, ci;
417          alglib.sinecosineintegrals(x, out si, out ci);
418          Evaluate(interpreter, ds, "(cosint " + x + ")", 0, ci);
419          Evaluate(interpreter, ds, "(sinint " + x + ")", 0, si);
420        };
421        Action<double> checkHypSinCosIntegrals = (x) => {
422          double shi, chi;
423          alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
424          Evaluate(interpreter, ds, "(hypcosint " + x + ")", 0, chi);
425          Evaluate(interpreter, ds, "(hypsinint " + x + ")", 0, shi);
426        };
427        Action<double> checkFresnelSinCosIntegrals = (x) => {
428          double c = 0, s = 0;
429          alglib.fresnelintegral(x, ref c, ref s);
430          Evaluate(interpreter, ds, "(fresnelcosint " + x + ")", 0, c);
431          Evaluate(interpreter, ds, "(fresnelsinint " + x + ")", 0, s);
432        };
433        Action<double> checkNormErf = (x) => {
434          Evaluate(interpreter, ds, "(norm " + x + ")", 0, alglib.normaldistribution(x));
435          Evaluate(interpreter, ds, "(erf " + x + ")", 0, alglib.errorfunction(x));
436        };
437
438        Action<double> checkGamma = (x) => {
439          Evaluate(interpreter, ds, "(gamma " + x + ")", 0, alglib.gammafunction(x));
440        };
441        Action<double> checkPsi = (x) => {
442          try {
443            Evaluate(interpreter, ds, "(psi " + x + ")", 0, alglib.psi(x));
444          }
445          catch (alglib.alglibexception) { // ignore cases where alglib throws an exception
446          }
447        };
448        Action<double> checkDawson = (x) => {
449          Evaluate(interpreter, ds, "(dawson " + x + ")", 0, alglib.dawsonintegral(x));
450        };
451        Action<double> checkExpInt = (x) => {
452          Evaluate(interpreter, ds, "(expint " + x + ")", 0, alglib.exponentialintegralei(x));
453        };
454
455
456
457        foreach (var e in new[] { -2.0, -1.0, 0.0, 1.0, 2.0 }) {
458          checkAiry(e);
459          checkBessel(e);
460          checkSinCosIntegrals(e);
461          checkGamma(e);
462          checkExpInt(e);
463          checkDawson(e);
464          checkPsi(e);
465          checkNormErf(e);
466          checkFresnelSinCosIntegrals(e);
467          checkHypSinCosIntegrals(e);
468        }
469      }
470    }
471
472    private void Evaluate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset ds, string expr, int index, double expected) {
473      var importer = new SymbolicExpressionImporter();
474      ISymbolicExpressionTree tree = importer.Import(expr);
475
476      double actual = interpreter.GetSymbolicExpressionTreeValues(tree, ds, Enumerable.Range(index, 1)).First();
477
478      Assert.IsFalse(double.IsNaN(actual) && !double.IsNaN(expected));
479      Assert.IsFalse(!double.IsNaN(actual) && double.IsNaN(expected));
480      if (!double.IsNaN(actual) && !double.IsNaN(expected))
481        Assert.AreEqual(expected, actual, 1.0E-12, expr);
482    }
483  }
484}
Note: See TracBrowser for help on using the repository browser.