import numpy as np
class HiddenMarkovModel:
def __init__(self, states, observations, start_prob, trans_prob, emit_prob):
self.states = states
self.observations = observations
self.start_prob = start_prob
self.trans_prob = trans_prob
self.emit_prob = emit_prob
def viterbi(self, obs_seq):
n_states = len(self.states)
T = len(obs_seq)
dp = np.zeros((n_states, T))
path = np.zeros((n_states, T), dtype=int)
for s in range(n_states):
dp[s, 0] = self.start_prob[s] * self.emit_prob[s][self.observations.index(obs_seq[0])]
path[s, 0] = 0
for t in range(1, T):
for s in range(n_states):
prob_transition = dp[:, t-1] * self.trans_prob[:, s]
best_prev_state = prob_transition.argmax()
dp[s, t] = prob_transition[best_prev_state] * self.emit_prob[s][self.observations.index(obs_seq[t])]
path[s, t] = best_prev_state
best_last_state = dp[:, T-1].argmax()
best_path = [best_last_state]
for t in range(T-1, 0, -1):
best_last_state = path[best_last_state, t]
best_path.insert(0, best_last_state)
best_state_sequence = [self.states[state] for state in best_path]
return best_state_sequence
if __name__ == "__main__":
states = ['S1', 'S2']
observations = ['obs1', 'obs2', 'obs3']
start_prob = np.array([0.6, 0.4])
trans_prob = np.array([[0.7, 0.3],
[0.4, 0.6]])
emit_prob = np.array([[0.5, 0.4, 0.1],
[0.1, 0.3, 0.6]])
obs_seq = ['obs3', 'obs1', 'obs3']
hmm = HiddenMarkovModel(states, observations, start_prob, trans_prob, emit_prob)
best_sequence = hmm.viterbi(obs_seq)
print("Most likely state sequence:", best_sequence)
# your code goes here
aW1wb3J0IG51bXB5IGFzIG5wCgpjbGFzcyBIaWRkZW5NYXJrb3ZNb2RlbDoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBzdGF0ZXMsIG9ic2VydmF0aW9ucywgc3RhcnRfcHJvYiwgdHJhbnNfcHJvYiwgZW1pdF9wcm9iKToKICAgICAgICBzZWxmLnN0YXRlcyA9IHN0YXRlcwogICAgICAgIHNlbGYub2JzZXJ2YXRpb25zID0gb2JzZXJ2YXRpb25zCiAgICAgICAgc2VsZi5zdGFydF9wcm9iID0gc3RhcnRfcHJvYgogICAgICAgIHNlbGYudHJhbnNfcHJvYiA9IHRyYW5zX3Byb2IKICAgICAgICBzZWxmLmVtaXRfcHJvYiA9IGVtaXRfcHJvYgoKICAgIGRlZiB2aXRlcmJpKHNlbGYsIG9ic19zZXEpOgogICAgICAgIG5fc3RhdGVzID0gbGVuKHNlbGYuc3RhdGVzKQogICAgICAgIFQgPSBsZW4ob2JzX3NlcSkKCiAgICAgICAgZHAgPSBucC56ZXJvcygobl9zdGF0ZXMsIFQpKQogICAgICAgIHBhdGggPSBucC56ZXJvcygobl9zdGF0ZXMsIFQpLCBkdHlwZT1pbnQpCgogICAgICAgIGZvciBzIGluIHJhbmdlKG5fc3RhdGVzKToKICAgICAgICAgICAgZHBbcywgMF0gPSBzZWxmLnN0YXJ0X3Byb2Jbc10gKiBzZWxmLmVtaXRfcHJvYltzXVtzZWxmLm9ic2VydmF0aW9ucy5pbmRleChvYnNfc2VxWzBdKV0KICAgICAgICAgICAgcGF0aFtzLCAwXSA9IDAKCiAgICAgICAgZm9yIHQgaW4gcmFuZ2UoMSwgVCk6CiAgICAgICAgICAgIGZvciBzIGluIHJhbmdlKG5fc3RhdGVzKToKICAgICAgICAgICAgICAgIHByb2JfdHJhbnNpdGlvbiA9IGRwWzosIHQtMV0gKiBzZWxmLnRyYW5zX3Byb2JbOiwgc10KICAgICAgICAgICAgICAgIGJlc3RfcHJldl9zdGF0ZSA9IHByb2JfdHJhbnNpdGlvbi5hcmdtYXgoKQogICAgICAgICAgICAgICAgZHBbcywgdF0gPSBwcm9iX3RyYW5zaXRpb25bYmVzdF9wcmV2X3N0YXRlXSAqIHNlbGYuZW1pdF9wcm9iW3NdW3NlbGYub2JzZXJ2YXRpb25zLmluZGV4KG9ic19zZXFbdF0pXQogICAgICAgICAgICAgICAgcGF0aFtzLCB0XSA9IGJlc3RfcHJldl9zdGF0ZQoKICAgICAgICBiZXN0X2xhc3Rfc3RhdGUgPSBkcFs6LCBULTFdLmFyZ21heCgpCiAgICAgICAgYmVzdF9wYXRoID0gW2Jlc3RfbGFzdF9zdGF0ZV0KCiAgICAgICAgZm9yIHQgaW4gcmFuZ2UoVC0xLCAwLCAtMSk6CiAgICAgICAgICAgIGJlc3RfbGFzdF9zdGF0ZSA9IHBhdGhbYmVzdF9sYXN0X3N0YXRlLCB0XQogICAgICAgICAgICBiZXN0X3BhdGguaW5zZXJ0KDAsIGJlc3RfbGFzdF9zdGF0ZSkKCiAgICAgICAgYmVzdF9zdGF0ZV9zZXF1ZW5jZSA9IFtzZWxmLnN0YXRlc1tzdGF0ZV0gZm9yIHN0YXRlIGluIGJlc3RfcGF0aF0KICAgICAgICByZXR1cm4gYmVzdF9zdGF0ZV9zZXF1ZW5jZQoKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICBzdGF0ZXMgPSBbJ1MxJywgJ1MyJ10KICAgIG9ic2VydmF0aW9ucyA9IFsnb2JzMScsICdvYnMyJywgJ29iczMnXQoKICAgIHN0YXJ0X3Byb2IgPSBucC5hcnJheShbMC42LCAwLjRdKQogICAgdHJhbnNfcHJvYiA9IG5wLmFycmF5KFtbMC43LCAwLjNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICBbMC40LCAwLjZdXSkKICAgIGVtaXRfcHJvYiA9IG5wLmFycmF5KFtbMC41LCAwLjQsIDAuMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgWzAuMSwgMC4zLCAwLjZdXSkKCiAgICBvYnNfc2VxID0gWydvYnMzJywgJ29iczEnLCAnb2JzMyddCgogICAgaG1tID0gSGlkZGVuTWFya292TW9kZWwoc3RhdGVzLCBvYnNlcnZhdGlvbnMsIHN0YXJ0X3Byb2IsIHRyYW5zX3Byb2IsIGVtaXRfcHJvYikKICAgIGJlc3Rfc2VxdWVuY2UgPSBobW0udml0ZXJiaShvYnNfc2VxKQoKICAgIHByaW50KCJNb3N0IGxpa2VseSBzdGF0ZSBzZXF1ZW5jZToiLCBiZXN0X3NlcXVlbmNlKQoKIyB5b3VyIGNvZGUgZ29lcyBoZXJl