public NetworkPatch CreateAndApplyPatch(int changesPerPatch, int wantedNoOfNodes)
        {
            NetworkPatch patch = new NetworkPatch();

            for (int i = 0; i < changesPerPatch; i++)
            {
                NetworkMutator mutator;
                if (rand_.NextDouble() < addRemoveChance_)
                {
                    mutator = CreateAddRemoveMutator(wantedNoOfNodes);
                }
                else
                {
                    mutator = CreateTypeChangeMutator();
                }

                patch.mutators_.Add(mutator);
                mutator.Apply();
                /**
                 * NOTE: IMPORTANT: applying is here, because next mutator
                 * can be generated wrongly if this one is not applied
                 * (it'd fit for unchanged network, but not for changed one)
                 */
            }

            return patch;
        }
        public NetworkPatch CreateAndApplyPatch(int changesPerPatch, int wantedNoOfNodes)
        {
            NetworkPatch patch = new NetworkPatch();

            for (int i = 0; i < changesPerPatch; i++)
            {
                NetworkMutator mutator;
                if (rand_.NextDouble() < addRemoveChance_)
                {
                    mutator = CreateAddRemoveMutator(wantedNoOfNodes);
                }
                else
                {
                    mutator = CreateTypeChangeMutator();
                }

                patch.mutators_.Add(mutator);
                mutator.Apply();

                /**
                 * NOTE: IMPORTANT: applying is here, because next mutator
                 * can be generated wrongly if this one is not applied
                 * (it'd fit for unchanged network, but not for changed one)
                 */
            }

            return(patch);
        }
        private void PerformTeachingSerie(int wantedNoOfNodes, int changesPerPatch, int patchesPerTeachingSerie)
        {
            // patch --> its error change - lower = better
            Dictionary <NetworkPatch, double> patchesEfficiency = new Dictionary <NetworkPatch, double>();
            double serieStartError  = network_.CalculateTrainingSqrError();
            int    startNetworkHash = network_.GetHashCode();

            while (patchesEfficiency.Count < patchesPerTeachingSerie)
            {
#if DEBUG
                string graphBeforePatch = network_.PrintNetworkStruct();
#endif
                NetworkPatch patch = patchFactory_.CreateAndApplyPatch(changesPerPatch, wantedNoOfNodes);
                patchesEfficiency[patch] = network_.CalculateTrainingSqrError() - serieStartError;
#if DEBUG
                string graphAfterPatch = network_.PrintNetworkStruct();
#endif
                patch.Revert();
#if DEBUG
                string graphAfterRevert           = network_.PrintNetworkStruct();
                double errorAfterNotApplyingPatch = network_.CalculateTrainingSqrError();
                if (serieStartError != errorAfterNotApplyingPatch)
                {
                    Logger.Log(this, String.Format(
                                   "REVERT WENT WRONG!\n" +
                                   "<<<<<<<<<<<<GRAPH BEFORE PATCH >>>>>>>>>>\n{0}\n" +
                                   "<<<<<<<<<<<<GRAPH AFTER PATCH >>>>>>>>>>\n{1}\n" +
                                   "<<<<<<<<<<<<GRAPH AFTER REVERT >>>>>>>>>>\n{2}\n",
                                   graphBeforePatch,
                                   graphAfterPatch,
                                   graphAfterRevert),
                               10);
                    throw new ApplicationException("revert went wrong");
                }
#endif
            }

            //NOTE: what is interesting double.NaN is lowest possible number AND double.NaN != double.NaN //WTF??
            double bestChange = patchesEfficiency.Min(x => double.IsNaN(x.Value) ? double.PositiveInfinity : x.Value);
            Logger.Log(this, String.Format("best change {0}", bestChange));
            if (bestChange <= 0.0d && //IMPORTANT: for now only
                !double.IsInfinity(bestChange) &&
                !double.IsNaN(bestChange))
            {
                Logger.Log(this, "applying patch!");
                NetworkPatch bestPatch = patchesEfficiency.First(patch => patch.Value == bestChange).Key;
                bestPatch.Apply();
                double errorAfterApplyingPatch = network_.CalculateTrainingSqrError();
                Logger.Log(this, String.Format("error after appplying patch {0}", errorAfterApplyingPatch));
//#if DEBUG
                if (bestChange < -1E-2)
                {
                    PrintGraphVisualization(network_);
                }
//#endif

                double delta = 1E-4;
                if (serieStartError + bestChange - errorAfterApplyingPatch > delta)
                {
                    throw new ApplicationException("something went rly bad");
                }
            }
            else
            {
                Logger.Log(this, "NOT applying patch");
            }
        }