from graph.graph import Graph
import numpy as np

graph = Graph()

# add variable nodes
G = graph.add_var_node('Grade',2)
D = graph.add_var_node('Course Difficulty',2)
I = graph.add_var_node('Intelligence', 2)
# connecting factor
P_G_DI = np.array([[[0.5,0.1],[0.9,0.4]],[[0.5,0.9],[0.1,0.6]]])
graph.add_factor_node(P_G_DI, G, D, I)
# run sum-product and get marginals for variables
graph.compute_all_marginals()
marginal_dict = graph.get_all_marginals()
print 'distribution (Grade) :'
print marginal_dict['Grade']

# reset before altering graph further
graph.reset_all_messages()
################ UPON EXPLICIT CONDITIONING #############

# condition on variables
graph.vars['Intelligence'].condition(1)
graph.vars['Course Difficulty'].condition(0)
# Now compute all marginals using sum product
graph.compute_all_marginals()
marginal_dict = graph.get_all_marginals()
print 'distribution (Grade) :'
print marginal_dict['Grade']
    [[0.3, 0.4, 0.3], [0.25, 0.5, 0.25], [0.1, 0.1, 0.8]],
    [[0.4, 0.4, 0.2], [0.3, 0.4, 0.3], [0.25, 0.35, 0.4]],
    [[0.6, 0.2, 0.2], [0.7, 0.15, 0.15], [0.4, 0.3, 0.3]],
])
P_G_R = np.array([[0.5, 0.3, 0.2], [0.4, 0.3, 0.3], [0.2, 0.2, 0.6]])
'''
    Note: We modified P_DI_G and P_G_R only as these are the parameters that are
    to be tuned. These are the only parameters that include Grade (G) and thus
    these are the only unknown CPD tables as Grade is hidden.
'''

######################## Initialize the Factor Graph ######################
graph = Graph()

# add variable nodes
G = graph.add_var_node(
    'Grade', 3)  # Grade on GPA scale - 0 - 1.5(0)/ 1.5 - 3(1)/3 - 4(2)
D = graph.add_var_node('Course Difficulty',
                       3)  # Easy(0)/ Moderate(1) / Hard(2)
I = graph.add_var_node('Intelligence',
                       3)  # Poor(0) / Average(1) / Exceptional(2)
R = graph.add_var_node('Recommondation Letter',
                       3)  # Bad(0) / Average(1) / Excellent(2)
S = graph.add_var_node('SAT Performance',
                       3)  # Poor(0)/ Average(1) / Excellent(1)

for iteration in range(0, 10):
    print 'Iteration :', iteration
    # Expectation Step - Initialize Grade using the sum-product algorithm using Bel-Prop
    # Form the factor graph from the present distribution
    graph.add_factor_node(P_DI_G, D, I, G)
    graph.add_factor_node(P_G_R, G, R)
                   [[0.3,0.4,0.3],[0.25,0.5,0.25],[0.1,0.1,0.8]],
                   [[0.4,0.4,0.2],[0.3,0.4,0.3],[0.25,0.35,0.4]],
                   [[0.6,0.2,0.2],[0.7,0.15,0.15],[0.4,0.3,0.3]],
                 ])
P_G_R = np.array([[0.5,0.3,0.2],[0.4,0.3,0.3],[0.2,0.2,0.6]])
'''
    Note: We modified P_DI_G and P_G_R only as these are the parameters that are
    to be tuned. These are the only parameters that include Grade (G) and thus
    these are the only unknown CPD tables as Grade is hidden.
'''

######################## Initialize the Factor Graph ######################
graph = Graph()

# add variable nodes
G = graph.add_var_node('Grade',3) # Grade on GPA scale - 0 - 1.5(0)/ 1.5 - 3(1)/3 - 4(2)
D = graph.add_var_node('Course Difficulty',3) # Easy(0)/ Moderate(1) / Hard(2)
I = graph.add_var_node('Intelligence', 3) # Poor(0) / Average(1) / Exceptional(2)
R = graph.add_var_node('Recommondation Letter', 3) # Bad(0) / Average(1) / Excellent(2)
S = graph.add_var_node('SAT Performance', 3) # Poor(0)/ Average(1) / Excellent(1)

for iteration in range(0,10):
    print 'Iteration :', iteration
    # Expectation Step - Initialize Grade using the sum-product algorithm using Bel-Prop
    # Form the factor graph from the present distribution
    graph.add_factor_node(P_DI_G, D, I, G)
    graph.add_factor_node(P_G_R, G, R)
    graph.add_factor_node(P_I_S, I, S)
    graph.add_factor_node(P_D, D)
    graph.add_factor_node(P_I, I)
    # Now the hidden value is Grade
from graph.graph import Graph
import numpy as np

graph = Graph()

# add variable nodes
G = graph.add_var_node('Grade', 2)
D = graph.add_var_node('Course Difficulty', 2)
I = graph.add_var_node('Intelligence', 2)
# connecting factor
P_G_DI = np.array([[[0.5, 0.1], [0.9, 0.4]], [[0.5, 0.9], [0.1, 0.6]]])
graph.add_factor_node(P_G_DI, G, D, I)
# run sum-product and get marginals for variables
graph.compute_all_marginals()
marginal_dict = graph.get_all_marginals()
print 'distribution (Grade) :'
print marginal_dict['Grade']

# reset before altering graph further
graph.reset_all_messages()
################ UPON EXPLICIT CONDITIONING #############

# condition on variables
graph.vars['Intelligence'].condition(1)
graph.vars['Course Difficulty'].condition(0)
# Now compute all marginals using sum product
graph.compute_all_marginals()
marginal_dict = graph.get_all_marginals()
print 'distribution (Grade) :'
print marginal_dict['Grade']