'Propagates the output through the network and
generates delta for hidden and output nodes.
The learning rate determines speed vs. accuracy of the algorithm.'

def _propagate_backward(self, output=[], rate=0.5, momentum=0.1):

    (ai, ao, ah, wi, wo, ci, co) = (self._ai, self._ao, self._ah, self._wi, self._wo, self._ci, self._co)
    do = ([0.0] * len(ao))
    for (k, v) in enumerate(ao):
        error = (output[k] - v)
        do[k] = (error * sigmoid_derivative(v))
    dh = ([0.0] * len(ah))
    for (j, v) in enumerate(ah):
        error = sum(((do[k] * wo[j][k]) for k in range(len(ao))))
        dh[j] = (error * sigmoid_derivative(v))
    for (j, v1) in enumerate(ah):
        for (k, v2) in enumerate(ao):
            change = (do[k] * v1)
            wo[j][k] += ((rate * change) + (momentum * co[j][k]))
            co[j][k] = change
    for (i, v1) in enumerate(ai):
        for (j, v2) in enumerate(ah):
            change = (dh[j] * v1)
            wi[i][j] += ((rate * change) + (momentum * ci[i][j]))
            ci[i][j] = change
    return sum(((0.5 * ((output[k] - v) ** 2)) for (k, v) in enumerate(ao)))
