private static Node DAtan(FunctionNode f, IReadOnlyList <Node> dargs) => dargs.Check(1)[0] / (Node.One + Node.Power(f.Arguments[0], Node.Two));
        /// <summary>
        /// Derives the specified node to the variables.
        /// </summary>
        /// <param name="node">The nodes.</param>
        /// <returns>The derived nodes, or <c>null</c> if all derivatives are zero.</returns>
        public virtual Dictionary <VariableNode, Node> Derive(Node node)
        {
            if (Variables == null)
            {
                return(null);
            }

            // We can skip anything that is constant!
            if ((node.Properties & NodeProperties.Constant) != 0)
            {
                return(null);
            }

            Dictionary <VariableNode, Node> a = null, b = null;

            switch (node)
            {
            case UnaryOperatorNode un:
                if (un.NodeType == NodeTypes.Not)
                {
                    return(null);
                }
                a = Derive(un.Argument);
                switch (un.NodeType)
                {
                case NodeTypes.Plus: return(Apply(a, n => Node.Plus(n)));

                case NodeTypes.Minus: return(Apply(a, n => Node.Minus(n)));
                }
                break;

            case BinaryOperatorNode bn:
                switch (bn.NodeType)
                {
                case NodeTypes.And:
                case NodeTypes.Or:
                case NodeTypes.Xor:
                case NodeTypes.GreaterThan:
                case NodeTypes.GreaterThanOrEqual:
                case NodeTypes.LessThan:
                case NodeTypes.LessThanOrEqual:
                case NodeTypes.Equals:
                case NodeTypes.NotEquals:
                    return(null);
                }

                a = Derive(bn.Left);
                b = Derive(bn.Right);
                switch (bn.NodeType)
                {
                case NodeTypes.Add: return(Combine(a, b, n1 => n1, n2 => n2));

                case NodeTypes.Subtract: return(Combine(a, b, n1 => n1, n2 => Node.Minus(n2), (n1, n2) => Node.Subtract(n1, n2)));

                case NodeTypes.Multiply: return(Combine(a, b, n1 => n1 * bn.Right, n2 => bn.Left * n2));

                case NodeTypes.Divide:
                    return(Combine(a, b,
                                   n1 => n1 / bn.Right,
                                   n2 => - (n2 / Node.Power(bn.Right, Node.Two)),
                                   (n1, n2) => (n1 * bn.Right - bn.Left * n2) / Node.Power(bn.Right, Node.Two)));

                case NodeTypes.Pow:
                    return(Combine(a, b,
                                   n1 => n1 * bn.Right * Node.Power(bn.Left, bn.Right - Node.One),
                                   n2 => n2 * Node.Function("log", bn.Left) * bn));

                case NodeTypes.Modulo:
                    return(Combine(a, b,
                                   n1 => n1,
                                   n2 => n2 * -bn,
                                   (n1, n2) => n1 - n2 * bn));
                }
                break;

            case TernaryOperatorNode tn:
                a = Derive(tn.IfTrue);
                b = Derive(tn.IfFalse);
                return(Combine(a, b,
                               n1 => Node.Conditional(tn.Condition, n1, Node.Zero),
                               n2 => Node.Conditional(tn.Condition, Node.Zero, n2),
                               (n1, n2) => Node.Conditional(tn.Condition, n1, n2)));

            case FunctionNode fn:
                if (fn.Arguments.Count == 0)
                {
                    return(null);
                }

                // Build the derived arguments
                var lst = new Dictionary <VariableNode, Node[]>(Variables.Comparer);
                for (var i = 0; i < fn.Arguments.Count; i++)
                {
                    var darg = Derive(fn.Arguments[i]);
                    if (darg != null)
                    {
                        foreach (var pair in darg)
                        {
                            if (!lst.TryGetValue(pair.Key, out var dargs))
                            {
                                dargs = new Node[fn.Arguments.Count];
                                lst.Add(pair.Key, dargs);
                            }
                            dargs[i] = pair.Value;
                        }
                    }
                }

                // If there are no derivative, let's just stop here
                if (lst.Count == 0)
                {
                    return(null);
                }

                // Give a chance to our function rules
                if (FunctionRules == null || !FunctionRules.TryGetValue(fn.Name, out var rule))
                {
                    rule = (fn, darg) => ChainRule(fn, darg, "d{0}({1})");
                }
                a = new Dictionary <VariableNode, Node>(Variables.Comparer);
                foreach (var pair in lst)
                {
                    var df = rule(fn, pair.Value);
                    if (df != null)
                    {
                        a.Add(pair.Key, df);
                    }
                }

                // If all derivatives are zero, return null
                return(a.Count > 0 ? a : null);

            case VariableNode vn:
                if (Variables.Contains(vn))
                {
                    a = new Dictionary <VariableNode, Node>(Variables.Comparer)
                    {
                        { vn, Node.One }
                    };
                    return(a);
                }
                return(null);

            case PropertyNode _:
            case ConstantNode _:
                return(null);
            }

            throw new Exception("Could not derive expression node {0}".FormatString(node));
        }
 private static Node DAsin(FunctionNode f, IReadOnlyList <Node> dargs) => dargs.Check(1)[0] / Node.Function("sqrt", Node.One - Node.Power(f.Arguments[0], Node.Two));