"""Forward/sum likelihood with authored discrete parameters; no training."""
from fractions import Fraction as F
from itertools import product
import json
PI=[F(3,5),F(2,5)]
T=[[F(3,4),F(1,4)],[F(1,5),F(4,5)]]
B=[{'R':F(4,5),'B':F(1,5),'G':F(0)},{'R':F(3,10),'B':F(7,10),'G':F(0)}]
def forward(obs):
    if any(o not in B[0] for o in obs):raise ValueError('unknown symbol')
    if not obs:return [],F(1)
    a=[PI[j]*B[j][obs[0]] for j in range(2)];rows=[a]
    for o in obs[1:]:
        a=[sum((a[i]*T[i][j] for i in range(2)),F(0))*B[j][o] for j in range(2)]
        rows.append(a)
    return rows,sum(a,F(0))
def joint(path,obs):
    if not obs:return F(1)
    p=PI[path[0]]*B[path[0]][obs[0]]
    for t in range(1,len(obs)):p*=T[path[t-1]][path[t]]*B[path[t]][obs[t]]
    return p
if __name__=='__main__':
    assert sum(PI)==1 and all(sum(r)==1 for r in T) and all(sum(r.values())==1 for r in B)
    obs=['R','B','R'];rows,total=forward(obs)
    paths=[{'path':list(q),'joint':str(joint(q,obs))} for q in product(range(2),repeat=3)]
    assert total==sum((joint(q,obs) for q in product(range(2),repeat=3)),F(0))
    assert sum((forward(o)[1] for o in product('RB',repeat=3)),F(0))==1
    assert forward(['G'])[1]==0 and forward([])[1]==1
    print(json.dumps({'observation':obs,'alpha_rows':[[str(v) for v in r] for r in rows],'observation_likelihood':str(total),'all_eight_path_joints':paths,'impossible_G_likelihood':'0','parameters_learned':False},indent=2))
