public IEnumerable <double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable <int> rows)
        {
            if (!rows.Any())
            {
                return(Enumerable.Empty <double>());
            }

            if (cachedData == null || this.dataset != dataset)
            {
                InitCache(dataset);
            }

            byte mapSupportedSymbols(ISymbolicExpressionTreeNode node)
            {
                var opCode = OpCodes.MapSymbolToOpCode(node);

                if (supportedOpCodes.Contains(opCode))
                {
                    return(opCode);
                }
                else
                {
                    throw new NotSupportedException($"The native interpreter does not support {node.Symbol.Name}");
                }
            };
            var code = Compile(tree, mapSupportedSymbols);

            var rowsArray = rows.ToArray();
            var result    = new double[rowsArray.Length];

            NativeWrapper.GetValuesVectorized(code, code.Length, rowsArray, rowsArray.Length, result);

            // when evaluation took place without any error, we can increment the counter
            lock (syncRoot) {
                EvaluatedSolutions++;
            }

            return(result);
        }
        public static double CalculateComplexity(ISymbolicExpressionTreeNode treeNode)
        {
            var node = treeNode;

            if (node.Symbol is ProgramRootSymbol)
            {
                node = node.GetSubtree(0);
            }
            if (node.Symbol is StartSymbol)
            {
                node = node.GetSubtree(0);
            }

            switch (OpCodes.MapSymbolToOpCode(node))
            {
            case OpCodes.Constant: {
                return(1);
            }

            case OpCodes.Variable:
            case OpCodes.BinaryFactorVariable:
            case OpCodes.FactorVariable: {
                return(2);
            }

            case OpCodes.Add:
            case OpCodes.Sub: {
                double complexity = 0;
                for (int i = 0; i < node.SubtreeCount; i++)
                {
                    complexity += CalculateComplexity(node.GetSubtree(i));
                }
                return(complexity);
            }

            case OpCodes.Mul:
            case OpCodes.Div: {
                double complexity = 1;
                for (int i = 0; i < node.SubtreeCount; i++)
                {
                    var nodeComplexity = CalculateComplexity(node.GetSubtree(i));
                    complexity *= nodeComplexity + 1;
                }
                return(complexity);
            }

            case OpCodes.Sin:
            case OpCodes.Cos:
            case OpCodes.Tan:
            case OpCodes.Exp:
            case OpCodes.Log: {
                double complexity = CalculateComplexity(node.GetSubtree(0));
                return(Math.Pow(2.0, complexity));
            }

            case OpCodes.Square: {
                double complexity = CalculateComplexity(node.GetSubtree(0));
                return(complexity * complexity);
            }

            case OpCodes.SquareRoot: {
                double complexity = CalculateComplexity(node.GetSubtree(0));
                return(complexity * complexity * complexity);
            }

            case OpCodes.Power:
            case OpCodes.Root: {
                double complexity = CalculateComplexity(node.GetSubtree(0));
                var    exponent   = node.GetSubtree(1) as ConstantTreeNode;
                if (exponent != null)
                {
                    double expVal = exponent.Value;
                    if (expVal < 0)
                    {
                        expVal = Math.Abs(expVal);
                    }
                    if (expVal < 1)
                    {
                        expVal = 1 / expVal;
                    }
                    return(Math.Pow(complexity, Math.Round(expVal)));
                }

                double expComplexity = CalculateComplexity(node.GetSubtree(1));
                return(Math.Pow(complexity, 2 * expComplexity));
            }

            default:
                throw new NotSupportedException();
            }
        }
Ejemplo n.º 3
0
        private static Expression MakeExpr(ISymbolicExpressionTreeNode node, Dictionary <string, int> variableIndices, Expression row, Expression columns)
        {
            var opcode = OpCodes.MapSymbolToOpCode(node);

            #region switch opcode
            switch (opcode)
            {
            case OpCodes.Constant: {
                var constantTreeNode = (ConstantTreeNode)node;
                return(Expression.Constant(constantTreeNode.Value));
            }

            case OpCodes.Variable: {
                var variableTreeNode = (VariableTreeNode)node;
                var variableWeight   = Expression.Constant(variableTreeNode.Weight);
                var variableName     = variableTreeNode.VariableName;
                var indexExpr        = Expression.Constant(variableIndices[variableName]);
                var valuesExpr       = Expression.ArrayIndex(columns, indexExpr);
                return(Expression.Multiply(variableWeight, Expression.Property(valuesExpr, Indexer, row)));
            }

            case OpCodes.Add: {
                Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                for (int i = 1; i < node.SubtreeCount; ++i)
                {
                    result = Expression.Add(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
                }
                return(result);
            }

            case OpCodes.Sub: {
                Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                if (node.SubtreeCount == 1)
                {
                    return(Expression.Negate(result));
                }
                for (int i = 1; i < node.SubtreeCount; ++i)
                {
                    result = Expression.Subtract(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
                }
                return(result);
            }

            case OpCodes.Mul: {
                Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                for (int i = 1; i < node.SubtreeCount; ++i)
                {
                    result = Expression.Multiply(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
                }
                return(result);
            }

            case OpCodes.Div: {
                Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                if (node.SubtreeCount == 1)
                {
                    return(Expression.Divide(Expression.Constant(1.0), result));
                }
                for (int i = 1; i < node.SubtreeCount; ++i)
                {
                    result = Expression.Divide(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
                }
                return(result);
            }

            case OpCodes.Average: {
                Expression result = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                for (int i = 1; i < node.SubtreeCount; ++i)
                {
                    result = Expression.Add(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns));
                }
                return(Expression.Divide(result, Expression.Constant((double)node.SubtreeCount)));
            }

            case OpCodes.Cos: {
                var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                return(Expression.Call(Cos, arg));
            }

            case OpCodes.Sin: {
                var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                return(Expression.Call(Sin, arg));
            }

            case OpCodes.Tan: {
                var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                return(Expression.Call(Tan, arg));
            }

            case OpCodes.Square: {
                var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                return(Expression.Power(arg, Expression.Constant(2.0)));
            }

            case OpCodes.Power: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var power = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
                return(Expression.Power(arg, Expression.Call(Round, power)));
            }

            case OpCodes.SquareRoot: {
                var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                return(Expression.Call(Sqrt, arg));
            }

            case OpCodes.Root: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var power = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
                return(Expression.Power(arg, Expression.Divide(Expression.Constant(1.0), Expression.Call(Round, power))));
            }

            case OpCodes.Exp: {
                var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                return(Expression.Call(Exp, arg));
            }

            case OpCodes.Log: {
                var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                return(Expression.Call(Log, arg));
            }

            case OpCodes.Gamma: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN = Expression.Call(IsNaN, arg);

                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(
                    new[] { result },
                    Expression.IfThenElse(
                        isNaN,
                        Expression.Assign(result, Expression.Constant(double.NaN)),
                        Expression.Assign(result, Expression.Call(Gamma, arg))
                        ),
                    result
                    );
                return(expr);
            }

            case OpCodes.Psi: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN = Expression.Call(IsNaN, arg);

                var result = Expression.Variable(typeof(double));
                var floor  = Expression.Call(Floor, arg);
                var expr   = Expression.Block(
                    new[] { result },
                    Expression.IfThenElse(
                        isNaN,
                        Expression.Assign(result, Expression.Constant(double.NaN)),
                        Expression.IfThenElse(
                            Expression.AndAlso(
                                Expression.LessThanOrEqual(arg, Expression.Constant(0.0)),
                                Expression.Call(IsAlmost, Expression.Subtract(floor, arg), Expression.Constant(0.0))),
                            Expression.Assign(result, Expression.Constant(double.NaN)),
                            Expression.Assign(result, Expression.Call(Psi, arg)))
                        ),
                    result);

                return(expr);
            }

            case OpCodes.Dawson: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(
                    new[] { result },
                    Expression.IfThenElse(isNaN,
                                          Expression.Assign(result, Expression.Constant(double.NaN)),
                                          Expression.Assign(result, Expression.Call(DawsonIntegral, arg))),
                    result
                    );

                return(expr);
            }

            case OpCodes.ExponentialIntegralEi: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(
                    new[] { result },
                    Expression.IfThenElse(isNaN,
                                          Expression.Assign(result, Expression.Constant(double.NaN)),
                                          Expression.Assign(result, Expression.Call(ExponentialIntegralEi, arg))),
                    result
                    );

                return(expr);
            }

            case OpCodes.SineIntegral: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN = Expression.Call(IsNaN, arg);
                var si    = Expression.Variable(typeof(double));
                var ci    = Expression.Variable(typeof(double));
                var block = Expression.Block(
                    new[] { si, ci },
                    Expression.Call(SineCosineIntegrals, arg, si, ci),
                    si
                    );
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.CosineIntegral: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN = Expression.Call(IsNaN, arg);
                var si    = Expression.Variable(typeof(double));
                var ci    = Expression.Variable(typeof(double));
                var block = Expression.Block(
                    new[] { si, ci },
                    Expression.Call(SineCosineIntegrals, arg, si, ci),
                    ci
                    );
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.HyperbolicSineIntegral: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN = Expression.Call(IsNaN, arg);
                var shi   = Expression.Variable(typeof(double));
                var chi   = Expression.Variable(typeof(double));
                var block = Expression.Block(
                    new[] { shi, chi },
                    Expression.Call(HyperbolicSineCosineIntegrals, arg, shi, chi),
                    shi
                    );
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.HyperbolicCosineIntegral: {
                var arg   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN = Expression.Call(IsNaN, arg);
                var shi   = Expression.Variable(typeof(double));
                var chi   = Expression.Variable(typeof(double));
                var block = Expression.Block(
                    new[] { shi, chi },
                    Expression.Call(HyperbolicSineCosineIntegrals, arg, shi, chi),
                    chi
                    );
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.FresnelSineIntegral: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var s      = Expression.Variable(typeof(double));
                var c      = Expression.Variable(typeof(double));
                var block  = Expression.Block(new[] { s, c }, Expression.Call(FresnelIntegral, arg, c, s), s);
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.FresnelCosineIntegral: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var s      = Expression.Variable(typeof(double));
                var c      = Expression.Variable(typeof(double));
                var block  = Expression.Block(new[] { s, c }, Expression.Call(FresnelIntegral, arg, c, s), c);
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.AiryA: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var ai     = Expression.Variable(typeof(double));
                var aip    = Expression.Variable(typeof(double));
                var bi     = Expression.Variable(typeof(double));
                var bip    = Expression.Variable(typeof(double));
                var block  = Expression.Block(new[] { ai, aip, bi, bip }, Expression.Call(Airy, arg, ai, aip, bi, bip), ai);
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.AiryB: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var ai     = Expression.Variable(typeof(double));
                var aip    = Expression.Variable(typeof(double));
                var bi     = Expression.Variable(typeof(double));
                var bip    = Expression.Variable(typeof(double));
                var block  = Expression.Block(new[] { ai, aip, bi, bip }, Expression.Call(Airy, arg, ai, aip, bi, bip), bi);
                var result = Expression.Variable(typeof(double));
                var expr   = Expression.Block(new[] { result },
                                              Expression.IfThenElse(isNaN,
                                                                    Expression.Assign(result, Expression.Constant(double.NaN)),
                                                                    Expression.Assign(result, block)),
                                              result
                                              );

                return(expr);
            }

            case OpCodes.Norm: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var result = Expression.Variable(typeof(double));
                return(Expression.Block(
                           new[] { result },
                           Expression.IfThenElse(
                               Expression.Call(IsNaN, arg),
                               Expression.Assign(result, arg),
                               Expression.Assign(result, Expression.Call(NormalDistribution, arg))),
                           result));
            }

            case OpCodes.Erf: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var result = Expression.Variable(typeof(double));
                return(Expression.Block(
                           new[] { result },
                           Expression.IfThenElse(
                               isNaN,
                               Expression.Assign(result, Expression.Constant(double.NaN)),
                               Expression.Assign(result, Expression.Call(ErrorFunction, arg))),
                           result));
            }

            case OpCodes.Bessel: {
                var arg    = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var isNaN  = Expression.Call(IsNaN, arg);
                var result = Expression.Variable(typeof(double));
                return(Expression.Block(
                           new[] { result },
                           Expression.IfThenElse(
                               isNaN,
                               Expression.Assign(result, Expression.Constant(double.NaN)),
                               Expression.Assign(result, Expression.Call(Bessel, arg))),
                           result));
            }

            case OpCodes.IfThenElse: {
                var test      = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var result    = Expression.Variable(typeof(double));
                var condition = Expression.IfThenElse(Expression.GreaterThan(test, Expression.Constant(0.0)),
                                                      Expression.Assign(result, MakeExpr(node.GetSubtree(1), variableIndices, row, columns)),
                                                      Expression.Assign(result, MakeExpr(node.GetSubtree(2), variableIndices, row, columns)));
                return(Expression.Block(new[] { result }, condition, result));
            }

            case OpCodes.AND: {
                var result = Expression.Variable(typeof(double));
                var expr   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);

                for (int i = 1; i < node.SubtreeCount; ++i)
                {
                    expr = Expression.Block(new[] { result },
                                            Expression.IfThenElse(
                                                Expression.GreaterThan(expr, Expression.Constant(0.0)),
                                                Expression.Assign(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns)),
                                                Expression.Assign(result, expr)),
                                            result
                                            );
                }

                return(Expression.Block(
                           new[] { result },
                           Expression.Assign(result, expr),
                           Expression.IfThenElse(
                               Expression.GreaterThan(result, Expression.Constant(0.0)),
                               Expression.Assign(result, Expression.Constant(1.0)),
                               Expression.Assign(result, Expression.Constant(-1.0))
                               ),
                           result
                           ));
            }

            case OpCodes.OR: {
                var result = Expression.Variable(typeof(double));
                var expr   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);

                for (int i = 1; i < node.SubtreeCount; ++i)
                {
                    expr = Expression.Block(new[] { result },
                                            Expression.IfThenElse(
                                                Expression.LessThanOrEqual(expr, Expression.Constant(0.0)),
                                                Expression.Assign(result, MakeExpr(node.GetSubtree(i), variableIndices, row, columns)),
                                                Expression.Assign(result, expr)),
                                            result
                                            );
                }

                return(Expression.Block(
                           new[] { result },
                           Expression.Assign(result, expr),
                           Expression.IfThenElse(
                               Expression.GreaterThan(result, Expression.Constant(0.0)),
                               Expression.Assign(result, Expression.Constant(1.0)),
                               Expression.Assign(result, Expression.Constant(-1.0))
                               ),
                           result
                           ));
            }

            case OpCodes.NOT: {
                var value     = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var result    = Expression.Variable(typeof(double));
                var condition = Expression.IfThenElse(Expression.GreaterThan(value, Expression.Constant(0.0)),
                                                      Expression.Assign(result, Expression.Constant(-1.0)),
                                                      Expression.Assign(result, Expression.Constant(1.0)));
                return(Expression.Block(new[] { result }, condition, result));
            }

            case OpCodes.XOR: {
                var ps    = Expression.Variable(typeof(int));
                var block = Expression.Block(
                    new[] { ps },
                    Expression.Assign(ps, Expression.Constant(0)),
                    ps
                    );

                foreach (var subtree in node.Subtrees)
                {
                    var expr = MakeExpr(subtree, variableIndices, row, columns);
                    block = Expression.Block(
                        new[] { ps },
                        Expression.Assign(ps, block),
                        Expression.IfThen(Expression.GreaterThan(expr, Expression.Constant(0.0)),
                                          Expression.PostIncrementAssign(ps)),
                        ps
                        );
                }

                var result  = Expression.Variable(typeof(double));
                var xorExpr = Expression.Block(
                    new[] { result },
                    Expression.IfThenElse(
                        Expression.Equal(Expression.Modulo(block, Expression.Constant(2)), Expression.Constant(0)),
                        Expression.Assign(result, Expression.Constant(-1.0)),
                        Expression.Assign(result, Expression.Constant(1.0))
                        ),
                    result
                    );
                return(xorExpr);
            }

            case OpCodes.GT: {
                var left   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var right  = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
                var result = Expression.Variable(typeof(double));

                var condition = Expression.IfThenElse(Expression.GreaterThan(left, right),
                                                      Expression.Assign(result, Expression.Constant(1.0)), Expression.Assign(result, Expression.Constant(-1.0)));
                return(Expression.Block(
                           new[] { result },
                           condition,
                           result));
            }

            case OpCodes.LT: {
                var left   = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var right  = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
                var result = Expression.Variable(typeof(double));

                var condition = Expression.IfThenElse(Expression.LessThan(left, right),
                                                      Expression.Assign(result, Expression.Constant(1.0)), Expression.Assign(result, Expression.Constant(-1.0)));
                return(Expression.Block(new[] { result }, condition, result));
            }

            case OpCodes.VariableCondition: {
                var variableConditionTreeNode = (VariableConditionTreeNode)node;
                if (variableConditionTreeNode.Symbol.IgnoreSlope)
                {
                    throw new NotSupportedException("Strict variable conditionals are not supported");
                }
                var variableName      = variableConditionTreeNode.VariableName;
                var indexExpr         = Expression.Constant(variableIndices[variableName]);
                var valuesExpr        = Expression.ArrayIndex(columns, indexExpr);
                var variableValue     = Expression.Property(valuesExpr, Indexer, row);
                var variableThreshold = Expression.Constant(variableConditionTreeNode.Threshold);
                var variableSlope     = Expression.Constant(variableConditionTreeNode.Slope);

                var x           = Expression.Subtract(variableValue, variableThreshold);
                var xSlope      = Expression.Multiply(Expression.Negate(variableSlope), x);
                var xSlopeExp   = Expression.Call(Exp, xSlope);
                var p           = Expression.Divide(Expression.Constant(1), Expression.Add(Expression.Constant(1), xSlopeExp));
                var trueBranch  = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
                var falseBranch = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
                return(Expression.Add(
                           Expression.Multiply(trueBranch, p),
                           Expression.Multiply(falseBranch, Expression.Subtract(Expression.Constant(1), p))
                           ));
            }

            default:
                throw new NotSupportedException("Unsupported symbol: " + node.Symbol);
            }
            #endregion
        }