"""
Forward(HMM, O)
A = [
[] (indexed on the ending state)
] (indexed on the starting state)
A[start][end] -> transition from start to end
B = [
[] (indexed on observation)
] (indexed on hidden state state)
B[state][observation] -> probability of state emitting observation
pi -> initial probabilities
"""
def forward(A, B, PI, O):
a = [[0] * len(A) for _ in range(len(O))]
for i in range(len(A)):
a[0][i] = PI[i] * B[i][O[0]]
for t in range(1, len(O)):
for j in range(len(A)):
a[t][j] = 0
for i in range(len(A)):
a[t][j] = a[t][j] + a[t-1][i] * A[i][j]
a[t][j] = a[t][j] * B[j][O[t]]
p = 0
for i in range(len(A)):
p += a[len(O)-1][i]
return p
A = [
[0.5, 0.5],
[0.4, 0.6]
]
B = [
[0.5, 0.4, 0.1],
[0.2, 0.4, 0.4]
]
PI = [0.2, 0.8]
O = [2, 0, 2]
print(forward(A, B, PI, O))
IiIiCkZvcndhcmQoSE1NLCBPKQoKQSA9IFsKW10gKGluZGV4ZWQgb24gdGhlIGVuZGluZyBzdGF0ZSkKXSAoaW5kZXhlZCBvbiB0aGUgc3RhcnRpbmcgc3RhdGUpCgpBW3N0YXJ0XVtlbmRdIC0+IHRyYW5zaXRpb24gZnJvbSBzdGFydCB0byBlbmQKCkIgPSBbCltdIChpbmRleGVkIG9uIG9ic2VydmF0aW9uKQpdIChpbmRleGVkIG9uIGhpZGRlbiBzdGF0ZSBzdGF0ZSkKCkJbc3RhdGVdW29ic2VydmF0aW9uXSAtPiBwcm9iYWJpbGl0eSBvZiBzdGF0ZSBlbWl0dGluZyBvYnNlcnZhdGlvbgoKcGkgLT4gaW5pdGlhbCBwcm9iYWJpbGl0aWVzCiIiIgoKZGVmIGZvcndhcmQoQSwgQiwgUEksIE8pOgogICAgYSA9IFtbMF0gKiBsZW4oQSkgZm9yIF8gaW4gcmFuZ2UobGVuKE8pKV0KCiAgICBmb3IgaSBpbiByYW5nZShsZW4oQSkpOgogICAgICAgIGFbMF1baV0gPSBQSVtpXSAqIEJbaV1bT1swXV0KICAgIAogICAgZm9yIHQgaW4gcmFuZ2UoMSwgbGVuKE8pKToKICAgICAgICBmb3IgaiBpbiByYW5nZShsZW4oQSkpOgogICAgICAgICAgICBhW3RdW2pdID0gMAoKICAgICAgICAgICAgZm9yIGkgaW4gcmFuZ2UobGVuKEEpKToKICAgICAgICAgICAgICAgIGFbdF1bal0gPSBhW3RdW2pdICsgYVt0LTFdW2ldICogQVtpXVtqXQogICAgICAgICAgICAKICAgICAgICAgICAgYVt0XVtqXSA9IGFbdF1bal0gKiBCW2pdW09bdF1dCiAgICAKICAgIHAgPSAwCiAgICBmb3IgaSBpbiByYW5nZShsZW4oQSkpOgogICAgICAgIHAgKz0gYVtsZW4oTyktMV1baV0KICAgIAogICAgcmV0dXJuIHAKCgpBID0gWwogICAgWzAuNSwgMC41XSwKICAgIFswLjQsIDAuNl0KXQpCID0gWwogICAgWzAuNSwgMC40LCAwLjFdLAogICAgWzAuMiwgMC40LCAwLjRdCl0KUEkgPSBbMC4yLCAwLjhdCgpPID0gWzIsIDAsIDJdCgpwcmludChmb3J3YXJkKEEsIEIsIFBJLCBPKSk=