public Trainer(HybridStatePredictor target)
            {
                this.target = target;
                checkLock   = new object();
                threads     = new List <Thread>();
                readLocks   = new List <object>();
                trainLocks  = new List <object>();
                predictors  = new List <HybridStatePredictor>();

                dnaLength = target.table.Length;
                int steps;

                for (steps = 0; Math.Pow(2, steps) < dnaLength; steps++)
                {
                    ;
                }
                steps++; //include last and first
                trainIntensity             = new int[steps];
                trainSampleCount           = new int[steps];
                trainAccumulatedAccuracies = new double[steps];
                for (int i = 0; i < steps; i++)
                {
                    if (i != steps - 1)
                    {
                        trainIntensity[i] = (int)Math.Pow(2, i);
                    }
                    else
                    {
                        trainIntensity[i] = dnaLength;
                    }
                }
            }
        public static void leapOverride(HybridStatePredictor destination, HybridStatePredictor original, Random rdm, int intensity)
        {
            destination.reset();
            //Copy original to destination
            original.table.CopyTo(destination.table, 0);

            destination.trainingDepth = original.trainingDepth + 1;

            //Choose the number of changes to make to the original based on intensity
            //not very optimal
            int changeCount = intensity;

            destination.lastLeapCount = changeCount;

            //Make changes
            int index;

            for (int i = 0; i < changeCount; i++)
            {
                //Choose random table index for change
                index = rdm.Next(destination.table.Length);

                //Check if index is prediction image or state image
                if (index % 2 == 0)
                {
                    destination.table[index] = (byte)rdm.Next(destination.symbolSize); //New random prediction at index
                }
                else
                {
                    destination.table[index] = (byte)rdm.Next(destination.stateSize); //New random state at index
                }
            }

            destination.computeStateTransitionsTable();
        }
        public static HybridStatePredictor loadFromFile(string file)
        {
            byte[] saveArray = System.IO.File.ReadAllBytes(file);

            HybridStatePredictor load = null;

            //version check
            if (saveArray[0] == 0)
            {
                int symbolSize = BitConverter.ToInt32(saveArray, 1);
                int stateSize  = BitConverter.ToInt32(saveArray, 5);
                load = new HybridStatePredictor(symbolSize, stateSize);
                load.trainingDepth   = BitConverter.ToInt32(saveArray, 9);
                load.predictionCount = BitConverter.ToInt32(saveArray, 13);
                load.errorCount      = BitConverter.ToInt32(saveArray, 17);
                load.lossCount       = BitConverter.ToInt32(saveArray, 21);
                load.lastLeapCount   = BitConverter.ToInt32(saveArray, 25);
                for (int i = 0; i < load.table.Length; i++)
                {
                    load.table[i] = saveArray[29 + i];
                }

                load.computeStateTransitionsTable();
            }
            else
            {
                throw new Exception("Invalid file version.");
            }

            return(load);
        }
            public void StopTrain()
            {
                training = false;

                //Pass through all trainLocks to check cleared
                for (int i = 0; i < trainLocks.Count; i++)
                {
                    Monitor.Enter(trainLocks[i]);
                    Monitor.Exit(trainLocks[i]);
                }

                //Copy train result to target
                HybridStatePredictor.copyInto(best, target);
            }
 public static void copyInto(HybridStatePredictor original, HybridStatePredictor destination)
 {
     original.table.CopyTo(destination.table, 0);
     destination.errorCount      = original.errorCount;
     destination.lastLeapCount   = original.lastLeapCount;
     destination.predictionCount = original.predictionCount;
     destination.state           = original.state;
     destination.stateSize       = original.stateSize;
     destination.symbolSize      = original.symbolSize;
     destination.tableStride     = original.tableStride;
     destination.trainingDepth   = original.trainingDepth;
     original.stateMetrics.CopyTo(destination.stateMetrics, 0);
     destination.stateStride = original.stateStride;
     original.stateTransitionTable.CopyTo(destination.stateTransitionTable, 0);
     destination.lossCount = original.lossCount;
     original.lossTransitionTable.CopyTo(destination.lossTransitionTable, 0);
 }
        public static void randomOverride(HybridStatePredictor destination, Random rdm)
        {
            destination.reset();
            destination.trainingDepth = 0;


            for (int i = 0; i < destination.table.Length; i++)
            {
                if (i % 2 == 0)
                {
                    destination.table[i] = (byte)rdm.Next(destination.symbolSize); //New random prediction at index
                }
                else
                {
                    destination.table[i] = (byte)rdm.Next(destination.stateSize); //New random state at index
                }
            }

            destination.computeStateTransitionsTable();
        }
            public void StartTrain(SymbolCorpus trainSet)
            {
                this.trainSet = trainSet;
                int threadCount = 8;

                training = true;

                best = new HybridStatePredictor(target.symbolSize, target.stateSize);
                HybridStatePredictor.copyInto(target, best);
                best.reset();
                best.testPredict(trainSet);
                Console.WriteLine("Layer training started with: " + best.getStats());

                for (int i = 0; i < trainSampleCount.Length; i++)
                {
                    trainSampleCount[i]           = 1;
                    trainAccumulatedAccuracies[i] = best.accuracy;
                }


                for (int i = 0; i < threadCount; i++)
                {
                    //Add thread lock
                    readLocks.Add(new object());
                    trainLocks.Add(new object());
                    //Create thread resource
                    HybridStatePredictor tester = new HybridStatePredictor(best.symbolSize, best.stateSize);
                    predictors.Add(tester);
                    //Create and start thread
                    Thread tt = new Thread(ThreadTrain);
                    threads.Add(tt);
                }

                //Start threads after to avoid first cycle conflicts
                for (int i = 0; i < threadCount; i++)
                {
                    threads[i].Start(i);
                }
            }
            private void ThreadTrain(object indexObj)
            {
                int    index             = (int)indexObj;
                Random rdm               = new Random(index);
                int    currentTrainIndex = trainIntensity.Length - 1;

                Monitor.Enter(trainLocks[index]);


                int usedIntensity;

                //while training is in place
                while (training)
                {
                    //Copy from best (if version control is in place, check version)
                    usedIntensity = rdm.Next(trainIntensity[currentTrainIndex]) + 1; //Inclusive upper bound, exclusive lower bound
                    lock (readLocks[index])
                    {
                        HybridStatePredictor.leapOverride(predictors[index], best, rdm, usedIntensity);
                    }

                    predictors[index].testPredict(trainSet);

                    lock (checkLock)
                    {
                        //Increment used training intensity sampling count
                        for (int i = currentTrainIndex; i >= 0; i--)
                        {
                            if (usedIntensity <= trainIntensity[i])
                            {
                                trainSampleCount[i]++;
                            }
                        }

                        if (predictors[index].accuracy > best.accuracy)
                        {
                            //Best found
                            //Tune training intensity
                            //Add incentive to used training Intensity
                            double bestImprovement = trainAccumulatedAccuracies[0] / trainSampleCount[0];
                            int    bestIndex       = 0;
                            double improvement;
                            for (int i = currentTrainIndex; i >= 0; i--)
                            {
                                if (usedIntensity <= trainIntensity[i])
                                {
                                    trainAccumulatedAccuracies[i] += predictors[index].accuracy - best.accuracy;
                                }
                                improvement = trainAccumulatedAccuracies[i] / trainSampleCount[i];
                                if (improvement > bestImprovement)
                                {
                                    bestImprovement = improvement;
                                    bestIndex       = i;
                                }
                            }
                            //Go through remaining intensitys to check if there is a better one
                            for (int i = currentTrainIndex + 1; i < trainSampleCount.Length; i++)
                            {
                                improvement = trainAccumulatedAccuracies[i] / trainSampleCount[i];
                                if (improvement > bestImprovement)
                                {
                                    bestImprovement = improvement;
                                    bestIndex       = i;
                                }
                            }
                            //Change index to the best expected improvement
                            currentTrainIndex = bestIndex;

                            if (predictors[index].trainingDepth % 10 == 0)
                            {
                                printTrainingIntensityStatus();
                            }

                            //Start copy procedure
                            //Lock all read locks
                            for (int i = 0; i < readLocks.Count; i++)
                            {
                                Monitor.Enter(readLocks[i]);
                            }

                            //Copy into best
                            HybridStatePredictor.copyInto(predictors[index], best);

                            Console.WriteLine("Leap by thread " + index + " : " + best.getStats());
                            //Unlock all read locks
                            for (int i = 0; i < readLocks.Count; i++)
                            {
                                Monitor.Exit(readLocks[i]);
                            }
                        }
                        else
                        {
                            //Failed leap
                            //leapIntensity = 0.99 * leapIntensity + 0.01 * (1f); //Gravity to randomness
                        }
                    }
                }

                Monitor.Exit(trainLocks[index]);
            }
        public void train2(SymbolCorpus trainSet, double minutes)
        {
            Random rdm = new Random();

            HybridStatePredictor predictor = new HybridStatePredictor(symbolSize, stateSize);

            //Make copy of current
            copyInto(this, predictor);

            if (predictor.trainingDepth == 0)
            {
                randomOverride(predictor, rdm);

                //Read and predict analysis
                predictor.testPredict(trainSet);

                //TODO Generate some more randoms and choose best - might not be needed since leap Intensity is so high at the beginning
            }

            //Initialize training variables
            HybridStatePredictor testTable = new HybridStatePredictor(predictor.symbolSize, predictor.stateSize);
            HybridStatePredictor temp;

            double leapIntensity = predictor.lastLeapIntensity * 2 * 4;

            if (leapIntensity > 0.9)
            {
                leapIntensity = 0.9;
            }

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            Console.Write("Training:");
            int percentil = 1;

            while (stopwatch.ElapsedMilliseconds < 1000 * 60 * minutes)
            {
                if (stopwatch.ElapsedMilliseconds > (1000 * 60 * minutes / 10.0) * percentil)
                {
                    Console.Write("$"); //print training tick
                    percentil++;
                }

                //Mutation
                //leapOverride(testTable, predictor, rdm, leapIntensity);

                //Read and predict analysis
                testTable.testPredict(trainSet);

                if (testTable.accuracy > predictor.accuracy)
                {
                    //Best predictor found

                    //Soft change with memory for sucessful mutations intensity (x2 because of random average behaviour)
                    leapIntensity = 0.8 * leapIntensity + 0.2 * (2 * testTable.lastLeapIntensity * 4);

                    if (leapIntensity > 0.9)
                    {
                        leapIntensity = 0.9; //maximum allowed mutation intensity
                    }
                    //Swap predictors for memory usage
                    temp      = predictor;
                    predictor = testTable;
                    testTable = temp;
                }
            }
            stopwatch.Stop();
            Console.WriteLine();

            copyInto(predictor, this);
        }