/// <summary>
        /// Initializes a new instance of the <see cref="DoubleArrayChromosome"/> class.
        /// </summary>
        /// 
        /// <param name="source">Source chromosome to copy.</param>
        /// 
        /// <remarks><para>This is a copy constructor, which creates the exact copy
        /// of specified chromosome.</para></remarks>
        /// 
        public DoubleArrayChromosome( DoubleArrayChromosome source )
        {
            this.chromosomeGenerator = source.chromosomeGenerator;
            this.mutationMultiplierGenerator = source.mutationMultiplierGenerator;
            this.mutationAdditionGenerator = source.mutationAdditionGenerator;
            this.length  = source.length;
            this.fitness = source.fitness;
            this.mutationBalancer = source.mutationBalancer;
            this.crossoverBalancer = source.crossoverBalancer;

            // copy genes
            val = (double[]) source.val.Clone( );
        }
        /// <summary>
        /// Runs learning epoch.
        /// </summary>
        /// 
        /// <param name="input">Array of input vectors.</param>
        /// <param name="output">Array of output vectors.</param>
        /// 
        /// <returns>Returns summary squared learning error for the entire epoch.</returns>
        /// 
        /// <remarks><para><note>While running the neural network's learning process, it is required to
        /// pass the same <paramref name="input"/> and <paramref name="output"/> values for each
        /// epoch. On the very first run of the method it will initialize evolutionary fitness
        /// function with the given input/output. So, changing input/output in middle of the learning
        /// process, will break it.</note></para></remarks>
        ///
        public double RunEpoch( double[][] input, double[][] output )
        {
            //Debug.Assert( input.Length > 0 );
            //Debug.Assert( output.Length > 0 );
               // Debug.Assert( input.Length == output.Length );
               // Debug.Assert( network.InputsCount == input.Length );

            // check if it is a first run and create population if so
            if ( population == null )
            {
                // sample chromosome
                DoubleArrayChromosome chromosomeExample = new DoubleArrayChromosome(
                    chromosomeGenerator, mutationMultiplierGenerator, mutationAdditionGenerator,
                    numberOfNetworksWeights );

                // create population ...
                population = new Population( populationSize, chromosomeExample,
                    new EvolutionaryFitness(network, input, output), selectionMethod);
                // ... and configure it
                population.CrossoverRate = crossOverRate;
                population.MutationRate = mutationRate;
                population.RandomSelectionPortion = randomSelectionRate;
            }

            // run genetic epoch
            population.RunEpoch( );

            // get best chromosome of the population
            DoubleArrayChromosome chromosome = (DoubleArrayChromosome) population.BestChromosome;
            double[] chromosomeGenes = chromosome.Value;

            // put best chromosome's value into neural network's weights
            int v = 0;

            for ( int i = 0; i < network.Layers.Length; i++ )
            {
                Layer layer = network.Layers[i];

                for ( int j = 0; j < layer.Neurons.Length; j++ )
                {
                    ActivationNeuron neuron = layer.Neurons[j] as ActivationNeuron;

                    for ( int k = 0; k < neuron.Weights.Length; k++ )
                    {
                        neuron.Weights[k] = chromosomeGenes[v++];
                    }
                    neuron.Threshold = chromosomeGenes[v++];
                }
            }

            //Debug.Assert( v == numberOfNetworksWeights );

            return 1.0 / chromosome.Fitness;
        }