/// <summary>
        /// Computes the activation of node n.  We initially start with output neurons, and work
        /// our way backward.
        /// </summary>
        private void ComputeActivation(Node n, List <Node> previousNodeRequests)
        {
            if (n.Role == NodeRole.Input || n.Role == NodeRole.Bias)
            {
                // It doesn't make sense to compute the activation of Input and Bias nodes.
                // The activation of the Bias node is always 1
                // The activation of the input node comes from an external input vector.
                return;
            }

            n.IncomingActivity = 0;
            foreach (Link l in n.LinksIncoming.Values)
            {
                double activationContribution = 0;
                if (previousNodeRequests.Contains(l.NodeIn))
                {
                    // We've already asked about this node, so we must have hit a recurrent loop.
                    // Use the previous activation, and stop asking.
                    activationContribution = l.NodeIn.ActivationPrevious * l.Weight;
                }
                else
                {
                    previousNodeRequests.Add(l.NodeIn);
                    ComputeActivation(l.NodeIn, previousNodeRequests);
                    // After computing, pop the last item off the list
                    previousNodeRequests.RemoveAt(previousNodeRequests.Count - 1);
                    activationContribution = l.NodeIn.ActivationCurrent * l.Weight;
                }
                n.IncomingActivity += activationContribution;
            }

            n.ActivationPrevious = n.ActivationCurrent;
            n.ActivationCurrent  = ActivationFunctions.Sigmoidal_0_1(n.IncomingActivity);
        }