/// <summary> /// Differentiate the function with respect to the variable /// </summary> /// <param name="function"></param> /// <param name="variable"></param> /// <returns></returns> private static Expression Differentiate(Function function, Expression variable, BlockExpressionBuilder builder) { // note that one of the function parameters is the variable var expression = function.Expression; if (expression is BinaryExpression) { BinaryExpression binaryExpression = expression as BinaryExpression; if (expression.NodeType == ExpressionType.Multiply) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) { return(Expression.Multiply(new ConstantExpression <double>(2), variable)); } if (binaryExpression.Left == variable) { return(binaryExpression.Right); } else if (binaryExpression.Right == variable) { return(binaryExpression.Left); } } else if (expression.NodeType == ExpressionType.Add) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) { return(new ConstantExpression <double>(2)); } else if (binaryExpression.Left == variable) { return(new ConstantExpression <double>(1)); } else if (binaryExpression.Right == variable) { return(new ConstantExpression <double>(1)); } } else if (expression.NodeType == ExpressionType.Subtract) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) { return(new ConstantExpression <double>(0)); } else if (binaryExpression.Left == variable) { return(new ConstantExpression <double>(1)); } else if (binaryExpression.Right == variable) { return(new ConstantExpression <double>(-1)); } } else if (expression.NodeType == ExpressionType.Divide) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) { throw new NotImplementedException(); // should not happen } if (binaryExpression.Left == variable) { var right = binaryExpression.Right as ReferencingVectorParameterExpression <double>; if (right.IsScalar) { return(builder.AddLocalAssignment <double>(1 / right.ScalarValue, new ScaleInverseExpression <double>(binaryExpression.Right as VectorParameterExpression, 1))); } else { return(builder.AddLocalAssignment <double>(new ScaleInverseExpression <double>(binaryExpression.Right as VectorParameterExpression, 1))); } } else if (binaryExpression.Right == variable) { return(builder.AddNegateDivideExpression(function.Parameter, binaryExpression.Right as VectorParameterExpression)); // i.e. x/y => x/y * -1/y } } } if (expression is UnaryMathsExpression) { var unaryExpression = expression as UnaryMathsExpression; if (unaryExpression.UnaryType == UnaryElementWiseOperation.ScaleOffset) { return(new ConstantExpression <double>((unaryExpression as ScaleOffsetExpression <double>).Scale)); } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.Negate) { return(new ConstantExpression <double>(-1)); } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.ScaleInverse) { return(builder.AddNegateDivideExpression(function.Parameter, unaryExpression.Operand)); // i.e. x/y => x/y * -1/y } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.Exp) { return(function.Parameter); } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.Log) { return(builder.AddInverseExpression(unaryExpression.Operand)); } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.SquareRoot) { return(builder.AddHalfInverseSquareRootExpression(unaryExpression.Operand)); } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.CumulativeNormal) { return(builder.AddGaussian(unaryExpression.Operand)); } else { throw new NotImplementedException(); } } else { throw new NotImplementedException(); } }
/// <summary> /// Differentiate the function with respect to the variable /// </summary> /// <param name="function"></param> /// <param name="variable"></param> /// <returns></returns> private static Expression Differentiate(Function function, Expression variable, BlockExpressionBuilder builder) { // note that one of the function parameters is the variable var expression = function.Expression; if (expression is BinaryExpression) { BinaryExpression binaryExpression = expression as BinaryExpression; if (expression.NodeType == ExpressionType.Multiply) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) { return Expression.Multiply(new ConstantExpression<double>(2), variable); } if (binaryExpression.Left == variable) return binaryExpression.Right; else if (binaryExpression.Right == variable) return binaryExpression.Left; } else if (expression.NodeType == ExpressionType.Add) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) { return new ConstantExpression<double>(2); } else if (binaryExpression.Left == variable) return new ConstantExpression<double>(1); else if (binaryExpression.Right == variable) return new ConstantExpression<double>(1); } else if (expression.NodeType == ExpressionType.Subtract) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) { return new ConstantExpression<double>(0); } else if (binaryExpression.Left == variable) return new ConstantExpression<double>(1); else if (binaryExpression.Right == variable) return new ConstantExpression<double>(-1); } else if (expression.NodeType == ExpressionType.Divide) { if (binaryExpression.Left == variable && binaryExpression.Right == variable) throw new NotImplementedException(); // should not happen if (binaryExpression.Left == variable) { var right = binaryExpression.Right as ReferencingVectorParameterExpression<double>; if (right.IsScalar) return builder.AddLocalAssignment<double>(1 / right.ScalarValue, new ScaleInverseExpression<double>(binaryExpression.Right as VectorParameterExpression, 1)); else return builder.AddLocalAssignment<double>(new ScaleInverseExpression<double>(binaryExpression.Right as VectorParameterExpression, 1)); } else if (binaryExpression.Right == variable) { return builder.AddNegateDivideExpression(function.Parameter, binaryExpression.Right as VectorParameterExpression); // i.e. x/y => x/y * -1/y } } } if (expression is UnaryMathsExpression) { var unaryExpression = expression as UnaryMathsExpression; if (unaryExpression.UnaryType == UnaryElementWiseOperation.ScaleOffset) { return new ConstantExpression<double>((unaryExpression as ScaleOffsetExpression<double>).Scale); } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.Negate) return new ConstantExpression<double>(-1); else if (unaryExpression.UnaryType == UnaryElementWiseOperation.ScaleInverse) { return builder.AddNegateDivideExpression(function.Parameter, unaryExpression.Operand); // i.e. x/y => x/y * -1/y } else if (unaryExpression.UnaryType == UnaryElementWiseOperation.Exp) return function.Parameter; else if (unaryExpression.UnaryType == UnaryElementWiseOperation.Log) return builder.AddInverseExpression(unaryExpression.Operand); else if (unaryExpression.UnaryType == UnaryElementWiseOperation.SquareRoot) return builder.AddHalfInverseSquareRootExpression(unaryExpression.Operand); else if (unaryExpression.UnaryType == UnaryElementWiseOperation.CumulativeNormal) return builder.AddGaussian(unaryExpression.Operand); else throw new NotImplementedException(); } else throw new NotImplementedException(); }