//Generates the response training data
        public static void GenerateTrainingData(PhysicallyUncloneableFunction aPUF, sbyte[][] trainingData, sbyte[] trainingResponse, Random randomGenerator)
        {
            int trainingSize = trainingData.Length;
            int bitNum       = aPUF.BitNumber;

            for (int i = 0; i < trainingSize; i++)
            {
                trainingData[i] = GenerateRandomPhiVector(bitNum, randomGenerator);
                //trainingResponse[i] = new sbyte[1];
                trainingResponse[i] = aPUF.ComputeResponse(trainingData[i]);
            }
        }
        //Generates textfiles for loading IPUF training data into Keras
        public static void GenerateIPUFDataForKeras(PhysicallyUncloneableFunction iPUF, int trainingSize, string trainDirectory)
        {
            int indexer = 0;

            sbyte[][] trainingData     = new sbyte[trainingSize][];
            sbyte[][] trainingResponse = new sbyte[1][]; //first index corresponds to the number of different PUFs (in this case 1) second index is sample number
            trainingResponse[0] = new sbyte[trainingSize];
            Random[] rGen = new Random[AppConstants.CoreNumber];
            PhysicallyUncloneableFunction[] iPUFHolder = new PhysicallyUncloneableFunction[] { iPUF }; //only need a single IPUF for this type of data generation

            //Data is generated in parallel so we need a random number generator for each core
            for (int i = 0; i < AppConstants.CoreNumber; i++)
            {
                rGen[i] = new Random((int)DateTime.Now.Ticks);
                System.Threading.Thread.Sleep(10); //prevent the random number generators from being the same
            }
            //Generate all the training data and responses in blocks (in parallel)
            GenerateTrainingDataParallel(iPUFHolder, trainingData, trainingResponse, rGen);

            //Now have the training data and responses filled in, time to write to textfiles
            string[] lines   = new string[trainingSize];
            string[] phiLine = new string[1]; //this is to write phi information into the text file
            for (int i = 0; i < trainingSize; i++)
            {
                //lines[i] = trainingResponse[0][i].ToString();
                lines[i] = "";
                for (int j = 0; j < iPUF.BitNumber + 1; j++) //length of phi
                {
                    if (trainingData[i][j] == 1)
                    {
                        lines[i] = lines[i] + trainingData[i][j];
                    }
                    else
                    {
                        lines[i] = lines[i] + "m"; //m means -1
                    }
                }
                phiLine[0] = lines[i];
                string currentFileName = trainingResponse[0][i].ToString() + indexer.ToString();
                File.WriteAllLines(trainDirectory + "\\" + currentFileName + ".txt", phiLine);
                indexer++;
            }
            //Write the training text file that contains all the examples
            //string[] trainingFileLines = new string[trainingSize];
            //for (int i = 0; i < trainingSize; i++)
            //{
            //    trainingFileLines[i] = lines[i] + ".txt" + "\t" + trainingResponse[0][i].ToString();
            //}
            //File.WriteAllLines(trainDirectory + "\\TrainingClassList.txt", trainingFileLines);
        }
        //Generates the response training data for a single PUF model in parallel
        public static void GenerateTrainingDataParallel(PhysicallyUncloneableFunction aPUF, sbyte[][] trainingData, sbyte[][] trainingResponse, Random[] randomGenerator)
        {
            int trainingSize = trainingData.Length;
            int coreNumberForThisMethodOnly = AppConstants.CoreNumber;
            //error checking
            double roundCheck = trainingSize / (double)coreNumberForThisMethodOnly;

            if (roundCheck != (int)roundCheck)
            {
                coreNumberForThisMethodOnly = AppConstants.CoreNumber - 3; //try reducing the core number to make the parallelization work

                //do another double check just to be safe
                roundCheck = trainingSize / (double)coreNumberForThisMethodOnly;
                if (roundCheck != (int)roundCheck)
                {
                    throw new Exception("The training size is not integer divisible by the number of CPU cores. Resize training data or avoid parallelization.");
                }
            }

            int trainingBlock = trainingSize / coreNumberForThisMethodOnly;
            int bitNum        = aPUF.BitNumber;

            Parallel.For(0, coreNumberForThisMethodOnly, i =>
                         //for(int i=0;i<coreNumberForThisMethodOnly;i++)
            {
                //for (int i = 0; i < AppConstants.CoreNumber; i++)
                //{
                for (int j = trainingBlock * i; j < (trainingBlock * (i + 1)); j++)
                {
                    trainingData[j]        = GenerateRandomPhiVector(bitNum, randomGenerator[i]);
                    trainingResponse[0][j] = aPUF.ComputeResponse(trainingData[j]);
                }
                Console.Out.WriteLine(i.ToString());
                // }
            });
            //int l = 0;
        }