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(); } }
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 }