public void Train(FeedForwardNeuralNetwork net, double[][] input, double[][] desiredOutput)
        {
            int inputNeuronCount = net.InputSignal.Length;
            int outputNeuronCount = net.OutputSignal.Length;

            if (input[0].Length != inputNeuronCount || desiredOutput[0].Length != net.OutputSignal.Length)
                throw new Exception("Input or output values number are invalid.");

            // maximum allowed epoches
            const int maxEpoches = 500000000;
            bool go = true;
            //number of learning sequences
            int sequences = input.Length;
            double[][] signal = net.Signal;
            double[][] error = net.Error;
            double[][][] weight = net.Weight;
            double[][][] weightChange = net.WeightChange;
            int[] neurons = net.Neurons;
            int layerCount = net.Layers;

            double previousAverageError = 0;
            while (go)
            {
                // check for infinite loop
                if (net.Epoch >= maxEpoches)
                    throw new Exception("Training takes too long. Try to change network architecture.");

                double averageError=0;
                for (int curr = 0; curr < sequences; curr++)
                {
                    double[] currInput = input[curr];
                    double[] currDesiredOutput = desiredOutput[curr];
                    //setting input signals
                    net.InputSignal = currInput;
                    //executing network
                    net.Pulse();
                    //calculating errors of output neurons
                    for (int i = 0; i < outputNeuronCount; i++)
                    {
                        error[layerCount - 1][i] =
                            net.ActivationFunction.Derivative(signal[layerCount - 1][i]) *
                            (currDesiredOutput[i] - signal[layerCount - 1][i]);
                        averageError += 0.5f * (currDesiredOutput[i] - signal[layerCount - 1][i]) *
                                        (currDesiredOutput[i] - signal[layerCount - 1][i]);
                    }
                    _learningRate = _learningRate * (averageError >= previousAverageError ? 0.2 : 5); //_learningRate * (_adaptationRate * averageError * previousAverageError + 1);
                    previousAverageError = averageError;

                    //calculating all errors and wight changes
                    for (int layer = layerCount - 1; layer > 0; layer--)
                    {
                        for (int i = 0; i < neurons[layer - 1]; i++)
                        {
                            double temp = 0;
                            for (int j = 0; j < neurons[layer]; j++)
                            {
                                double delta = _learningRate * error[layer][j] * signal[layer - 1][i];
                                //adding momentum to prevent from detecting a local minima
                                weight[layer - 1][i][j] += delta + _momentumRate * weightChange[layer - 1][i][j];
                                weightChange[layer - 1][i][j] = delta;
                                temp += error[layer][j] * weight[layer - 1][i][j];
                            }
                            error[layer - 1][i] = net.ActivationFunction.Derivative(signal[layer - 1][i]) * temp;
                        }
                    }
                }

                if (averageError <= _precision)
                    go = false;
            }
        }