private List<Tuple<Person, double>> RecogniseSpeaker(List<double[]> mfccs)
        {
            var results     = new List<Tuple<Person, double>>();
            var mfccArray   = mfccs.ToArray();

            double[]    input           = new double[GetNetworksInputSize()];
            int         totalSamples    = 0;

            Dictionary<Person, double>  resultsPerNetwork   = new Dictionary<Person, double>();
            Dictionary<Person, int>     samplesPerNetwork   = new Dictionary<Person, int>();
            Dictionary<Person, GnuPlot> plots               = new Dictionary<Person, GnuPlot>();

            foreach (var person in people) {
                resultsPerNetwork[person] = 0.0f;
                samplesPerNetwork[person] = 0;
                plots[person] = new GnuPlot(person.FullName, GetRecognitionPlotFileName(person));
                plots[person].BeginPlot();
            }

            for (int start = 0; start < mfccArray.Length - algorithmParams.SignalFramesCount; start++) {
                CopyInputData(input, mfccArray, start);

                var result = from person in people
                              let network = neuralNetworks[person]
                              select new KeyValuePair<Person, double>(
                                  person,
                                  network.Compute(new[] { input })[0][0]
                                  );

                foreach (var r in result) {
                    plots[r.Key].AddDataPoint(start, r.Value);

                    if (r.Value > THRESHOLD || r.Value < (1.0 - THRESHOLD)) {
                        //samplesPerNetwork[r.Key]++;
                        resultsPerNetwork[r.Key] += (r.Value > THRESHOLD) ? r.Value : (r.Value - 1.0);// NormalizeResult(r.Value);

                        if(r.Value > THRESHOLD)
                            totalSamples++;
                    }
                }
            }

            foreach (var p in people) {
                plots[p].SetYRange(0, 1);
                plots[p].EndPlot();
            }

            var finalResults = from person in people
                               let res = Math.Max(0, resultsPerNetwork[person])
                               let norm = res / (double)totalSamples
                               select new Tuple<Person, double>(person, norm);
            //var finalResults = from person in people
            //                   let samples  = samplesPerNetwork[person]
            //                   let res      = resultsPerNetwork[person]
            //                   let norm     = (samples == 0) ? 0 : (res / (double)samples)
            //                   select new Tuple<Person, double>(person, norm);

            return finalResults.ToList();
        }
        private void TrainPersonNeuralNetwork(
            Dictionary<Person, List<double[]>[]> trainingMfccs,
            Dictionary<Person, List<double[]>[]> testMfccs,
            double[] input, double[][] answer, Person person,
            PerceptronWrapper network)
        {
            GnuPlot plot = new GnuPlot(
                person.FullName,
                @"D:\GIT\nnetwork_mini_pw\charts\plot_" + person.FullName.Replace(' ', '_') + ".png"
                );
            plot.BeginPlot();

            List<double[]>[] personMfccs = null;
            int iterations = 0;

            while (iterations < MaxIterationCounts) {
                double expectedAnswer;

                if (Random.NextDouble() < algorithmParams.TCoef) {
                    expectedAnswer      = 0.0d;
                    Person otherPerson  = SelectOtherPerson(person);
                    personMfccs         = trainingMfccs[otherPerson];
                }
                else {
                    expectedAnswer      = 1.0d;
                    personMfccs         = trainingMfccs[person];
                }

                DrawInputData(input, personMfccs);

                double scale            = Math.Sqrt(1.0 + iterations);
                double newLearningRate  = algorithmParams.LearningRate / scale;
                double newMomentum      = algorithmParams.Momentum / scale;

                answer[0][0] = expectedAnswer;
                network.Train(newLearningRate, 1, newMomentum,
                    new[] { input },
                    answer);

                iterations++;

                if (iterations % 1000 == 0) {
                    double testResult   = TestPersonNeuralNetwork(person, testMfccs, input);
                    double learnResult  = TestPersonNeuralNetwork(person, trainingMfccs, input);
                    AddPlotPoint(plot, iterations, learnResult, testResult);

                    if (testResult <= TestSetMaxError)
                    {
                        break;
                    }
                }
            }

            plot.AddAlgorithmParamsToTitle(algorithmParams);
            plot.End2Plot();
        }
        private static void AddPlotPoint(GnuPlot plot, int iterations, double learnResult, double testResult)
        {
            plot.AddDataPoint(iterations, learnResult, testResult);

            string line = String.Format(CultureInfo.InvariantCulture, "{0}\t{1}", iterations, testResult);
            Debug.WriteLine(line);
        }