/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.mahout.classifier.sequencelearning.hmm; import org.apache.mahout.math.Matrix; import org.junit.Test; public class HMMAlgorithmsTest extends HMMTestBase { /** * Test the forward algorithm by comparing the alpha values with the values * obtained from HMM R model. We test the test observation sequence "O1" "O0" * "O2" "O2" "O0" "O0" "O1" by comparing the generated alpha values to the * R-generated "reference". */ @Test public void testForwardAlgorithm() { // intialize the expected alpha values double[][] alphaExpectedA = { {0.02, 0.0392, 0.002438, 0.00035456, 0.0011554672, 7.158497e-04, 4.614927e-05}, {0.01, 0.0054, 0.001824, 0.00069486, 0.0007586904, 2.514137e-04, 1.721505e-05}, {0.32, 0.0262, 0.002542, 0.00038026, 0.0001360234, 3.002345e-05, 9.659608e-05}, {0.03, 0.0000, 0.013428, 0.00951084, 0.0000000000, 0.000000e+00, 2.428986e-05},}; // fetch the alpha matrix using the forward algorithm Matrix alpha = HmmAlgorithms.forwardAlgorithm(getModel(), getSequence(), false); // first do some basic checking assertNotNull(alpha); assertEquals(4, alpha.numCols()); assertEquals(7, alpha.numRows()); // now compare the resulting matrices for (int i = 0; i < 4; ++i) { for (int j = 0; j < 7; ++j) { assertEquals(alphaExpectedA[i][j], alpha.get(j, i), EPSILON); } } } @Test public void testLogScaledForwardAlgorithm() { // intialize the expected alpha values double[][] alphaExpectedA = { {0.02, 0.0392, 0.002438, 0.00035456, 0.0011554672, 7.158497e-04, 4.614927e-05}, {0.01, 0.0054, 0.001824, 0.00069486, 0.0007586904, 2.514137e-04, 1.721505e-05}, {0.32, 0.0262, 0.002542, 0.00038026, 0.0001360234, 3.002345e-05, 9.659608e-05}, {0.03, 0.0000, 0.013428, 0.00951084, 0.0000000000, 0.000000e+00, 2.428986e-05},}; // fetch the alpha matrix using the forward algorithm Matrix alpha = HmmAlgorithms.forwardAlgorithm(getModel(), getSequence(), true); // first do some basic checking assertNotNull(alpha); assertEquals(4, alpha.numCols()); assertEquals(7, alpha.numRows()); // now compare the resulting matrices for (int i = 0; i < 4; ++i) { for (int j = 0; j < 7; ++j) { assertEquals(Math.log(alphaExpectedA[i][j]), alpha.get(j, i), EPSILON); } } } /** * Test the backward algorithm by comparing the beta values with the values * obtained from HMM R model. We test the following observation sequence "O1" * "O0" "O2" "O2" "O0" "O0" "O1" by comparing the generated beta values to the * R-generated "reference". */ @Test public void testBackwardAlgorithm() { // intialize the expected beta values double[][] betaExpectedA = { {0.0015730559, 0.003543656, 0.00738264, 0.040692, 0.0848, 0.17, 1}, {0.0017191865, 0.002386795, 0.00923652, 0.052232, 0.1018, 0.17, 1}, {0.0003825772, 0.001238558, 0.00259464, 0.012096, 0.0664, 0.66, 1}, {0.0004390858, 0.007076994, 0.01063512, 0.013556, 0.0304, 0.17, 1}}; // fetch the beta matrix using the backward algorithm Matrix beta = HmmAlgorithms.backwardAlgorithm(getModel(), getSequence(), false); // first do some basic checking assertNotNull(beta); assertEquals(4, beta.numCols()); assertEquals(7, beta.numRows()); // now compare the resulting matrices for (int i = 0; i < 4; ++i) { for (int j = 0; j < 7; ++j) { assertEquals(betaExpectedA[i][j], beta.get(j, i), EPSILON); } } } @Test public void testLogScaledBackwardAlgorithm() { // intialize the expected beta values double[][] betaExpectedA = { {0.0015730559, 0.003543656, 0.00738264, 0.040692, 0.0848, 0.17, 1}, {0.0017191865, 0.002386795, 0.00923652, 0.052232, 0.1018, 0.17, 1}, {0.0003825772, 0.001238558, 0.00259464, 0.012096, 0.0664, 0.66, 1}, {0.0004390858, 0.007076994, 0.01063512, 0.013556, 0.0304, 0.17, 1}}; // fetch the beta matrix using the backward algorithm Matrix beta = HmmAlgorithms.backwardAlgorithm(getModel(), getSequence(), true); // first do some basic checking assertNotNull(beta); assertEquals(4, beta.numCols()); assertEquals(7, beta.numRows()); // now compare the resulting matrices for (int i = 0; i < 4; ++i) { for (int j = 0; j < 7; ++j) { assertEquals(Math.log(betaExpectedA[i][j]), beta.get(j, i), EPSILON); } } } @Test public void testViterbiAlgorithm() { // initialize the expected hidden sequence int[] expected = {2, 0, 3, 3, 0, 0, 2}; // fetch the viterbi generated sequence int[] computed = HmmAlgorithms.viterbiAlgorithm(getModel(), getSequence(), false); // first make sure we return the correct size assertNotNull(computed); assertEquals(computed.length, getSequence().length); // now check the contents for (int i = 0; i < getSequence().length; ++i) { assertEquals(expected[i], computed[i]); } } @Test public void testLogScaledViterbiAlgorithm() { // initialize the expected hidden sequence int[] expected = {2, 0, 3, 3, 0, 0, 2}; // fetch the viterbi generated sequence int[] computed = HmmAlgorithms.viterbiAlgorithm(getModel(), getSequence(), true); // first make sure we return the correct size assertNotNull(computed); assertEquals(computed.length, getSequence().length); // now check the contents for (int i = 0; i < getSequence().length; ++i) { assertEquals(expected[i], computed[i]); } } }