예제 #1
0
        /// <summary>
        /// Run a simulation and store the results for later use by <see cref="GetIndices(MarketObservable, List{Date})"/>
        /// </summary>
        /// <param name="simNumber"></param>
        public override void RunSimulation(int simNumber)
        {
            simulation    = new Dictionary <int, double[]>();
            acculatedDivi = new Dictionary <int, double[]>();
            var    simPrices = prices.Copy();
            double oldDF     = 1;
            double newDF;

            for (var timeCounter = 0; timeCounter < allRequiredDates.Count; timeCounter++)
            {
                double dt = timeCounter > 0
                    ? allRequiredDates[timeCounter] - allRequiredDates[timeCounter - 1]
                    : allRequiredDates[timeCounter] - anchorDate.value;
                newDF = discountCurve.GetDF(allRequiredDates[timeCounter]);
                var rateDrift = oldDF / newDF;
                oldDF = newDF;
                dt    = dt / 365.0;
                var sdt = Math.Sqrt(dt);
                var dW  = normal.Generate();
                acculatedDivi[allRequiredDates[timeCounter]] = Vector.Zeros(shares.Length);
                for (var s = 0; s < shares.Length; s++)
                {
                    acculatedDivi[allRequiredDates[timeCounter]][s] = simPrices[s] * divYields[s] * dt;
                    simPrices[s] = simPrices[s] * rateDrift *
                                   Math.Exp((-divYields[s] - 0.5 * vols[s] * vols[s]) *dt + vols[s] *sdt *dW[s]);
                }

                simulation[allRequiredDates[timeCounter]] = simPrices.Copy();
            }
        }
예제 #2
0
        private void DoCreateData()
        {
            // Generate data with n Gaussian distributions
            var data = new double[this.k][][];

            for (var i = 0; i < this.k; i++)
            {
                // Create random centroid to place the Gaussian distribution
                var mean = Matrix.Random(2, -6.0, +6.0);

                // Create random covariance matrix for the distribution
                var covariance = Accord.Statistics.Tools.RandomCovariance(2, -5, 5);

                // Create the Gaussian distribution
                var gaussian = new MultivariateNormalDistribution(mean, covariance);

                var samples = Tools.Random.Next(150, 250);
                data[i] = gaussian.Generate(samples);
            }

            // Join the generated data
            this.mixture = Matrix.Stack(data);

            // Update the scatter plot
            CreateScatterplot(this.PlotModel, Colors, this.mixture, this.k);

            // Forget previous initialization
            this.kmeans = null;

            this.canInitializeOrFit = true;
            this.ChangeCanExecute();
        }
        public void GenerateTest2()
        {
            Accord.Math.Tools.SetupGenerator(0);

            var normal = new MultivariateNormalDistribution(
                new double[] { 2, 6 },
                new double[, ] {
                { 2, 1 }, { 1, 5 }
            });

            double[][] sample = new double[1000000][];
            for (int i = 0; i < sample.Length; i++)
            {
                sample[i] = normal.Generate();
            }

            double[] mean = sample.Mean();
            double[,] cov = sample.Covariance();

            Assert.AreEqual(2, mean[0], 1e-2);
            Assert.AreEqual(6, mean[1], 1e-2);

            Assert.AreEqual(2, cov[0, 0], 1e-2);
            Assert.AreEqual(1, cov[0, 1], 1e-2);
            Assert.AreEqual(1, cov[1, 0], 1e-2);
            Assert.AreEqual(5, cov[1, 1], 2e-2);
        }
        /// <summary>
        ///   Creates the initial scatter plot graphs containing some random
        ///   data. This data is generated by sampling Gaussian distributions.
        /// </summary>
        ///
        private void btnGenerateRandom_Click(object sender, EventArgs e)
        {
            k = (int)numClusters.Value;

            // Generate data with n Gaussian distributions
            double[][][] data = new double[k][][];

            for (int i = 0; i < k; i++)
            {
                // Create random centroid to place the Gaussian distribution
                double[] mean = Vector.Random(2, -6.0, +6.0);

                // Create random covariance matrix for the distribution
                double[,] covariance = Accord.Statistics.Tools.RandomCovariance(2, -5, 5);

                // Create the Gaussian distribution
                var gaussian = new MultivariateNormalDistribution(mean, covariance);

                int samples = Accord.Math.Random.Generator.Random.Next(150, 250);
                data[i] = gaussian.Generate(samples);
            }

            // Join the generated data
            observations = Matrix.Stack(data);

            // Update the scatter plot
            CreateScatterplot(graph, observations, k);

            // Forget previous initialization
            kmeans = null;
        }
예제 #5
0
        public void MultivariateNormalGenerateTest()
        {
            // mean vector
            double[] mu = { 2.0, 6.0 };

            // covariance
            double[,] cov =
            {
                { 2, 1 },
                { 1, 5 }
            };

            // Create a multivariate Normal distribution
            var normal = new MultivariateNormalDistribution(mu, cov);

            // Generate 1000000 samples from it
            double[][] samples = normal.Generate(1000000);

            // Try to estimate a new Normal distribution from
            // generated samples to check if they indeed match
            var actual = MultivariateNormalDistribution.Estimate(samples);

            Assert.IsTrue(mu.IsEqual(actual.Mean, 0.1));
            Assert.IsTrue(cov.IsEqual(actual.Covariance, 0.1));
        }
        public void GenerateTest1()
        {
            Accord.Math.Tools.SetupGenerator(0);

            double[] mean = { 2, 6 };

            double[,] cov =
            {
                { 2, 1 },
                { 1, 5 }
            };

            var normal = new MultivariateNormalDistribution(mean, cov);

            double[][] source = normal.Generate(10000000);

            var target = new MultivariateEmpiricalDistribution(source);

            Assert.IsTrue(mean.IsEqual(target.Mean, 0.001));
            Assert.IsTrue(cov.IsEqual(target.Covariance, 0.003));

            double[][] samples = target.Generate(10000000);

            double[] sampleMean = samples.Mean();
            double[,] sampleCov = samples.Covariance();

            Assert.AreEqual(2, sampleMean[0], 1e-2);
            Assert.AreEqual(6, sampleMean[1], 1e-2);
            Assert.AreEqual(2, sampleCov[0, 0], 1e-2);
            Assert.AreEqual(1, sampleCov[0, 1], 1e-2);
            Assert.AreEqual(1, sampleCov[1, 0], 1e-2);
            Assert.AreEqual(5, sampleCov[1, 1], 2e-2);
        }
예제 #7
0
        public override void RunSimulation(int simNumber)
        {
            foreach (var simulator in _ccySimMap.Values)
            {
                simulator.RunSimulation(simNumber);
            }
            _simulation = new Dictionary <int, double[]>();
            var simPrices = _spots.Copy();
            var oldDrifts = Vector.Ones(simPrices.Length);

            for (var timeCounter = 0; timeCounter < _allRequiredDates.Count; timeCounter++)
            {
                double dt = timeCounter > 0
                    ? _allRequiredDates[timeCounter] - _allRequiredDates[timeCounter - 1]
                    : _allRequiredDates[timeCounter] - _anchorDate.value;
                dt = dt / 365.0;
                var sdt = Math.Sqrt(dt);
                var dW  = _normal.Generate();

                for (var s = 0; s < _currencyPairs.Length; s++)
                {
                    var drift = _ccySimMap[_currencyPairs[s].CounterCurrency.ToString()]
                                .Numeraire(_allRequiredDates[timeCounter]) /
                                _ccySimMap[_currencyPairs[s].BaseCurrency.ToString()]
                                .Numeraire(_allRequiredDates[timeCounter]);

                    simPrices[s] = simPrices[s] * drift / oldDrifts[s] *
                                   Math.Exp(-0.5 * _vols[s] * _vols[s] * dt + _vols[s] * sdt * dW[s]);
                    oldDrifts[s] = drift;
                }

                _simulation[_allRequiredDates[timeCounter]] = simPrices.Copy();
            }
        }
예제 #8
0
        public override void RunSimulation(int simNumber)
        {
            foreach (HullWhite1F simulator in rateSimulators)
            {
                simulator.RunSimulation(simNumber);
            }
            simulation = new Dictionary <int, double[]>();
            double[] simPrices = spots.Copy();
            double[] oldDrifts = Vector.Ones(simPrices.Length);

            for (int timeCounter = 0; timeCounter < allRequiredDates.Count; timeCounter++)
            {
                double dt = timeCounter > 0 ? allRequiredDates[timeCounter] - allRequiredDates[timeCounter - 1] : allRequiredDates[timeCounter] - anchorDate.value;
                dt = dt / 365.0;
                double   sdt = Math.Sqrt(dt);
                double[] dW  = normal.Generate();

                for (int s = 0; s < currencyPairs.Length; s++)
                {
                    double drift = ccySimMap[currencyPairs[s].counterCurrency].Numeraire(allRequiredDates[timeCounter]) /
                                   ccySimMap[currencyPairs[s].baseCurrency].Numeraire(allRequiredDates[timeCounter]);

                    simPrices[s] = simPrices[s] * drift / oldDrifts[s] *
                                   Math.Exp((-0.5 * vols[s] * vols[s]) * dt + vols[s] * sdt * dW[s]);
                    oldDrifts[s] = drift;
                }
                simulation[allRequiredDates[timeCounter]] = simPrices.Copy();
            }
        }
예제 #9
0
        private static void Create(int n1, int n2, int k, out double[][] inputs, out NaiveKNearestNeighbors naive, out KNearestNeighbors <double[]> normal, out KNearestNeighbors target)
        {
            int n = n1 + n2;

            double[][] gauss1 = MultivariateNormalDistribution.Generate(n1,
                                                                        mean: new double[] { 2, 1 },
                                                                        covariance: new double[, ]
            {
                { 1, 0 },
                { 0, 1 },
            });

            double[][] gauss2 = MultivariateNormalDistribution.Generate(n2,
                                                                        mean: new double[] { -1, 4 },
                                                                        covariance: new double[, ]
            {
                { 2, 1 },
                { 0, 3 },
            });

            inputs = gauss1.Stack(gauss2);
            int[] outputs = Matrix.Vector(n1, 0).Concatenate(Matrix.Vector(n2, +1));

            var idx = Vector.Sample(n1 + n2);

            inputs  = inputs.Submatrix(idx);
            outputs = outputs.Submatrix(idx);

            naive  = new NaiveKNearestNeighbors(k, inputs, outputs);
            normal = new KNearestNeighbors <double[]>(k, inputs, outputs, new Euclidean());
            target = new KNearestNeighbors(k, inputs, outputs);
        }
예제 #10
0
        public Class GenerateClassByGaussian(int vectorSize, double expectationX, double expectationY, double[,] covarian)
        {
            var vector          = new double[vectorSize, 2];
            var distribution    = new MultivariateNormalDistribution(new[] { expectationX, expectationY }, covarian);
            var generatedPoints = distribution.Generate(vectorSize);

            for (int i = 0; i < vectorSize; i++)
            {
                vector[i, 0] = generatedPoints[i][0];
                vector[i, 1] = generatedPoints[i][1];
            }

            return(new Class(vector, expectationX, expectationY));
        }
예제 #11
0
    // Update is called once per frame
    void Update()
    {
        // Move the sphere to its current destination position
        sphere.transform.position += Time.smoothDeltaTime * destination;

        // Increase the frame counter
        numberOfFramesPassed++;

        // Change destination every 10 frames
        if (numberOfFramesPassed % 10 == 0)
        {
            // 10 frames have passed, change destination:
            float[] random = normal.Generate().ToSingle();
            destination = new Vector3(random[0], random[1], random[2]);
        }
    }
예제 #12
0
        public IEnumerable <Point> GenerateNegativePointsFromPositivesDistribution(double quantile, int count = 100)
        {
            for (var i = 0; i < count; i++)
            {
                double[] point;

                do
                {
                    point = _multivariateNormalDistribution.Generate();
                } while (_multivariateNormalDistribution.Mahalanobis(point) < CalculateThreshold(quantile));

                yield return(new Point(point)
                {
                    Label = false
                });
            }
        }
        private double[][] GetSamples(int howMany, List <BooleanStatistic> statistics)
        {
            var disitrubtion = new NormalDistribution(0, Math.Sqrt(1));
            var mean         = new double[CovarianceMatrix.GetLength(0)];

            for (int i = 0; i < CovarianceMatrix.GetLength(0); i++)
            {
                mean[i] = disitrubtion.InverseDistributionFunction(GetMean(i, statistics));
            }

            var mnormaldist = new MultivariateNormalDistribution(mean, CovarianceMatrix);
            var samples     = mnormaldist.Generate(howMany);

            samples = Booleanize(samples);

            return(samples);
        }
예제 #14
0
        public static List <double[, ]> StockPathSimulator(double spot, double vol, double divYield, double rate, double timeToExpiry, int numOfSims, int timeSteps, double bump)
        {
            double dt  = (double)timeToExpiry / timeSteps;
            var    sdt = Math.Sqrt(dt);

            // Create an instance of the multivariate normal distribution
            double[,] correlations = { { 1.0 } };
            var normal = new MultivariateNormalDistribution(Vector.Zeros(1), correlations);

            double[,] stockpaths      = new double[numOfSims, timeSteps];
            double[,] stockpaths_up   = new double[numOfSims, timeSteps];
            double[,] stockpaths_down = new double[numOfSims, timeSteps];

            for (int sim = 0; sim < numOfSims; sim++)
            {
                double S_t      = spot;
                double S_t_up   = spot + bump;
                double S_t_down = spot - bump;

                for (int t = 0; t < timeSteps; t++)
                {
                    double dW = normal.Generate()[0];
                    S_t = S_t * Math.Pow(Math.E, ((rate - divYield - Math.Pow(vol, 2) / 2) * dt + vol * dW * sdt));
                    stockpaths[sim, t] = S_t;

                    S_t_up = S_t_up * Math.Pow(Math.E, ((rate - divYield - Math.Pow(vol, 2) / 2) * dt + vol * dW * sdt));
                    stockpaths_up[sim, t] = S_t_up;

                    S_t_down = S_t_down * Math.Pow(Math.E, ((rate - divYield - Math.Pow(vol, 2) / 2) * dt + vol * dW * sdt));
                    stockpaths_down[sim, t] = S_t_down;
                }
            }

            var paths = new List <double[, ]>();

            paths.Add(stockpaths);
            paths.Add(stockpaths_up);
            paths.Add(stockpaths_down);

            return(paths);
        }
예제 #15
0
        //generate Gaussian distributed 2d array
        public static double[,] NormalDistributionSamples(int numberOfSamples, int sampleSize)
        {
            var temp = new MultivariateNormalDistribution(dimension: sampleSize);

            // mean vector
            double[] mu = temp.Generate();
            // covariance
            double[,] cov =
            {
                { 2, 1 },
                { 1, 5 }
            };

            // Create a multivariate Normal distribution
            var normal = new MultivariateNormalDistribution(mu);

            // Generate samples from it
            double[][] samples = normal.Generate(numberOfSamples);

            // Convert jagged array to 2D array
            try
            {
                int firstDim  = samples.Length;
                int secondDim = samples.GroupBy(row => row.Length).Single().Key; // throws InvalidOperationException if source is not rectangular

                var result = new double[firstDim, secondDim];
                for (int i = 0; i < firstDim; ++i)
                {
                    for (int j = 0; j < secondDim; ++j)
                    {
                        result[i, j] = samples[i][j];
                    }
                }

                return(result);
            }
            catch (InvalidOperationException)
            {
                throw new InvalidOperationException("The given jagged array is not rectangular.");
            }
        }
예제 #16
0
        public void TestMultivariateNormalSim()
        {
            double[,] correlations = { { 1.0, 0.4, 0.5 },
                                       { 0.4, 1.0, 0.6 },
                                       { 0.5, 0.6, 1.0 } };
            MultivariateNormalDistribution normal = new MultivariateNormalDistribution(Vector.Zeros(3), correlations);
            int N = 10000;

            double[,] X = new double[N, 3];
            for (int i = 0; i < N; i++)
            {
                double[] dW = normal.Generate();
                X[i, 0] = dW[0];
                X[i, 1] = dW[1];
                X[i, 2] = dW[2];
            }
            double[,] corr = X.Correlation();
            Assert.AreEqual(corr[1, 0], 0.4, 0.05);
            Assert.AreEqual(corr[2, 0], 0.5, 0.05);
            Assert.AreEqual(corr[2, 1], 0.6, 0.05);
        }
        public static void GenerateValues2(int howMany, double meanA, double meanB, double meanC, double[,] R)
        {
            var disitrubtion = new NormalDistribution(0, Math.Sqrt(1));
            var mean         = new double[] { disitrubtion.InverseDistributionFunction(meanA), disitrubtion.InverseDistributionFunction(meanB), disitrubtion.InverseDistributionFunction(meanC) };

            var mnormaldist = new MultivariateNormalDistribution(mean, R);
            var samples     = mnormaldist.Generate(howMany);

            var aSamples = new double[howMany];
            var bSamples = new double[howMany];
            var cSamples = new double[howMany];

            for (int i = 0; i < samples.Length; i++)
            {
                aSamples[i] = samples[i][0] > 0 ? 1 : 0;
                bSamples[i] = samples[i][1] > 0 ? 1 : 0;
                cSamples[i] = samples[i][2] > 0 ? 1 : 0;
            }

            var resultCorrAb = CalculateCorrelation(aSamples, bSamples);
            var resultCorrAc = CalculateCorrelation(aSamples, cSamples);
            var resultCorrBc = CalculateCorrelation(bSamples, cSamples);
        }
예제 #18
0
        private void btnGenerateRandom_Click(object sender, EventArgs e)
        {
            k = (int)numClusters.Value;

            // Generate data with n Gaussian distributions
            double[][][] data = new double[k][][];

            for (int i = 0; i < k; i++)
            {
                // Create random centroid to place the Gaussian distribution
                var mean = Matrix.Random(2, -6.0, +6.0);

                // Create random covariance matrix for the distribution
                double[,] covariance;
                do
                {
                    covariance = Matrix.Random(2, true, 0.0, 3.0);
                }while (!covariance.IsPositiveDefinite());


                // Create the Gaussian distribution
                var gaussian = new MultivariateNormalDistribution(mean, covariance);

                int samples = Accord.Math.Tools.Random.Next(150, 250);
                data[i] = gaussian.Generate(samples);
            }

            // Join the generated data
            mixture = Matrix.Stack(data);

            // Update the scatterplot
            CreateScatterplot(graph, mixture, k);

            // Forget previous initialization
            kmeans = null;
        }
        public void sequence_parsing_test()
        {
            #region doc_learn_fraud_analysis

            // Ensure results are reproducible
            Accord.Math.Random.Generator.Seed = 0;

            // Let's say we have the following data about credit card transactions,
            // where the data is organized in order of transaction, per credit card
            // holder. Everytime the "Time" column starts at zero, denotes that the
            // sequence of observations follow will correspond to transactions of the
            // same person:

            double[,] data =
            {
                // "Time", "V1",   "V2",  "V3", "V4", "V5", "Amount",  "Fraud"
                { 0, 0.521, 0.124, 0.622, 15.2, 25.6,  2.70, 0 },              // first person, ok
                { 1, 0.121, 0.124, 0.822, 12.2, 25.6,  42.0, 0 },              // first person, ok

                { 0, 0.551, 0.124, 0.422, 17.5, 25.6,  20.0, 0 },              // second person, ok
                { 1, 0.136, 0.154, 0.322, 15.3, 25.6,  50.0, 0 },              // second person, ok
                { 2, 0.721, 0.240, 0.422, 12.2, 25.6, 100.0, 1 },              // second person, fraud!
                { 3, 0.222, 0.126, 0.722, 18.1, 25.8,  10.0, 0 },              // second person, ok
            };

            // Transform the above data into a jagged matrix
            double[][][] input;
            int[][]      states;
            transform(data, out input, out states);

            // Determine here the number of dimensions in the observations (in this case, 6)
            int observationDimensions = 6; // 6 columns: "V1", "V2", "V3", "V4", "V5", "Amount"

            // Create some prior distributions to help initialize our parameters
            var priorC = new WishartDistribution(dimension: observationDimensions, degreesOfFreedom: 10); // this 10 is just some random number, you might have to tune as if it was a hyperparameter
            var priorM = new MultivariateNormalDistribution(dimension: observationDimensions);

            // Configure the learning algorithms to train the sequence classifier
            var teacher = new MaximumLikelihoodLearning <MultivariateNormalDistribution, double[]>()
            {
                // Their emissions will be multivariate Normal distributions initialized using the prior distributions
                Emissions = (j) => new MultivariateNormalDistribution(mean: priorM.Generate(), covariance: priorC.Generate()),

                // We will prevent our covariance matrices from becoming degenerate by adding a small
                // regularization value to their diagonal until they become positive-definite again:
                FittingOptions = new NormalOptions()
                {
                    Regularization = 1e-6
                },
            };

            // Use the teacher to learn a new HMM
            var hmm = teacher.Learn(input, states);

            // Use the HMM to predict whether the transations were fradulent or not:
            int[] firstPerson = hmm.Decide(input[0]);  // predict the first person, output should be: 0, 0

            int[] secondPerson = hmm.Decide(input[1]); // predict the second person, output should be: 0, 0, 1, 0
            #endregion


            Assert.AreEqual(new[] { 0, 0 }, firstPerson);
            Assert.AreEqual(new[] { 0, 0, 1, 0 }, secondPerson);
        }
예제 #20
0
        /// <summary>
        ///   Generates a random vector of observations from a distribution with the given parameters.
        /// </summary>
        ///
        /// <param name="samples">The number of samples to generate.</param>
        /// <param name="mean">The mean vector μ (mu) for the distribution.</param>
        /// <param name="covariance">The covariance matrix Σ (sigma) for the distribution.</param>
        ///
        /// <returns>A random vector of observations drawn from this distribution.</returns>
        ///
        public static double[][] Generate(int samples, double[] mean, double[,] covariance)
        {
            var normal = new MultivariateNormalDistribution(mean, covariance);

            return(normal.Generate(samples));
        }
        public void learn_pendigits_normalization()
        {
            #region doc_learn_pendigits
            // Ensure we get reproducible results
            Accord.Math.Random.Generator.Seed = 0;

            // Download the PENDIGITS dataset from UCI ML repository
            var pendigits = new Pendigits(path: Path.GetTempPath());

            // Get and pre-process the training set
            double[][][] trainInputs  = pendigits.Training.Item1;
            int[]        trainOutputs = pendigits.Training.Item2;

            // Pre-process the digits so each of them is centered and scaled
            trainInputs = trainInputs.Apply(Accord.Statistics.Tools.ZScores);
            trainInputs = trainInputs.Apply((x) => x.Subtract(x.Min())); // make them positive

            // Create some prior distributions to help initialize our parameters
            var priorC = new WishartDistribution(dimension: 2, degreesOfFreedom: 5);
            var priorM = new MultivariateNormalDistribution(dimension: 2);

            // Create a template Markov classifier that we can use as a base for the HCRF
            var hmmc = new HiddenMarkovClassifier <MultivariateNormalDistribution, double[]>(
                classes: pendigits.NumberOfClasses, topology: new Forward(5),
                initial: (i, j) => new MultivariateNormalDistribution(mean: priorM.Generate(), covariance: priorC.Generate()));

            // Create a new learning algorithm for creating HCRFs
            var teacher = new HiddenQuasiNewtonLearning <double[]>()
            {
                Function = new MarkovMultivariateFunction(hmmc),

                MaxIterations = 10
            };

            // The following line is only needed to ensure reproducible results. Please remove it to enable full parallelization
            teacher.ParallelOptions.MaxDegreeOfParallelism = 1; // (Remove, comment, or change this line to enable full parallelism)

            // Use the learning algorithm to create a classifier
            var hcrf = teacher.Learn(trainInputs, trainOutputs);

            // Compute predictions for the training set
            int[] trainPredicted = hcrf.Decide(trainInputs);

            // Check the performance of the classifier by comparing with the ground-truth:
            var    m1       = new ConfusionMatrix(predicted: trainPredicted, expected: trainOutputs);
            double trainAcc = m1.Accuracy; // should be 0.89594053744997137


            // Prepare the testing set
            double[][][] testInputs  = pendigits.Testing.Item1;
            int[]        testOutputs = pendigits.Testing.Item2;

            // Apply the same normalizations
            testInputs = testInputs.Apply(Accord.Statistics.Tools.ZScores);
            testInputs = testInputs.Apply((x) => x.Subtract(x.Min())); // make them positive

            // Compute predictions for the test set
            int[] testPredicted = hcrf.Decide(testInputs);

            // Check the performance of the classifier by comparing with the ground-truth:
            var    m2      = new ConfusionMatrix(predicted: testPredicted, expected: testOutputs);
            double testAcc = m2.Accuracy; // should be 0.89594053744997137
            #endregion

            Assert.AreEqual(0.89594053744997137, trainAcc, 1e-10);
            Assert.AreEqual(0.896050173472111, testAcc, 1e-10);
        }
        public void learn_pendigits_normalization()
        {
            Console.WriteLine("Starting NormalQuasiNewtonHiddenLearningTest.learn_pendigits_normalization");

            using (var travis = new KeepTravisAlive())
            {
                #region doc_learn_pendigits
                // Ensure we get reproducible results
                Accord.Math.Random.Generator.Seed = 0;

                // Download the PENDIGITS dataset from UCI ML repository
                var pendigits = new Pendigits(path: Path.GetTempPath());

                // Get and pre-process the training set
                double[][][] trainInputs  = pendigits.Training.Item1;
                int[]        trainOutputs = pendigits.Training.Item2;

                // Pre-process the digits so each of them is centered and scaled
                trainInputs = trainInputs.Apply(Accord.Statistics.Tools.ZScores);
                trainInputs = trainInputs.Apply((x) => x.Subtract(x.Min())); // make them positive

                // Create some prior distributions to help initialize our parameters
                var priorC = new WishartDistribution(dimension: 2, degreesOfFreedom: 5);
                var priorM = new MultivariateNormalDistribution(dimension: 2);

                // Create a new learning algorithm for creating continuous hidden Markov model classifiers
                var teacher1 = new HiddenMarkovClassifierLearning <MultivariateNormalDistribution, double[]>()
                {
                    // This tells the generative algorithm how to train each of the component models. Note: The learning
                    // algorithm is more efficient if all generic parameters are specified, including the fitting options
                    Learner = (i) => new BaumWelchLearning <MultivariateNormalDistribution, double[], NormalOptions>()
                    {
                        Topology = new Forward(5), // Each model will have a forward topology with 5 states

                        // Their emissions will be multivariate Normal distributions initialized using the prior distributions
                        Emissions = (j) => new MultivariateNormalDistribution(mean: priorM.Generate(), covariance: priorC.Generate()),

                        // We will train until the relative change in the average log-likelihood is less than 1e-6 between iterations
                        Tolerance     = 1e-6,
                        MaxIterations = 1000, // or until we perform 1000 iterations (which is unlikely for this dataset)

                        // We will prevent our covariance matrices from becoming degenerate by adding a small
                        // regularization value to their diagonal until they become positive-definite again:
                        FittingOptions = new NormalOptions()
                        {
                            Regularization = 1e-6
                        }
                    }
                };

                // The following line is only needed to ensure reproducible results. Please remove it to enable full parallelization
                teacher1.ParallelOptions.MaxDegreeOfParallelism = 1; // (Remove, comment, or change this line to enable full parallelism)

                // Use the learning algorithm to create a classifier
                var hmmc = teacher1.Learn(trainInputs, trainOutputs);


                // Create a new learning algorithm for creating HCRFs
                var teacher2 = new HiddenQuasiNewtonLearning <double[]>()
                {
                    Function = new MarkovMultivariateFunction(hmmc),

                    MaxIterations = 10
                };

                // The following line is only needed to ensure reproducible results. Please remove it to enable full parallelization
                teacher2.ParallelOptions.MaxDegreeOfParallelism = 1; // (Remove, comment, or change this line to enable full parallelism)

                // Use the learning algorithm to create a classifier
                var hcrf = teacher2.Learn(trainInputs, trainOutputs);

                // Compute predictions for the training set
                int[] trainPredicted = hcrf.Decide(trainInputs);

                // Check the performance of the classifier by comparing with the ground-truth:
                var    m1       = new GeneralConfusionMatrix(predicted: trainPredicted, expected: trainOutputs);
                double trainAcc = m1.Accuracy; // should be 0.66523727844482561


                // Prepare the testing set
                double[][][] testInputs  = pendigits.Testing.Item1;
                int[]        testOutputs = pendigits.Testing.Item2;

                // Apply the same normalizations
                testInputs = testInputs.Apply(Accord.Statistics.Tools.ZScores);
                testInputs = testInputs.Apply((x) => x.Subtract(x.Min())); // make them positive

                // Compute predictions for the test set
                int[] testPredicted = hcrf.Decide(testInputs);

                // Check the performance of the classifier by comparing with the ground-truth:
                var    m2      = new GeneralConfusionMatrix(predicted: testPredicted, expected: testOutputs);
                double testAcc = m2.Accuracy; // should be 0.66506538564184681
                #endregion

                Assert.AreEqual(0.66523727844482561, trainAcc, 1e-10);
                Assert.AreEqual(0.66506538564184681, testAcc, 1e-10);
            }
        }