直接上干货哈,其他子算法,后续补上。
1 package jxutcm.edu.cn.hmm.model;
2
3 import jxutcm.edu.cn.hmm.bean.HMMHelper;
4 import jxutcm.edu.cn.util.TCMMath;
5
6 /**
7 * 【改进后的前向算法】
8 * 【带比例因子修正的前向算法 :计算观察序列的概率 】
9 * 【注意】 改进后,就没必要使用后向算法来求观测序列概率了,直接利用中间比例因子scale就可以求得,在改进的前向算法中以写logProb()函数
10 *
11 * 前向算法:
12 * 目的:
13 * 1、先计算前向变量矩阵
14 * 2、再用前向变量矩阵 来 计算一个观测序列的概率
15 * @author haozl
16 */
17 public class ForwardWithScale extends HMM{
18 public int[] O;//观测序列observe//如yellow red blue yellow green 这些在enum Color {red,yellow,blue,green }的索引位置
19
20 public double[][] alpha; //前向变量矩阵
21
22 public double[] scale;//用于修正的比例因子——从带比例因子修正后的前向算法计算
23
24 /**
25 * flag 表示 A和B是否是自然对数化(lnX) true: A和B自然对数化后传进来 false: A和B未自然对数化
26 */
27 public ForwardWithScale(double[][] A, double[][] B, double[] PI, int[] O, boolean flag){
28 super(A, B, PI, flag);
29 this.O=O;
30 }
31
32 public ForwardWithScale(HMM hmm, int[] O){
33 super(hmm);
34 this.O=O;
35 }
36
37 /**
38 * 【计算前向变量矩阵】
39 * 在时间 t 的条件下,hmm输出观察序列O(1)O(2)...O(t)且该时间t下的隐藏状态为s_i(第i个隐藏状态,共N种隐藏状态)的概率
40 * alpha[ t ][ i ] = alpha_t( i ) = log(P(O(1)O(2)...O(t), q_t=s_i | λ))
41 */
42 public void CalculateForeMatrix(){
43 int T = O.length;
44 alpha = new double[ T ][ N ];//每一时刻(每行)上 可能出现的多个状态的发生的前向变量概率
45 scale = new double[ T ];//【比例因子】
46 scale[ 0 ] =Double.NEGATIVE_INFINITY;
47 //1、初始化,计算初始时刻(直觉上的第1时刻)所有状态的局部概率
48 for (int i = 0; i < N ; i++){
49 alpha[ 0 ][ i ] = logPI[ i ] + logB[ i ][ O[ 0 ] ];
50 /*******************增加部分*****************/
51 scale[ 0 ] = TCMMath.logplus( scale[ 0 ] , alpha[ 0 ][ i ]);
52 }
53 /*******************增加部分*****************/
54 for(int i=0; i< N; i++){//利用比例因子归一化
55 alpha[ 0 ][ i ] -= scale [ 0 ];
56 }
57
58 //2、归纳,递归计算每个时间点的局部概率
59 for (int t = 1; t < T; t++){//从(直觉上的第2时刻)即t=1(下标从0开始)观测值算起——第时间t下开始循环
60 scale[ t ] = Double.NEGATIVE_INFINITY;
61 for (int j = 0; j < N; j++) {//
62 double sum = Double.NEGATIVE_INFINITY; // = log(0)
63 for (int i = 0; i < N; i++){//到第 i 种隐状态下的累计概率
64 //sum+=alpha[ t-1 ][ i ] * A[ i ] [ j ]
65 sum = TCMMath.logplus( sum, alpha[t - 1][ i ] + logA[ i ][ j ]);
66 }
67 //alpha[ t ][ j ] = 【t-1时刻 所有 隐藏状态 i 】到达 【t时刻 隐藏状态 j】并【t时刻显示出O( t )】的前向变量概率
68 //alpha[ t ] [ j ] = ∑ ( alpha[ t-1 ][ i ] * A[ i ] [ j ] ) *B[ j ] [ O(t) ] 求和符号表示 1<=i <=N
69 alpha[ t ][ j ] = logB[ j ][ O[ t ] ] + sum;//在 【t 时刻】 下 输出观察序列 O1O2……Ot(已知观测序列的局部) 且位于第 j 种隐藏状态发生的概率
70 /*******************增加部分*****************/
71 scale[ t ] = TCMMath.logplus( scale[ t ] , alpha[ t ][ j ]);//比例因子
72 }
73 /*******************增加部分*****************/
74 for (int j = 0; j < N; j++) {//利用比例因子归一化
75 alpha[ t ][ j ] -= scale [ t ];
76 }
77 }
78 }
79
80 /**
81 * 【计算观测序列的概率】——返回的是自然对数
82 */
83 public double logProb() {
84 //3、终止,求概率就直接使用比例因子求得
85 int T = O.length;
86 double sum = 0; // = log(1)
87 for(int t=0; t< T; t++){
88 sum += scale[ t ];
89 }
90 return sum;
91 }
92
93 /**
94 * 【计算观测序列的概率】——前提是先计算前向变量矩阵
95 * P( O | μ ) = ∑alpha_T( i ) (求和上界N,求和下界i=1)
96 * @return 返回的结果是概率的自然对数
97 * 计算 t=T 时刻下输出观察序列 O0……OT(已经观测序列的局部)且位于第 T 状态下发生的概率
98 public double logProb() {
99 //3.终止,观察序列的概率等于最终时刻( T )所有局部概率之和
100 double sum = Double.NEGATIVE_INFINITY; // = log(0)
101 int T = O.length;
102 for (int i = 0; i < N; i++){
103 sum = TCMMath.logplus(sum, alpha[ T-1 ][ i ]);//下标从0开始
104 }
105 return sum;
106 }
107 */
108
109 /**
110 * 打印前向变量矩阵
111 */
112 public void print() {
113 for (int j = 0; j < N; j++) {
114 for (int i = 0; i < alpha.length; i++){
115 System.out.print(HMMHelper.fmtlog(alpha[ i ][ j ]));
116 }
117 System.out.println();
118 }
119 }
120 }