You are viewing an archived page from the original site. Go to the new numericalmethod.com →

source: public/Examples/src/main/java/com/numericalmethod/suanshu/examples/MarkovModel.java @ 194

Revision 55, 9.3 KB checked in by kenyiu, 8 months ago (diff)

CHG: Made examples as a project by adding a maven POM.

Line 
1/*
2 * Copyright (c) Numerical Method Inc.
3 * http://www.numericalmethod.com/
4 *
5 * THIS SOFTWARE IS LICENSED, NOT SOLD.
6 *
7 * YOU MAY USE THIS SOFTWARE ONLY AS DESCRIBED IN THE LICENSE.
8 * IF YOU ARE NOT AWARE OF AND/OR DO NOT AGREE TO THE TERMS OF THE LICENSE,
9 * DO NOT USE THIS SOFTWARE.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS", WITH NO WARRANTY WHATSOEVER,
12 * EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
13 * ANY WARRANTIES OF ACCURACY, ACCESSIBILITY, COMPLETENESS,
14 * FITNESS FOR A0 PARTICULAR PURPOSE, MERCHANTABILITY, NON-INFRINGEMENT,
15 * TITLE AND USEFULNESS.
16 *
17 * IN NO EVENT AND UNDER NO LEGAL THEORY,
18 * WHETHER IN ACTION, CONTRACT, NEGLIGENCE, TORT, OR OTHERWISE,
19 * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
20 * ANY CLAIMS, DAMAGES OR OTHER LIABILITIES,
21 * ARISING AS A0 RESULT OF USING OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23package com.numericalmethod.suanshu.examples;
24
25import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.Matrix;
26import com.numericalmethod.suanshu.algebra.linear.matrix.doubles.matrixtype.dense.DenseMatrix;
27import com.numericalmethod.suanshu.algebra.linear.vector.doubles.Vector;
28import com.numericalmethod.suanshu.algebra.linear.vector.doubles.dense.DenseVector;
29import com.numericalmethod.suanshu.stats.hmm.HmmInnovation;
30import com.numericalmethod.suanshu.stats.hmm.mixture.MixtureBaumWelch;
31import com.numericalmethod.suanshu.stats.hmm.mixture.distribution.MixtureLogNormalDistribution;
32import com.numericalmethod.suanshu.stats.hmm.rabiner.RabinerHiddenMarkovModel;
33import com.numericalmethod.suanshu.stats.hmm.rabiner.RabinerTrainByEM;
34import com.numericalmethod.suanshu.stats.markovchain.SimpleMC;
35
36/**
37 * Demonstrates how to construct and train a hidden Markov model in Java using SuanShu.
38 *
39 * @author Haksun Li
40 */
41public final class MarkovModel {
42
43    /**
44     * An example transition matrix with three states.
45     */
46    public static final Matrix A0 = new DenseMatrix(
47            new double[][]{
48                {1. / 2., 1. / 2., 0.},
49                {1. / 3., 1. / 3., 1. / 3.},
50                {0., 1. / 2., 1. / 2.}
51            });
52    /**
53     * An example vector of initial probabilities.
54     */
55    public static final Vector PI = new DenseVector(new double[]{0.2, 0.8});
56    /**
57     * An example transition matrix with two states.
58     */
59    public static final Matrix A1 = new DenseMatrix(new double[][]{
60                {0.8, 0.2},
61                {0.3, 0.7}
62            });
63    /**
64     * An example matrix of probability of observing symbols (column) given states(row).
65     */
66    public static final Matrix B1 = new DenseMatrix(new double[][]{
67                {0.8, 0.1, 0.1},
68                {0.1, 0.1, 0.8}
69            });
70
71    private MarkovModel() {
72    }
73
74    public static void main(String[] args) {
75        System.out.println("This class demonstrates how to construct and train a hidden Markov "
76                           + "model in Java using SuanShu.");
77        System.out.printf("Stationary probabilities: %s%n", getStationaryProbabilities(A0));
78
79        rabinerHMM();
80        mixedHMM();
81    }
82
83    /**
84     * Returns the stationary probabilities of the states, given a transition matrix.
85     *
86     * @param A the transition matrix from which to compute the stationary probabilities
87     * @return the stationary probabilities of the states in the transition matrix
88     */
89    public static Vector getStationaryProbabilities(Matrix A) {
90        return SimpleMC.getStationaryProbabilities(A);
91    }
92
93    /**
94     * Creates a Hidden Markov Model as defined by Rabiner, generates observations from it. We then
95     * attempt to train a HMM to match those observations and print the results.
96     */
97    public static void rabinerHMM() {
98        com.numericalmethod.suanshu.stats.hmm.rabiner.RabinerHiddenMarkovModel model =
99                new com.numericalmethod.suanshu.stats.hmm.rabiner.RabinerHiddenMarkovModel(PI, A1, B1);
100
101        int[] observations = simulateHMM(10000, model);
102
103        Vector GUESSED_PI = new DenseVector(
104                new double[]{0.5, 0.5});
105        Matrix GUESSED_A = new DenseMatrix(
106                new double[][]{
107                    {0.5, 0.5},
108                    {0.5, 0.5}
109                });
110        Matrix GUESSED_B = new DenseMatrix(
111                new double[][]{
112                    {0.40, 0.30, 0.30},
113                    {0.30, 0.30, 0.40}
114                });
115
116        RabinerHiddenMarkovModel guessedModel = new RabinerHiddenMarkovModel(GUESSED_PI, GUESSED_A, GUESSED_B);
117        RabinerHiddenMarkovModel trainedModel = trainHMM(100, observations, guessedModel);
118        System.out.printf("A: %s, %nB: %s%n", trainedModel.A(), trainedModel.B());
119    }
120
121    /**
122     * Generates the given number of observations from the given HMM model.
123     *
124     * @param n     the number of observations to generate
125     * @param model the HMM model from which to generate the observations
126     * @return the observations generated by the simulation
127     */
128    public static int[] simulateHMM(int n, RabinerHiddenMarkovModel model) {
129        // simulation
130        int[] observations = new int[n];
131        for (int i = 0; i < n; ++i) {
132            HmmInnovation innovation = model.next();
133            observations[i] = (int) innovation.getObservation();
134        }
135        return observations;
136    }
137
138    /**
139     * Trains a HMM using the given observations, starting from the given guessed model.
140     *
141     * @param n            the number of iterations used by the training algorithm
142     * @param observations the observations from which to train the HMMM
143     * @param guessed      the guessed model
144     * @return the trained HMM model
145     */
146    public static RabinerTrainByEM trainHMM(int n, int[] observations, RabinerHiddenMarkovModel guessed) {
147        return new RabinerTrainByEM(observations, guessed, n);
148    }
149
150    /**
151     * Creates a mixture HMM, which features observations drawn from a continuous distribution and
152     * generates observations. We then attempt to train a HMM to match those observations and print
153     * the results.
154     */
155    public static void mixedHMM() {
156        // Create the model
157        Vector PI0 = new DenseVector(new double[]{0., 1., 0.});
158        MixtureLogNormalDistribution.Lambda[] lambda0 = new MixtureLogNormalDistribution.Lambda[]{
159            new MixtureLogNormalDistribution.Lambda(1., .5),// (mu, sigma)
160            new MixtureLogNormalDistribution.Lambda(10., 1.),
161            new MixtureLogNormalDistribution.Lambda(3., .5)
162        };
163        com.numericalmethod.suanshu.stats.hmm.mixture.MixtureHiddenMarkovModel model =
164                new com.numericalmethod.suanshu.stats.hmm.mixture.MixtureHiddenMarkovModel(
165                PI0, A0, new MixtureLogNormalDistribution(lambda0));
166
167        // Simulate observations
168        double[] observations = simulateContinuousHMM(10000, model);
169
170        // Create our initial guess
171        Vector PI1 = new DenseVector(new double[]{1. / 3., 1. / 3., 1. / 3.});
172        Matrix A1 = new DenseMatrix(new double[][]{
173                    {1. / 3., 1. / 3., 1. / 3.},
174                    {1. / 3., 1. / 3., 1. / 3.},
175                    {1. / 3., 1. / 3., 1. / 3.},});
176        MixtureLogNormalDistribution.Lambda[] lambda1 = new MixtureLogNormalDistribution.Lambda[]{
177            new MixtureLogNormalDistribution.Lambda(1., 1.),// (mu, sigma)
178            new MixtureLogNormalDistribution.Lambda(3., 1.),
179            new MixtureLogNormalDistribution.Lambda(2., 1.)
180        };
181        com.numericalmethod.suanshu.stats.hmm.mixture.MixtureHiddenMarkovModel guessedModel =
182                new com.numericalmethod.suanshu.stats.hmm.mixture.MixtureHiddenMarkovModel(
183                PI1, A1, new MixtureLogNormalDistribution(lambda1));
184
185        // Create the trained HMM model
186        com.numericalmethod.suanshu.stats.hmm.HiddenMarkovModel hmm =
187                trainContinuousHMM(200, 1E-5, observations, guessedModel);
188        System.out.printf("A: %s%n", hmm.A());
189    }
190
191    /**
192     * Generates the given number of observations for the given HMM model with continuous
193     * observations from a log-normal distribution.
194     *
195     * @param n     the number of observations to generate
196     * @param model the model from which to generate the observations
197     * @return the generated observations
198     */
199    public static double[] simulateContinuousHMM(
200            int n, com.numericalmethod.suanshu.stats.hmm.mixture.MixtureHiddenMarkovModel model) {
201
202        double[] observations = new double[n];
203        for (int t = 0; t < n; ++t) {
204            observations[t] = model.next().getObservation();
205        }
206        return observations;
207    }
208
209    /**
210     * Trains a HMM using the given observations, starting from the given guessed model.
211     *
212     * @param n            the maximum number of iterations used by the training algorithm
213     * @param epsilon      the desired precision
214     * @param observations the observations with which to train the HMM
215     * @param guessed      the guessed model
216     * @return the trained HMM model
217     */
218    public static com.numericalmethod.suanshu.stats.hmm.HiddenMarkovModel trainContinuousHMM(
219            int n, double epsilon, double[] observations,
220            com.numericalmethod.suanshu.stats.hmm.mixture.MixtureHiddenMarkovModel guessed) {
221
222        MixtureBaumWelch trainedModel = new MixtureBaumWelch(observations, guessed, epsilon, n);
223        return trainedModel;
224    }
225}
Note: See TracBrowser for help on using the repository browser.