Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs @ 17456

Last change on this file since 17456 was 17181, checked in by swagner, 5 years ago

#2875: Merged r17180 from trunk to stable

File size: 23.8 KB
RevLine 
[5571]1#region License Information
2/* HeuristicLab
[17181]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[5571]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 HeuristicLab.Common;
25using HeuristicLab.Core;
[6740]26using HeuristicLab.Data;
[5571]27using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
[6740]28using HeuristicLab.Parameters;
[17097]29using HEAL.Attic;
[5571]30
31namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
[17097]32  [StorableType("FB94F333-B32A-44FB-A561-CBDE76693D20")]
[5571]33  [Item("SymbolicDataAnalysisExpressionTreeInterpreter", "Interpreter for symbolic expression trees including automatically defined functions.")]
[14811]34  public class SymbolicDataAnalysisExpressionTreeInterpreter : ParameterizedNamedItem,
35    ISymbolicDataAnalysisExpressionTreeInterpreter {
[5749]36    private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
[14811]37    private const string CheckExpressionsWithIntervalArithmeticParameterDescription = "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.";
[7615]38    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
[5571]39
[14811]40    public override bool CanChangeName {
41      get { return false; }
42    }
[5571]43
[14811]44    public override bool CanChangeDescription {
45      get { return false; }
46    }
47
[5749]48    #region parameter properties
[14811]49    public IFixedValueParameter<BoolValue> CheckExpressionsWithIntervalArithmeticParameter {
50      get { return (IFixedValueParameter<BoolValue>)Parameters[CheckExpressionsWithIntervalArithmeticParameterName]; }
[5749]51    }
[7615]52
[14811]53    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {
54      get { return (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
[7615]55    }
[5749]56    #endregion
57
58    #region properties
[14811]59    public bool CheckExpressionsWithIntervalArithmetic {
60      get { return CheckExpressionsWithIntervalArithmeticParameter.Value.Value; }
61      set { CheckExpressionsWithIntervalArithmeticParameter.Value.Value = value; }
[5749]62    }
[7615]63
[14811]64    public int EvaluatedSolutions {
65      get { return EvaluatedSolutionsParameter.Value.Value; }
66      set { EvaluatedSolutionsParameter.Value.Value = value; }
[7615]67    }
[5749]68    #endregion
69
[5571]70    [StorableConstructor]
[17097]71    protected SymbolicDataAnalysisExpressionTreeInterpreter(StorableConstructorFlag _) : base(_) { }
[14811]72
73    protected SymbolicDataAnalysisExpressionTreeInterpreter(SymbolicDataAnalysisExpressionTreeInterpreter original,
74      Cloner cloner)
75      : base(original, cloner) { }
76
[5571]77    public override IDeepCloneable Clone(Cloner cloner) {
78      return new SymbolicDataAnalysisExpressionTreeInterpreter(this, cloner);
79    }
80
81    public SymbolicDataAnalysisExpressionTreeInterpreter()
[5749]82      : base("SymbolicDataAnalysisExpressionTreeInterpreter", "Interpreter for symbolic expression trees including automatically defined functions.") {
[14811]83      Parameters.Add(new FixedValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", new BoolValue(false)));
84      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
[5571]85    }
86
[8436]87    protected SymbolicDataAnalysisExpressionTreeInterpreter(string name, string description)
88      : base(name, description) {
[14811]89      Parameters.Add(new FixedValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", new BoolValue(false)));
90      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
[8436]91    }
92
[7615]93    [StorableHook(HookType.AfterDeserialization)]
94    private void AfterDeserialization() {
[14811]95      var evaluatedSolutions = new IntValue(0);
96      var checkExpressionsWithIntervalArithmetic = new BoolValue(false);
97      if (Parameters.ContainsKey(EvaluatedSolutionsParameterName)) {
98        var evaluatedSolutionsParameter = (IValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName];
99        evaluatedSolutions = evaluatedSolutionsParameter.Value;
100        Parameters.Remove(EvaluatedSolutionsParameterName);
101      }
102      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", evaluatedSolutions));
103      if (Parameters.ContainsKey(CheckExpressionsWithIntervalArithmeticParameterName)) {
104        var checkExpressionsWithIntervalArithmeticParameter = (IValueParameter<BoolValue>)Parameters[CheckExpressionsWithIntervalArithmeticParameterName];
105        Parameters.Remove(CheckExpressionsWithIntervalArithmeticParameterName);
106        checkExpressionsWithIntervalArithmetic = checkExpressionsWithIntervalArithmeticParameter.Value;
107      }
108      Parameters.Add(new FixedValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, CheckExpressionsWithIntervalArithmeticParameterDescription, checkExpressionsWithIntervalArithmetic));
[7615]109    }
110
111    #region IStatefulItem
112    public void InitializeState() {
[14811]113      EvaluatedSolutions = 0;
[7615]114    }
115
[14811]116    public void ClearState() { }
[7615]117    #endregion
118
[14811]119    private readonly object syncRoot = new object();
120    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset,
121      IEnumerable<int> rows) {
122      if (CheckExpressionsWithIntervalArithmetic) {
[8436]123        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
[14811]124      }
[7120]125
[14811]126      lock (syncRoot) {
127        EvaluatedSolutions++; // increment the evaluated solutions counter
[9004]128      }
[8436]129      var state = PrepareInterpreterState(tree, dataset);
130
131      foreach (var rowEnum in rows) {
132        int row = rowEnum;
133        yield return Evaluate(dataset, ref row, state);
134        state.Reset();
135      }
[7154]136    }
137
[12702]138    private static InterpreterState PrepareInterpreterState(ISymbolicExpressionTree tree, IDataset dataset) {
[8436]139      Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
[5987]140      int necessaryArgStackSize = 0;
[8436]141      foreach (Instruction instr in code) {
[6860]142        if (instr.opCode == OpCodes.Variable) {
[8436]143          var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
[9976]144          instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
[15131]145        } else if (instr.opCode == OpCodes.FactorVariable) {
146          var factorTreeNode = instr.dynamicNode as FactorVariableTreeNode;
147          instr.data = dataset.GetReadOnlyStringValues(factorTreeNode.VariableName);
148        } else if (instr.opCode == OpCodes.BinaryFactorVariable) {
149          var factorTreeNode = instr.dynamicNode as BinaryFactorVariableTreeNode;
150          instr.data = dataset.GetReadOnlyStringValues(factorTreeNode.VariableName);
[5571]151        } else if (instr.opCode == OpCodes.LagVariable) {
[8436]152          var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
[9976]153          instr.data = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
[6860]154        } else if (instr.opCode == OpCodes.VariableCondition) {
[8436]155          var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
[9976]156          instr.data = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
[5987]157        } else if (instr.opCode == OpCodes.Call) {
158          necessaryArgStackSize += instr.nArguments + 1;
[5571]159        }
160      }
[8436]161      return new InterpreterState(code, necessaryArgStackSize);
162    }
[5571]163
[12702]164    public virtual double Evaluate(IDataset dataset, ref int row, InterpreterState state) {
[5571]165      Instruction currentInstr = state.NextInstruction();
166      switch (currentInstr.opCode) {
167        case OpCodes.Add: {
[8436]168            double s = Evaluate(dataset, ref row, state);
[5571]169            for (int i = 1; i < currentInstr.nArguments; i++) {
[8436]170              s += Evaluate(dataset, ref row, state);
[5571]171            }
172            return s;
173          }
174        case OpCodes.Sub: {
[8436]175            double s = Evaluate(dataset, ref row, state);
[5571]176            for (int i = 1; i < currentInstr.nArguments; i++) {
[8436]177              s -= Evaluate(dataset, ref row, state);
[5571]178            }
[14811]179            if (currentInstr.nArguments == 1) { s = -s; }
[5571]180            return s;
181          }
182        case OpCodes.Mul: {
[8436]183            double p = Evaluate(dataset, ref row, state);
[5571]184            for (int i = 1; i < currentInstr.nArguments; i++) {
[8436]185              p *= Evaluate(dataset, ref row, state);
[5571]186            }
187            return p;
188          }
189        case OpCodes.Div: {
[8436]190            double p = Evaluate(dataset, ref row, state);
[5571]191            for (int i = 1; i < currentInstr.nArguments; i++) {
[8436]192              p /= Evaluate(dataset, ref row, state);
[5571]193            }
[14811]194            if (currentInstr.nArguments == 1) { p = 1.0 / p; }
[5571]195            return p;
196          }
197        case OpCodes.Average: {
[8436]198            double sum = Evaluate(dataset, ref row, state);
[5571]199            for (int i = 1; i < currentInstr.nArguments; i++) {
[8436]200              sum += Evaluate(dataset, ref row, state);
[5571]201            }
202            return sum / currentInstr.nArguments;
203          }
[17072]204        case OpCodes.Absolute: {
205            return Math.Abs(Evaluate(dataset, ref row, state));
206          }
[17101]207        case OpCodes.Tanh: {
208            return Math.Tanh(Evaluate(dataset, ref row, state));
209          }
[5571]210        case OpCodes.Cos: {
[8436]211            return Math.Cos(Evaluate(dataset, ref row, state));
[5571]212          }
213        case OpCodes.Sin: {
[8436]214            return Math.Sin(Evaluate(dataset, ref row, state));
[5571]215          }
216        case OpCodes.Tan: {
[8436]217            return Math.Tan(Evaluate(dataset, ref row, state));
[5571]218          }
[7842]219        case OpCodes.Square: {
[8436]220            return Math.Pow(Evaluate(dataset, ref row, state), 2);
[7842]221          }
[17072]222        case OpCodes.Cube: {
223            return Math.Pow(Evaluate(dataset, ref row, state), 3);
224          }
[5571]225        case OpCodes.Power: {
[8436]226            double x = Evaluate(dataset, ref row, state);
227            double y = Math.Round(Evaluate(dataset, ref row, state));
[5571]228            return Math.Pow(x, y);
229          }
[7842]230        case OpCodes.SquareRoot: {
[8436]231            return Math.Sqrt(Evaluate(dataset, ref row, state));
[7842]232          }
[17072]233        case OpCodes.CubeRoot: {
[17103]234            var arg = Evaluate(dataset, ref row, state);
235            return arg < 0 ? -Math.Pow(-arg, 1.0 / 3.0) : Math.Pow(arg, 1.0 / 3.0);
[17072]236          }
[5571]237        case OpCodes.Root: {
[8436]238            double x = Evaluate(dataset, ref row, state);
239            double y = Math.Round(Evaluate(dataset, ref row, state));
[5571]240            return Math.Pow(x, 1 / y);
241          }
242        case OpCodes.Exp: {
[8436]243            return Math.Exp(Evaluate(dataset, ref row, state));
[5571]244          }
245        case OpCodes.Log: {
[8436]246            return Math.Log(Evaluate(dataset, ref row, state));
[5571]247          }
[7842]248        case OpCodes.Gamma: {
[8436]249            var x = Evaluate(dataset, ref row, state);
[14811]250            if (double.IsNaN(x)) { return double.NaN; } else { return alglib.gammafunction(x); }
[7842]251          }
252        case OpCodes.Psi: {
[8436]253            var x = Evaluate(dataset, ref row, state);
[7842]254            if (double.IsNaN(x)) return double.NaN;
[8430]255            else if (x <= 0 && (Math.Floor(x) - x).IsAlmost(0)) return double.NaN;
[7842]256            return alglib.psi(x);
257          }
258        case OpCodes.Dawson: {
[8436]259            var x = Evaluate(dataset, ref row, state);
[14811]260            if (double.IsNaN(x)) { return double.NaN; }
[7842]261            return alglib.dawsonintegral(x);
262          }
263        case OpCodes.ExponentialIntegralEi: {
[8436]264            var x = Evaluate(dataset, ref row, state);
[14811]265            if (double.IsNaN(x)) { return double.NaN; }
[7842]266            return alglib.exponentialintegralei(x);
267          }
268        case OpCodes.SineIntegral: {
269            double si, ci;
[8436]270            var x = Evaluate(dataset, ref row, state);
[7842]271            if (double.IsNaN(x)) return double.NaN;
272            else {
273              alglib.sinecosineintegrals(x, out si, out ci);
274              return si;
275            }
276          }
277        case OpCodes.CosineIntegral: {
278            double si, ci;
[8436]279            var x = Evaluate(dataset, ref row, state);
[7842]280            if (double.IsNaN(x)) return double.NaN;
281            else {
282              alglib.sinecosineintegrals(x, out si, out ci);
283              return ci;
284            }
285          }
286        case OpCodes.HyperbolicSineIntegral: {
287            double shi, chi;
[8436]288            var x = Evaluate(dataset, ref row, state);
[7842]289            if (double.IsNaN(x)) return double.NaN;
290            else {
291              alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
292              return shi;
293            }
294          }
295        case OpCodes.HyperbolicCosineIntegral: {
296            double shi, chi;
[8436]297            var x = Evaluate(dataset, ref row, state);
[7842]298            if (double.IsNaN(x)) return double.NaN;
299            else {
300              alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
301              return chi;
302            }
303          }
304        case OpCodes.FresnelCosineIntegral: {
305            double c = 0, s = 0;
[8436]306            var x = Evaluate(dataset, ref row, state);
[7842]307            if (double.IsNaN(x)) return double.NaN;
308            else {
309              alglib.fresnelintegral(x, ref c, ref s);
310              return c;
311            }
312          }
313        case OpCodes.FresnelSineIntegral: {
314            double c = 0, s = 0;
[8436]315            var x = Evaluate(dataset, ref row, state);
[7842]316            if (double.IsNaN(x)) return double.NaN;
317            else {
318              alglib.fresnelintegral(x, ref c, ref s);
319              return s;
320            }
321          }
322        case OpCodes.AiryA: {
323            double ai, aip, bi, bip;
[8436]324            var x = Evaluate(dataset, ref row, state);
[7842]325            if (double.IsNaN(x)) return double.NaN;
326            else {
327              alglib.airy(x, out ai, out aip, out bi, out bip);
328              return ai;
329            }
330          }
331        case OpCodes.AiryB: {
332            double ai, aip, bi, bip;
[8436]333            var x = Evaluate(dataset, ref row, state);
[7842]334            if (double.IsNaN(x)) return double.NaN;
335            else {
336              alglib.airy(x, out ai, out aip, out bi, out bip);
337              return bi;
338            }
339          }
340        case OpCodes.Norm: {
[8436]341            var x = Evaluate(dataset, ref row, state);
[7842]342            if (double.IsNaN(x)) return double.NaN;
343            else return alglib.normaldistribution(x);
344          }
345        case OpCodes.Erf: {
[8436]346            var x = Evaluate(dataset, ref row, state);
[7842]347            if (double.IsNaN(x)) return double.NaN;
348            else return alglib.errorfunction(x);
349          }
350        case OpCodes.Bessel: {
[8436]351            var x = Evaluate(dataset, ref row, state);
[7842]352            if (double.IsNaN(x)) return double.NaN;
353            else return alglib.besseli0(x);
354          }
[17072]355
356        case OpCodes.AnalyticQuotient: {
357            var x1 = Evaluate(dataset, ref row, state);
358            var x2 = Evaluate(dataset, ref row, state);
359            return x1 / Math.Pow(1 + x2 * x2, 0.5);
360          }
[5571]361        case OpCodes.IfThenElse: {
[8436]362            double condition = Evaluate(dataset, ref row, state);
[5571]363            double result;
364            if (condition > 0.0) {
[8436]365              result = Evaluate(dataset, ref row, state); state.SkipInstructions();
[5571]366            } else {
[8436]367              state.SkipInstructions(); result = Evaluate(dataset, ref row, state);
[5571]368            }
369            return result;
370          }
371        case OpCodes.AND: {
[8436]372            double result = Evaluate(dataset, ref row, state);
[5571]373            for (int i = 1; i < currentInstr.nArguments; i++) {
[8436]374              if (result > 0.0) result = Evaluate(dataset, ref row, state);
[5571]375              else {
[8436]376                state.SkipInstructions();
[5571]377              }
378            }
[6732]379            return result > 0.0 ? 1.0 : -1.0;
[5571]380          }
381        case OpCodes.OR: {
[8436]382            double result = Evaluate(dataset, ref row, state);
[5571]383            for (int i = 1; i < currentInstr.nArguments; i++) {
[8436]384              if (result <= 0.0) result = Evaluate(dataset, ref row, state);
[5571]385              else {
[8436]386                state.SkipInstructions();
[5571]387              }
388            }
389            return result > 0.0 ? 1.0 : -1.0;
390          }
391        case OpCodes.NOT: {
[8436]392            return Evaluate(dataset, ref row, state) > 0.0 ? -1.0 : 1.0;
[5571]393          }
[10910]394        case OpCodes.XOR: {
395            //mkommend: XOR on multiple inputs is defined as true if the number of positive signals is odd
396            // this is equal to a consecutive execution of binary XOR operations.
397            int positiveSignals = 0;
398            for (int i = 0; i < currentInstr.nArguments; i++) {
[14811]399              if (Evaluate(dataset, ref row, state) > 0.0) { positiveSignals++; }
[10910]400            }
401            return positiveSignals % 2 != 0 ? 1.0 : -1.0;
402          }
[5571]403        case OpCodes.GT: {
[8436]404            double x = Evaluate(dataset, ref row, state);
405            double y = Evaluate(dataset, ref row, state);
[14811]406            if (x > y) { return 1.0; } else { return -1.0; }
[5571]407          }
408        case OpCodes.LT: {
[8436]409            double x = Evaluate(dataset, ref row, state);
410            double y = Evaluate(dataset, ref row, state);
[14811]411            if (x < y) { return 1.0; } else { return -1.0; }
[5571]412          }
413        case OpCodes.TimeLag: {
414            var timeLagTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
415            row += timeLagTreeNode.Lag;
[8436]416            double result = Evaluate(dataset, ref row, state);
[5571]417            row -= timeLagTreeNode.Lag;
418            return result;
419          }
420        case OpCodes.Integral: {
421            int savedPc = state.ProgramCounter;
422            var timeLagTreeNode = (LaggedTreeNode)currentInstr.dynamicNode;
423            double sum = 0.0;
424            for (int i = 0; i < Math.Abs(timeLagTreeNode.Lag); i++) {
425              row += Math.Sign(timeLagTreeNode.Lag);
[8436]426              sum += Evaluate(dataset, ref row, state);
[5571]427              state.ProgramCounter = savedPc;
428            }
429            row -= timeLagTreeNode.Lag;
[8436]430            sum += Evaluate(dataset, ref row, state);
[5571]431            return sum;
432          }
433
434        //mkommend: derivate calculation taken from:
435        //http://www.holoborodko.com/pavel/numerical-methods/numerical-derivative/smooth-low-noise-differentiators/
436        //one sided smooth differentiatior, N = 4
437        // y' = 1/8h (f_i + 2f_i-1, -2 f_i-3 - f_i-4)
438        case OpCodes.Derivative: {
439            int savedPc = state.ProgramCounter;
[8436]440            double f_0 = Evaluate(dataset, ref row, state); row--;
[5571]441            state.ProgramCounter = savedPc;
[8436]442            double f_1 = Evaluate(dataset, ref row, state); row -= 2;
[5571]443            state.ProgramCounter = savedPc;
[8436]444            double f_3 = Evaluate(dataset, ref row, state); row--;
[5571]445            state.ProgramCounter = savedPc;
[8436]446            double f_4 = Evaluate(dataset, ref row, state);
[5571]447            row += 4;
448
449            return (f_0 + 2 * f_1 - 2 * f_3 - f_4) / 8; // h = 1
450          }
451        case OpCodes.Call: {
452            // evaluate sub-trees
453            double[] argValues = new double[currentInstr.nArguments];
454            for (int i = 0; i < currentInstr.nArguments; i++) {
[8436]455              argValues[i] = Evaluate(dataset, ref row, state);
[5571]456            }
457            // push on argument values on stack
458            state.CreateStackFrame(argValues);
459
460            // save the pc
461            int savedPc = state.ProgramCounter;
462            // set pc to start of function 
[9976]463            state.ProgramCounter = (ushort)currentInstr.data;
[5571]464            // evaluate the function
[8436]465            double v = Evaluate(dataset, ref row, state);
[5571]466
467            // delete the stack frame
468            state.RemoveStackFrame();
469
470            // restore the pc => evaluation will continue at point after my subtrees 
471            state.ProgramCounter = savedPc;
472            return v;
473          }
474        case OpCodes.Arg: {
[9976]475            return state.GetStackFrameValue((ushort)currentInstr.data);
[5571]476          }
477        case OpCodes.Variable: {
[8486]478            if (row < 0 || row >= dataset.Rows) return double.NaN;
[6740]479            var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
[9976]480            return ((IList<double>)currentInstr.data)[row] * variableTreeNode.Weight;
[5571]481          }
[15131]482        case OpCodes.BinaryFactorVariable: {
483            if (row < 0 || row >= dataset.Rows) return double.NaN;
484            var factorVarTreeNode = currentInstr.dynamicNode as BinaryFactorVariableTreeNode;
485            return ((IList<string>)currentInstr.data)[row] == factorVarTreeNode.VariableValue ? factorVarTreeNode.Weight : 0;
486          }
487        case OpCodes.FactorVariable: {
488            if (row < 0 || row >= dataset.Rows) return double.NaN;
489            var factorVarTreeNode = currentInstr.dynamicNode as FactorVariableTreeNode;
490            return factorVarTreeNode.GetValue(((IList<string>)currentInstr.data)[row]);
491          }
[5571]492        case OpCodes.LagVariable: {
[6740]493            var laggedVariableTreeNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
[5571]494            int actualRow = row + laggedVariableTreeNode.Lag;
[14811]495            if (actualRow < 0 || actualRow >= dataset.Rows) { return double.NaN; }
[9976]496            return ((IList<double>)currentInstr.data)[actualRow] * laggedVariableTreeNode.Weight;
[5571]497          }
498        case OpCodes.Constant: {
[8436]499            var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
[5897]500            return constTreeNode.Value;
[5571]501          }
502
503        //mkommend: this symbol uses the logistic function f(x) = 1 / (1 + e^(-alpha * x) )
504        //to determine the relative amounts of the true and false branch see http://en.wikipedia.org/wiki/Logistic_function
505        case OpCodes.VariableCondition: {
[8486]506            if (row < 0 || row >= dataset.Rows) return double.NaN;
[5571]507            var variableConditionTreeNode = (VariableConditionTreeNode)currentInstr.dynamicNode;
[15127]508            if (!variableConditionTreeNode.Symbol.IgnoreSlope) {
509              double variableValue = ((IList<double>)currentInstr.data)[row];
510              double x = variableValue - variableConditionTreeNode.Threshold;
511              double p = 1 / (1 + Math.Exp(-variableConditionTreeNode.Slope * x));
[5571]512
[15127]513              double trueBranch = Evaluate(dataset, ref row, state);
514              double falseBranch = Evaluate(dataset, ref row, state);
[5571]515
[15127]516              return trueBranch * p + falseBranch * (1 - p);
517            } else {
518              // strict threshold
519              double variableValue = ((IList<double>)currentInstr.data)[row];
520              if (variableValue <= variableConditionTreeNode.Threshold) {
521                var left = Evaluate(dataset, ref row, state);
522                state.SkipInstructions();
523                return left;
524              } else {
525                state.SkipInstructions();
526                return Evaluate(dataset, ref row, state);
527              }
528            }
[5571]529          }
[14811]530        default:
531          throw new NotSupportedException();
[5571]532      }
533    }
534  }
[14811]535}
Note: See TracBrowser for help on using the repository browser.