/// <summary>
        /// Calculates the weight adjustments for the connections into the output layer.
        /// </summary>
        /// <param name="outErr">the output unit errors</param>
        /// <param name="nNet">the network undergoing training</param>
        ///
        private void CalcOutputWtAdjust(List <double> outErr, NeuralNet nNet)
        {
            int           n = nNet.NumLayers, prevIdx = 0;
            List <double> xVec = new List <double>();

            // get the weighted connections between the last hidden layer and the output layer
            NNetWeightedConnect wtConnect = nNet.GetWeightedConnect(n);

            // get the input values for the weighted connections
            nNet.GetActivations(xVec, n - 1);

            int nOut = wtConnect.NumOutputNodes;

            // calculate the weight adjustments for each weighted connection output unit
            for (int i = 0; i < nOut; i++)
            {
                double        ei      = outErr[i];
                List <double> weights = new List <double>();

                // get the output units weight vector
                wtConnect.GetWeightVector(i, weights);

                // calculate the total weight adjustment
                for (int j = 0; j < xVec.Count; j++)
                {
                    // the weight adjustment calculation
                    double dW = mLearnConst * ei * xVec[j];

                    // if the momentum term is greater than 0
                    // the previous weighting needs to be taken into account
                    if (mMomentum > 0)
                    {
                        if (mPrevOutWt.Count > prevIdx)
                        {
                            double dWPrev = mPrevOutWt[prevIdx];

                            // include a percentage of the previous weighting
                            dW += mMomentum * dWPrev;

                            // store the weighting
                            mPrevOutWt[prevIdx] = dW;
                        }
                        else
                        {
                            // store the first weighting
                            mPrevOutWt.Add(dW);
                        }
                    }

                    // the total weight adjustment
                    weights[j] += dW;
                    prevIdx++;
                }

                wtConnect.SetWeightVector(i, weights);
            }

            nNet.SetWeightedConnect(wtConnect, n);
        }
        /// <summary>
        /// Calculates the weight adjustments for the connections into the hidden layers.
        /// </summary>
        /// <param name="hidErrSig">the hidden unit errors</param>
        /// <param name="inputVec">the current training set input values</param>
        /// <param name="nNet">the network undergoing training</param>
        ///
        private void CalcHiddenWtAdjust(List <List <double> > hidErrSig,
                                        List <double> inputVec, NeuralNet nNet)
        {
            List <double> xVec = new List <double>();
            int           maxHidLayIdx = nNet.NumLayers - 1, prevIdx = 0;

            // calculate the weight adjustments for the hidden layers
            for (int n = maxHidLayIdx; n >= 0; n--)
            {
                // get the weighted connections between the current layer and the previous hidden layer
                NNetWeightedConnect wtConnect = nNet.GetWeightedConnect(n);

                // get the hidden unit errors for the previous hidden layer
                // N.B. the hidden error signals are stored in reverse order
                List <double> outErr = hidErrSig[maxHidLayIdx - n];

                if (n == 0)
                {
                    // we are dealing with the input layer
                    xVec = inputVec;
                }
                else
                {
                    // we are dealing with a hidden layer
                    nNet.GetActivations(xVec, n - 1);
                }

                int nOut = wtConnect.NumOutputNodes;

                // calculate the weight adjustments for each weighted connection output unit
                for (int i = 0; i < nOut; i++)
                {
                    double        ei      = outErr[i];
                    List <double> weights = new List <double>();

                    // get the output units weight vector
                    wtConnect.GetWeightVector(i, weights);

                    // calculate the total weight adjustment
                    for (int j = 0; j < xVec.Count; j++)
                    {
                        // the weight adjustment calculation
                        double dW = mLearnConst * ei * xVec[j];

                        // if the momentum term is greater than 0
                        // the previous weighting needs to be taken into account
                        if (mMomentum > 0)
                        {
                            if (mPrevHidWt.Count > prevIdx)
                            {
                                double dWPrev = mPrevHidWt[prevIdx];

                                // include a percentage of the previous weighting
                                dW += mMomentum * dWPrev;

                                // store the weighting
                                mPrevHidWt[prevIdx] = dW;
                            }
                            else
                            {
                                // store the first weighting
                                mPrevHidWt.Add(dW);
                            }
                        }

                        // the total weight adjustment
                        weights[j] += dW;
                        prevIdx++;
                    }

                    wtConnect.SetWeightVector(i, weights);
                }

                nNet.SetWeightedConnect(wtConnect, n);
            }
        }
        /// <summary>
        /// Instantiates this network from a string representation stored in a file.
        /// </summary>
        /// <param name="fname">the file containing a string representation of the network</param>
        ///
        private void InitializeFromFile(string fname)
        {
            StreamReader inStream = new StreamReader(fname);

            if (inStream != null)
            {
                int outUnitType;

                // deserialize the main details
                string sNumInputs      = ReadString(inStream);
                string sNumOutputs     = ReadString(inStream);
                string sNumLayers      = ReadString(inStream);
                string sOutUnitType    = ReadString(inStream);
                string sOutUnitSlope   = ReadString(inStream);
                string sOutUnitAmplify = ReadString(inStream);

                mNumInputs      = Convert.ToInt32(sNumInputs);
                mNumOutputs     = Convert.ToInt32(sNumOutputs);
                mNumLayers      = Convert.ToInt32(sNumLayers);
                outUnitType     = Convert.ToInt32(sOutUnitType);
                mOutUnitSlope   = Convert.ToDouble(sOutUnitSlope);
                mOutUnitAmplify = Convert.ToDouble(sOutUnitAmplify);

                mOutUnitType = (ActiveT)outUnitType;

                // deserialize the layer data
                for (int i = 0; i <= mNumLayers; i++)                   // use <= to include the output layer
                {
                    string sDelim = ReadString(inStream);
                    string sNIn   = ReadString(inStream);
                    string sNOut  = ReadString(inStream);
                    string sNUnit = ReadString(inStream);
                    string sSUnit = ReadString(inStream);
                    string sAUnit = ReadString(inStream);

                    int    nIn   = Convert.ToInt32(sNIn);
                    int    nOut  = Convert.ToInt32(sNOut);
                    int    nUnit = Convert.ToInt32(sNUnit);
                    double sUnit = Convert.ToDouble(sSUnit);
                    double aUnit = Convert.ToDouble(sAUnit);

                    NNetWeightedConnect connect = new NNetWeightedConnect(nIn, nOut);

                    for (int j = 0; j < nOut; j++)
                    {
                        List <double> weights = new List <double>();

                        for (int k = 0; k < nIn; k++)
                        {
                            string sWgt = ReadString(inStream);
                            double wgt  = Convert.ToDouble(sWgt);

                            weights.Add(wgt);
                        }

                        connect.SetWeightVector(j, weights);
                    }

                    mLayers.Add(connect);
                    mActiveUnits.Add((ActiveT)nUnit);
                    mActiveSlope.Add(sUnit);
                    mActiveAmplify.Add(aUnit);
                }

                // tidy up
                inStream.Close();
            }
        }