import numpy as np

#to do with real data; I would have to 
#1. import the observation sequence where each obs represents a tract with a vector = price frequency distribution
#2. calculate emission probabilities for each tract (run rand.py for the size of tract dataset)

obs = ('G100200P', 'G250400P', 'G450600P', 'G650800P', 'G9002000P')

states = ('Residential', 'Commercial', 'Manufacturing')
 
initprob = {'Residential': 0.3, 'Commercial': 0.3, 'Manufacturing': 0.4}
 
 #emisprob was defined by Gaussian Probability Density Function (see rand.py)
emisprob = {
   'Residential' : {'G100200P': 0.37, 'G250400P': 0.37, 'G450600P': 0.59, 'G650800P': 0.83, 'G9002000P': 0.05},
   'Commercial' : {'G100200P': 0.58, 'G250400P': 0.31, 'G450600P': 0.83, 'G650800P': 0.43, 'G9002000P': 0.49},
   'Manufacturing': {'G100200P': 0.15, 'G250400P': 0.97, 'G450600P': 0.85, 'G650800P': 0.97, 'G9002000P': 0.31}
   }
 
transprob = {
   'Residential' : {'Residential': 0.5, 'Commercial': 0.4, 'Manufacturing': 0.1},
   'Commercial' : {'Residential': 0.3, 'Commercial': 0.5, 'Manufacturing': 0.2},
   'Manufacturing' : {'Residential': 0.1, 'Commercial': 0.4, 'Manufacturing': 0.5}
   }

def viterbi(obs, states, initprob, emisprob, transprob):
	U = [{}] #initialize an empty set
	path = {} #initialize an empty path

#initialize 
	for z in states:
		U[0][z] = initprob[z] * emisprob[z][obs[0]]
		path[z] = [z]

#When t > 0, perform Viterbi
	#for time through length of observation
	for	t in range(1, len(obs)):
		#U=MIU, this is the saved MAX
		U.append({})
		newpath = {}
	
		for z in states:
			#Recursion, gives max stored in "prob".
			(prob, state) = max((emisprob[z][obs[t]] * transprob[z0][z] * U[t-1][z0], z0) for z0 in states)
			#update U as prob
			U[t][z] = prob
			#update newpath. Keep track of max seq path at each step
			newpath[z] = path[state] + [z] 
		#throw away old path
		path = newpath
	n = 0
	if len(obs) !=1:
		n=t
	print_dptable(U)
	(prob, state) = max((U[n][z], z) for z in states)
	return (prob, path[state])

def print_dptable(U):
    s = "    " + " ".join(("%5d" % i) for i in range(len(U))) + "\n"
    for z in U[0]:
        s += "%.5s: " % z
        s += " ".join("%.5s" % ("%f" % u[z]) for u in U)
        s += "\n"
    print(s)

def run():
    return viterbi(obs, states, initprob, emisprob, transprob)
print(run())
	