public static LinearInstruction[] Compile(ISymbolicExpressionTree tree, Func <ISymbolicExpressionTreeNode, byte> opCodeMapper)
        {
            var root = tree.Root.GetSubtree(0).GetSubtree(0);
            var code = new LinearInstruction[root.GetLength()];

            code[0] = new LinearInstruction {
                dynamicNode = root, nArguments = (byte)root.SubtreeCount, opCode = opCodeMapper(root)
            };
            int c = 1, i = 0;

            foreach (var node in root.IterateNodesBreadth())
            {
                for (int j = 0; j < node.SubtreeCount; ++j)
                {
                    var s = node.GetSubtree(j);
                    code[c + j] = new LinearInstruction {
                        dynamicNode = s, nArguments = (byte)s.SubtreeCount, opCode = opCodeMapper(s)
                    };
                }
                code[i].childIndex = c;
                c += node.SubtreeCount;
                ++i;
            }
            return(code);
        }
        public static LinearInstruction[] Compile(ISymbolicExpressionTree tree, Func <ISymbolicExpressionTreeNode, byte> opCodeMapper)
        {
            var root = tree.Root.GetSubtree(0).GetSubtree(0);
            var code = new LinearInstruction[root.GetLength()];

            if (root.SubtreeCount > ushort.MaxValue)
            {
                throw new ArgumentException("Number of subtrees is too big (>65.535)");
            }
            code[0] = new LinearInstruction {
                dynamicNode = root, nArguments = (ushort)root.SubtreeCount, opCode = opCodeMapper(root)
            };
            int c = 1, i = 0;

            foreach (var node in root.IterateNodesBreadth())
            {
                for (int j = 0; j < node.SubtreeCount; ++j)
                {
                    var s = node.GetSubtree(j);
                    if (s.SubtreeCount > ushort.MaxValue)
                    {
                        throw new ArgumentException("Number of subtrees is too big (>65.535)");
                    }
                    code[c + j] = new LinearInstruction {
                        dynamicNode = s, nArguments = (ushort)s.SubtreeCount, opCode = opCodeMapper(s)
                    };
                }
                code[i].childIndex = c;
                c += node.SubtreeCount;
                ++i;
            }
            return(code);
        }
 public static LinearInstruction[] Compile(ISymbolicExpressionTree tree, Func<ISymbolicExpressionTreeNode, byte> opCodeMapper) {
   var root = tree.Root.GetSubtree(0).GetSubtree(0);
   var code = new LinearInstruction[root.GetLength()];
   code[0] = new LinearInstruction { dynamicNode = root, nArguments = (byte)root.SubtreeCount, opCode = opCodeMapper(root) };
   int c = 1, i = 0;
   foreach (var node in root.IterateNodesBreadth()) {
     for (int j = 0; j < node.SubtreeCount; ++j) {
       var s = node.GetSubtree(j);
       code[c + j] = new LinearInstruction { dynamicNode = s, nArguments = (byte)s.SubtreeCount, opCode = opCodeMapper(s) };
     }
     code[i].childIndex = c;
     c += node.SubtreeCount;
     ++i;
   }
   return code;
 }
 public static void PrepareInstructions(LinearInstruction[] code, IDataset dataset) {
   for (int i = 0; i != code.Length; ++i) {
     var instr = code[i];
     #region opcode switch
     switch (instr.opCode) {
       case OpCodes.Constant: {
           var constTreeNode = (ConstantTreeNode)instr.dynamicNode;
           instr.value = constTreeNode.Value;
           instr.skip = true; // the value is already set so this instruction should be skipped in the evaluation phase
         }
         break;
       case OpCodes.Variable: {
           var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
           instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
         }
         break;
       case OpCodes.LagVariable: {
           var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
           instr.data = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
         }
         break;
       case OpCodes.VariableCondition: {
           var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
           instr.data = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
         }
         break;
       case OpCodes.TimeLag:
       case OpCodes.Integral:
       case OpCodes.Derivative: {
           var seq = GetPrefixSequence(code, i);
           var interpreterState = new InterpreterState(seq, 0);
           instr.data = interpreterState;
           for (int j = 1; j != seq.Length; ++j)
             seq[j].skip = true;
         }
         break;
     }
     #endregion
   }
 }
 private static LinearInstruction[] GetPrefixSequence(LinearInstruction[] code, int startIndex) {
   var s = new Stack<int>();
   var list = new List<LinearInstruction>();
   s.Push(startIndex);
   while (s.Any()) {
     int i = s.Pop();
     var instr = code[i];
     // push instructions in reverse execution order
     for (int j = instr.nArguments - 1; j >= 0; j--) s.Push(instr.childIndex + j);
     list.Add(instr);
   }
   return list.ToArray();
 }
    private double Evaluate(IDataset dataset, int row, LinearInstruction[] code) {
      for (int i = code.Length - 1; i >= 0; --i) {
        if (code[i].skip) continue;
        #region opcode if
        var instr = code[i];
        if (instr.opCode == OpCodes.Variable) {
          if (row < 0 || row >= dataset.Rows) instr.value = double.NaN;
          var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
          instr.value = ((IList<double>)instr.data)[row] * variableTreeNode.Weight;
        } else if (instr.opCode == OpCodes.LagVariable) {
          var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
          int actualRow = row + laggedVariableTreeNode.Lag;
          if (actualRow < 0 || actualRow >= dataset.Rows)
            instr.value = double.NaN;
          else
            instr.value = ((IList<double>)instr.data)[actualRow] * laggedVariableTreeNode.Weight;
        } else if (instr.opCode == OpCodes.VariableCondition) {
          if (row < 0 || row >= dataset.Rows) instr.value = double.NaN;
          var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
          double variableValue = ((IList<double>)instr.data)[row];
          double x = variableValue - variableConditionTreeNode.Threshold;
          double p = 1 / (1 + Math.Exp(-variableConditionTreeNode.Slope * x));

          double trueBranch = code[instr.childIndex].value;
          double falseBranch = code[instr.childIndex + 1].value;

          instr.value = trueBranch * p + falseBranch * (1 - p);
        } else if (instr.opCode == OpCodes.Add) {
          double s = code[instr.childIndex].value;
          for (int j = 1; j != instr.nArguments; ++j) {
            s += code[instr.childIndex + j].value;
          }
          instr.value = s;
        } else if (instr.opCode == OpCodes.Sub) {
          double s = code[instr.childIndex].value;
          for (int j = 1; j != instr.nArguments; ++j) {
            s -= code[instr.childIndex + j].value;
          }
          if (instr.nArguments == 1) s = -s;
          instr.value = s;
        } else if (instr.opCode == OpCodes.Mul) {
          double p = code[instr.childIndex].value;
          for (int j = 1; j != instr.nArguments; ++j) {
            p *= code[instr.childIndex + j].value;
          }
          instr.value = p;
        } else if (instr.opCode == OpCodes.Div) {
          double p = code[instr.childIndex].value;
          for (int j = 1; j != instr.nArguments; ++j) {
            p /= code[instr.childIndex + j].value;
          }
          if (instr.nArguments == 1) p = 1.0 / p;
          instr.value = p;
        } else if (instr.opCode == OpCodes.Average) {
          double s = code[instr.childIndex].value;
          for (int j = 1; j != instr.nArguments; ++j) {
            s += code[instr.childIndex + j].value;
          }
          instr.value = s / instr.nArguments;
        } else if (instr.opCode == OpCodes.Cos) {
          instr.value = Math.Cos(code[instr.childIndex].value);
        } else if (instr.opCode == OpCodes.Sin) {
          instr.value = Math.Sin(code[instr.childIndex].value);
        } else if (instr.opCode == OpCodes.Tan) {
          instr.value = Math.Tan(code[instr.childIndex].value);
        } else if (instr.opCode == OpCodes.Square) {
          instr.value = Math.Pow(code[instr.childIndex].value, 2);
        } else if (instr.opCode == OpCodes.Power) {
          double x = code[instr.childIndex].value;
          double y = Math.Round(code[instr.childIndex + 1].value);
          instr.value = Math.Pow(x, y);
        } else if (instr.opCode == OpCodes.SquareRoot) {
          instr.value = Math.Sqrt(code[instr.childIndex].value);
        } else if (instr.opCode == OpCodes.Root) {
          double x = code[instr.childIndex].value;
          double y = code[instr.childIndex + 1].value;
          instr.value = Math.Pow(x, 1 / y);
        } else if (instr.opCode == OpCodes.Exp) {
          instr.value = Math.Exp(code[instr.childIndex].value);
        } else if (instr.opCode == OpCodes.Log) {
          instr.value = Math.Log(code[instr.childIndex].value);
        } else if (instr.opCode == OpCodes.Gamma) {
          var x = code[instr.childIndex].value;
          instr.value = double.IsNaN(x) ? double.NaN : alglib.gammafunction(x);
        } else if (instr.opCode == OpCodes.Psi) {
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else if (x <= 0 && (Math.Floor(x) - x).IsAlmost(0)) instr.value = double.NaN;
          else instr.value = alglib.psi(x);
        } else if (instr.opCode == OpCodes.Dawson) {
          var x = code[instr.childIndex].value;
          instr.value = double.IsNaN(x) ? double.NaN : alglib.dawsonintegral(x);
        } else if (instr.opCode == OpCodes.ExponentialIntegralEi) {
          var x = code[instr.childIndex].value;
          instr.value = double.IsNaN(x) ? double.NaN : alglib.exponentialintegralei(x);
        } else if (instr.opCode == OpCodes.SineIntegral) {
          double si, ci;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.sinecosineintegrals(x, out si, out ci);
            instr.value = si;
          }
        } else if (instr.opCode == OpCodes.CosineIntegral) {
          double si, ci;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.sinecosineintegrals(x, out si, out ci);
            instr.value = ci;
          }
        } else if (instr.opCode == OpCodes.HyperbolicSineIntegral) {
          double shi, chi;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
            instr.value = shi;
          }
        } else if (instr.opCode == OpCodes.HyperbolicCosineIntegral) {
          double shi, chi;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
            instr.value = chi;
          }
        } else if (instr.opCode == OpCodes.FresnelCosineIntegral) {
          double c = 0, s = 0;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.fresnelintegral(x, ref c, ref s);
            instr.value = c;
          }
        } else if (instr.opCode == OpCodes.FresnelSineIntegral) {
          double c = 0, s = 0;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.fresnelintegral(x, ref c, ref s);
            instr.value = s;
          }
        } else if (instr.opCode == OpCodes.AiryA) {
          double ai, aip, bi, bip;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.airy(x, out ai, out aip, out bi, out bip);
            instr.value = ai;
          }
        } else if (instr.opCode == OpCodes.AiryB) {
          double ai, aip, bi, bip;
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else {
            alglib.airy(x, out ai, out aip, out bi, out bip);
            instr.value = bi;
          }
        } else if (instr.opCode == OpCodes.Norm) {
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else instr.value = alglib.normaldistribution(x);
        } else if (instr.opCode == OpCodes.Erf) {
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else instr.value = alglib.errorfunction(x);
        } else if (instr.opCode == OpCodes.Bessel) {
          var x = code[instr.childIndex].value;
          if (double.IsNaN(x)) instr.value = double.NaN;
          else instr.value = alglib.besseli0(x);
        } else if (instr.opCode == OpCodes.IfThenElse) {
          double condition = code[instr.childIndex].value;
          double result;
          if (condition > 0.0) {
            result = code[instr.childIndex + 1].value;
          } else {
            result = code[instr.childIndex + 2].value;
          }
          instr.value = result;
        } else if (instr.opCode == OpCodes.AND) {
          double result = code[instr.childIndex].value;
          for (int j = 1; j < instr.nArguments; j++) {
            if (result > 0.0) result = code[instr.childIndex + j].value;
            else break;
          }
          instr.value = result > 0.0 ? 1.0 : -1.0;
        } else if (instr.opCode == OpCodes.OR) {
          double result = code[instr.childIndex].value;
          for (int j = 1; j < instr.nArguments; j++) {
            if (result <= 0.0) result = code[instr.childIndex + j].value;
            else break;
          }
          instr.value = result > 0.0 ? 1.0 : -1.0;
        } else if (instr.opCode == OpCodes.NOT) {
          instr.value = code[instr.childIndex].value > 0.0 ? -1.0 : 1.0;
        } else if (instr.opCode == OpCodes.XOR) {
          int positiveSignals = 0;
          for (int j = 0; j < instr.nArguments; j++) {
            if (code[instr.childIndex + j].value > 0.0) positiveSignals++;
          }
          instr.value = positiveSignals % 2 != 0 ? 1.0 : -1.0;
        } else if (instr.opCode == OpCodes.GT) {
          double x = code[instr.childIndex].value;
          double y = code[instr.childIndex + 1].value;
          instr.value = x > y ? 1.0 : -1.0;
        } else if (instr.opCode == OpCodes.LT) {
          double x = code[instr.childIndex].value;
          double y = code[instr.childIndex + 1].value;
          instr.value = x < y ? 1.0 : -1.0;
        } else if (instr.opCode == OpCodes.TimeLag || instr.opCode == OpCodes.Derivative || instr.opCode == OpCodes.Integral) {
          var state = (InterpreterState)instr.data;
          state.Reset();
          instr.value = interpreter.Evaluate(dataset, ref row, state);
        } else {
          var errorText = string.Format("The {0} symbol is not supported by the linear interpreter. To support this symbol, please use the SymbolicDataAnalysisExpressionTreeInterpreter.", instr.dynamicNode.Symbol.Name);
          throw new NotSupportedException(errorText);
        }
        #endregion
      }
      return code[0].value;
    }