private void SetResult(EvaluationContext context, FunctionFoundEventArgs <Derivatives <Func <double> > > args, IFunction <double, double> doubleFunction) { var argumentCount = args.ArgumentCount; var variableCount = 1; for (var i = 0; i < argumentCount; i++) { variableCount = Math.Max(variableCount, args[i].Count); } var result = new DoubleDerivatives(variableCount); var arguments = new Func <double> [argumentCount]; for (var i = 0; i < argumentCount; i++) { var iLocal = i; arguments[i] = () => args[iLocal][0](); } result[0] = () => { var argumentValues = arguments.Select(arg => arg()).ToArray(); return(doubleFunction.Logic(string.Empty, argumentValues, context)); }; if (doubleFunction is IDerivativeFunction <double, double> derivativeFunction) { var derivatives = new Lazy <Derivatives <Func <double> > >(() => derivativeFunction.Derivative(string.Empty, args, context)); for (var i = 1; i <= variableCount; i++) { var derivativeIndex = i; if (IsDerivativeDefined(args, derivativeIndex)) { result[i] = () => GetDerivativeValue(args, derivativeIndex, argumentCount, derivatives); } } } args.Result = result; }
/// <summary> /// Exponentials /// </summary> public static Derivatives <Func <double> > ApplyExp(Derivatives <Func <double> >[] arguments) { arguments.ThrowIfNot(nameof(arguments), 1); var arg = arguments[0]; var result = new DoubleDerivatives(arg.Count); var a0 = arg[0]; result[0] = () => Math.Exp(a0()); // Chain rule for derivatives for (var i = 1; i < arg.Count; i++) { if (arg[i] != null) { var ai = arg[i]; result[i] = () => Math.Exp(a0()) * ai(); } } return(result); }
/// <summary> /// Applies the square root. /// </summary> /// <param name="arguments">The arguments.</param> /// <returns>The square root result.</returns> public static Derivatives <Func <double> > ApplySqrt(Derivatives <Func <double> >[] arguments) { arguments.ThrowIfNot(nameof(arguments), 1); var a = arguments[0]; var result = new DoubleDerivatives(a.Count); var a0 = a[0]; result[0] = () => Math.Sqrt(a0()); // Apply the chain rule for (var i = 1; i < a.Count; i++) { if (a[i] != null) { var ai = a[i]; result[i] = () => - 0.5 * ai() / Math.Sqrt(a0()); } } return(result); }
/// <summary> /// Applies the absolute value. /// </summary> /// <param name="arguments">The arguments.</param> /// <returns>The absolute value result.</returns> public static Derivatives <Func <double> > ApplyAbs(Derivatives <Func <double> >[] arguments) { arguments.ThrowIfNot(nameof(arguments), 1); var arg = arguments[0]; var result = new DoubleDerivatives(arg.Count); var a0 = arg[0]; result[0] = () => Math.Abs(a0()); // Apply chain rule for (var i = 1; i < arg.Count; i++) { if (arg[i] != null) { var ai = arg[i]; result[i] = () => { var tmp = a0(); return(tmp > 0 ? ai() : tmp < 0 ? -ai() : 0); }; } } return(result); }
/// <summary> /// Applies the arctangent. /// </summary> /// <param name="arguments">The arguments.</param> /// <returns>The arctangent result.</returns> public static Derivatives <Func <double> > ApplyAtan(Derivatives <Func <double> >[] arguments) { arguments.ThrowIfNot(nameof(arguments), 1); var arg = arguments[0]; var result = new DoubleDerivatives(arg.Count); var a0 = arg[0]; result[0] = () => Math.Atan(a0()); // Apply the chain rule for (var i = 1; i < arg.Count; i++) { if (arg[i] != null) { var ai = arg[i]; result[i] = () => { var x = a0(); return(ai() / (1 + x * x)); }; } } return(result); }
/// <summary> /// Logarithms /// </summary> public static Derivatives <Func <double> > ApplyLog(Derivatives <Func <double> >[] arguments) { arguments.ThrowIfEmpty(nameof(arguments)); if (arguments.Length == 1) { // Ln(f(x))' = 1/f(x)*f'(x) var arg = arguments[0]; var result = new DoubleDerivatives(arg.Count); var a0 = arg[0]; result[0] = () => Math.Log(a0()); // Chain rule for (var i = 1; i < arg.Count; i++) { if (arg[i] != null) { var ai = arg[i]; result[i] = () => ai() / a0(); } } return(result); } if (arguments.Length == 2) { // Log(g(x), f(x)) = Ln(g(x)) / Ln(f(x)) var g = arguments[0]; var f = arguments[1]; var size = Math.Max(f.Count, g.Count); var result = new DoubleDerivatives(size); var g0 = g[0]; var f0 = f[0]; result[0] = () => Math.Log(g0(), f0()); // Chain rule for (var i = 1; i < size; i++) { if (g[i] != null && f[i] != null) { var gi = g[i]; var fi = f[i]; result[i] = () => { var tmpf0 = f0(); var tmpg0 = g0(); return(gi() / tmpg0 / Math.Log(tmpf0) - fi() / tmpf0 * Math.Log(tmpg0, tmpf0)); }; } else if (g[i] != null) { var gi = g[i]; result[i] = () => gi() / g0() / Math.Log(f0()); } else if (f[i] != null) { var fi = f[i]; result[i] = () => { var tmpf0 = f0(); return(-fi() / f0() * Math.Log(g0(), tmpf0)); }; } } return(result); } throw new CircuitException("Invalid number of arguments, {0} given but 2 expected".FormatString(arguments.Length)); }
/// <summary> /// Applies the maximum operator. /// </summary> /// <param name="arguments">The arguments.</param> /// <returns>The maximum result.</returns> public static Derivatives <Func <double> > ApplyMax(Derivatives <Func <double> >[] arguments) { arguments.ThrowIfEmpty(nameof(arguments)); var size = 1; for (var i = 0; i < arguments.Length; i++) { size = Math.Max(size, arguments[i].Count); } var result = new DoubleDerivatives(size); if (arguments.Length == 1) { result[0] = arguments[0][0]; return(result); } { // First two arguments var a = arguments[0][0]; var b = arguments[1][0]; result[0] = () => Math.Max(a(), b()); for (var k = 1; k < size; k++) { if (arguments[0][k] != null || arguments[1][k] != null) { CircuitWarning.Warning(null, "Trying to derive Min() for which the derivative may not exist in some points"); var tmpda = arguments[0][k]; var tmpdb = arguments[1][k]; var funca = arguments[0][0]; var funcb = arguments[1][0]; if (tmpda != null && tmpdb != null) { result[k] = () => funca() > funcb() ? tmpda() : tmpdb(); // Use the derivative of the function that is currently the smallest } else if (tmpda != null) { result[k] = () => funca() > funcb() ? tmpda() : 0; } else if (tmpdb != null) { result[k] = () => funca() > funcb() ? 0 : tmpdb(); } } } } for (var i = 2; i < arguments.Length; i++) { // First two arguments var a = result[0]; var b = arguments[i][0]; result[0] = () => Math.Max(a(), b()); for (var k = 1; k < size; k++) { if (arguments[0][k] != null || arguments[1][k] != null) { CircuitWarning.Warning(null, "Trying to derive Min() for which the derivative may not exist in some points"); var tmpda = result[k]; var tmpdb = arguments[i][k]; var funca = a; var funcb = arguments[i][0]; if (tmpda != null && tmpdb != null) { result[k] = () => funca() > funcb() ? tmpda() : tmpdb(); // Use the derivative of the function that is currently the smallest } else if (tmpda != null) { result[k] = () => funca() > funcb() ? tmpda() : 0; } else if (tmpdb != null) { result[k] = () => funca() > funcb() ? 0 : tmpdb(); } } } } return(result); }