<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Intelligent Systems Assignment 3
Bayes' net inference
Names
Step1:  a. Bayes' net for instant perception and position.
Build a Bayes' net that represent the relationships between the random variables. Based on it, write an expression for the joint probability distribution of all the variables.
b. Probability functions calculated from the instant model.
Assuming an uniform distribution for the Pacman position probability, write functions to calculate the following probabilities
Step2:  ii. $P(E_{E}=e_{E}|E_{N}=e_{N},E_{S}=E_{S})$
Step3:  iii. $P(S)$, where $S\subseteq{e_{N},e_{S},e_{E},e_{W}}$
Step4:  c. Bayes' net for dynamic perception and position.
Now we will consider a scenario where the Pacman moves a finite number of steps $n$. In this case we have $n$
different variables for the positions $X_{1},\dots,X_{n}$, as well as for each one of the perceptions, e.g.
$E_{N_{1}},\dots,E_{N_{n}}$ for the north perception. For the initial Pacman position, assume an uniform 
distribution among the valid positions. Also assume that at each time step the Pacman choses, to move, one of the valid neighbor positions with uniform probability. Draw the corresponding Bayes' net for $n=4$.
d. Probability functions calculated from the dynamic model.
Assuming an uniform distribution for the Pacman position probability, write functions to calculate the following probabilities
Step5:  ii. $P(X_{2}=x_{2}|E_{2}=e_{2},E_{3}=e_{3},E_{4}=e_{4})$
Step6:  iii. $P(E_{4}=e_{4}|E_{1}=e_{1},E_{2}=e_{2},E_{3}=e_{3})$
Step7:  iv. $P(E_{E_{2}}=e_{E_{2}}|E_{N_{2}}=e_{N_{2}},E_{S_{2}}=E_{S_{2}})$
Step8:  Test functions
You can use the following functions to test your solutions.
<ASSISTANT_TASK:>
Python Code:
class Directions:
    NORTH = 'North'
    SOUTH = 'South'
    EAST = 'East'
    WEST = 'West'
    STOP = 'Stop'
Explanation: Intelligent Systems Assignment 3
Bayes' net inference
Names:
IDs:
End of explanation
def P_1(eps, E_N, E_S):
    '''
    Calculates: P(X=x|E_{N}=e_{N},E_{S}=e_{S})
    Arguments: E_N, E_S \in {True,False}
               0 <= eps <= 1 (epsilon)
    Returns: dictionary of type int x int --> float
    '''
    pd = {(x,y):0 for x in range(1,7) for y in range(1,6)}
    return pd
P_1(0, True, False)
Explanation: a. Bayes' net for instant perception and position.
Build a Bayes' net that represent the relationships between the random variables. Based on it, write an expression for the joint probability distribution of all the variables.
b. Probability functions calculated from the instant model.
Assuming an uniform distribution for the Pacman position probability, write functions to calculate the following probabilities:
i. $P(X=x|E_{N}=e_{N},E_{S}=e_{S})$
End of explanation
def P_2(eps, E_N, E_S):
    '''
    Calculates: P(E_{E}=e_{E}|E_{N}=e_{N},E_{S}=E_{S})
    Arguments: E_N, E_S \in {True,False}
               0 <= eps <= 1
    Returns: dictionary of type (False, True) --> float
    '''
    pd = {True:0, False:0}
    return pd
P_2(0.2, True, False)
Explanation: ii. $P(E_{E}=e_{E}|E_{N}=e_{N},E_{S}=E_{S})$
End of explanation
def P_3(eps, S):
    '''
    Calculates: P(S), where S\subseteq\{e_{N},e_{S},e_{E},e_{W}\}
    Arguments: S a dictionary with keywords in Directions and values in
    {True,False}
               0 <= eps <= 1
    Returns: float value representing P(S)
    '''
    return 0
P_3(0.3, {Directions.EAST: True, Directions.SOUTH: False})
Explanation: iii. $P(S)$, where $S\subseteq{e_{N},e_{S},e_{E},e_{W}}$
End of explanation
def P_4(eps, E_1, E_3):
    '''
    Calculates: P(X_{4}=x_{4}|E_{1}=e_{1},E_{3}=e_{3})
    Arguments: E_1, E_3 dictionaries of type Directions --> {True,False}
               0 <= eps <= 1
    Returns: dictionary of type int x int --> float
    '''
    pd = {(x,y):0 for x in range(1,7) for y in range(1,6)}
    return pd
E_1 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
E_3 = {Directions.NORTH: True, Directions.SOUTH: True, Directions.EAST: False, Directions.WEST: False}
P_4(0.1, E_1, E_3)
Explanation: c. Bayes' net for dynamic perception and position.
Now we will consider a scenario where the Pacman moves a finite number of steps $n$. In this case we have $n$
different variables for the positions $X_{1},\dots,X_{n}$, as well as for each one of the perceptions, e.g.
$E_{N_{1}},\dots,E_{N_{n}}$ for the north perception. For the initial Pacman position, assume an uniform 
distribution among the valid positions. Also assume that at each time step the Pacman choses, to move, one of the valid neighbor positions with uniform probability. Draw the corresponding Bayes' net for $n=4$.
d. Probability functions calculated from the dynamic model.
Assuming an uniform distribution for the Pacman position probability, write functions to calculate the following probabilities:
i. $P(X_{4}=x_{4}|E_{1}=e_{1},E_{3}=e_{3})$
End of explanation
def P_5(eps, E_2, E_3, E_4):
    '''
    Calculates: P(X_{2}=x_{2}|E_{2}=e_{2},E_{3}=e_{3},E_{4}=e_{4})
    Arguments: E_2, E_3, E_4 dictionaries of type Directions --> {True,False}
               0 <= eps <= 1
    Returns: dictionary of type int x int --> float
    '''
    pd = {(x,y):0 for x in range(1,7) for y in range(1,6)}
    return pd
E_2 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
E_3 = {Directions.NORTH: True, Directions.SOUTH: True, Directions.EAST: False, Directions.WEST: False}
E_4 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
P_5(0.1, E_2, E_3, E_4)
Explanation: ii. $P(X_{2}=x_{2}|E_{2}=e_{2},E_{3}=e_{3},E_{4}=e_{4})$
End of explanation
def P_6(eps, E_1, E_2, E_3):
    '''
    Calculates: P(E_{4}=e_{4}|E_{1}=e_{1},E_{2}=e_{2},E_{3}=e_{3})
    Arguments: E_1, E_2, E_3 dictionaries of type Directions --> {True,False}
               0 <= eps <= 1
    Returns: dictionary of type {False, True}^4 --> float
    '''
    pd = {(n, s, e, w): 0 for n in [False, True] for s in [False, True] 
                                 for e in [False, True] for w in [False, True]}
    return pd
E_1 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
E_2 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
E_3 = {Directions.NORTH: True, Directions.SOUTH: True, Directions.EAST: False, Directions.WEST: False}
P_6(0.1, E_1, E_2, E_3)
Explanation: iii. $P(E_{4}=e_{4}|E_{1}=e_{1},E_{2}=e_{2},E_{3}=e_{3})$
End of explanation
def P_7(eps, E_N, E_S):
    '''
    Calculates: P(E_{E_{2}}=e_{E_{2}}|E_{N_{2}}=e_{N_{2}},E_{S_{2}}=E_{S_{2}})
    Arguments: E_N_2, E_S_2 \in {True,False}
               0 <= eps <= 1
    Returns: dictionary of type (False, True) --> float
    '''
    pd = {True:0, False:0}
    return pd
P_7(0.1, True, False)
Explanation: iv. $P(E_{E_{2}}=e_{E_{2}}|E_{N_{2}}=e_{N_{2}},E_{S_{2}}=E_{S_{2}})$
End of explanation
def approx_equal(val1, val2):
    return abs(val1-val2) <= 0.00001
def test_P_1():
    pd = P_1(0.0, True, True)
    assert approx_equal(pd[(2, 1)], 0.1111111111111111)
    assert approx_equal(pd[(3, 1)], 0)
    pd = P_1(0.3, True, False)
    assert approx_equal(pd[(2, 1)], 0.03804347826086956)
    assert approx_equal(pd[(3, 1)], 0.016304347826086956)
def test_P_2():
    pd = P_2(0.0, True, True)
    assert approx_equal(pd[False], 1.0)
    pd = P_2(0.3, True, False)
    assert approx_equal(pd[False], 0.5514492753623188)
def test_P_3():
    pd = P_3(0.1, {Directions.EAST: True, Directions.WEST: True})
    assert approx_equal(pd, 0.2299999999999999)
    pd = P_3(0.1, {Directions.EAST: True})
    assert approx_equal(pd, 0.3999999999999999)
    pd = P_3(0.2, {Directions.EAST: False, Directions.WEST: True, Directions.SOUTH: True})
    assert approx_equal(pd, 0.0980000000000000)
def test_P_4():
    E_1 = {Directions.NORTH: False, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: True}
    E_3 = {Directions.NORTH: False, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: True}
    pd = P_4(0.0, E_1, E_3)
    assert approx_equal(pd[(6, 3)], 0.1842105263157895)
    assert approx_equal(pd[(4, 3)], 0.0)
    pd = P_4(0.2, E_1, E_3)
    assert approx_equal(pd[(6, 3)], 0.17777843398830864)
    assert approx_equal(pd[(4, 3)], 0.000578430282649176)
    E_1 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
    E_3 = {Directions.NORTH: False, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
    pd = P_4(0.0, E_1, E_3)
    assert approx_equal(pd[(6, 2)], 0.3333333333333333)
    assert approx_equal(pd[(4, 3)], 0.0)
def test_P_5():
    E_2 = {Directions.NORTH: True, Directions.SOUTH: True, Directions.EAST: False, Directions.WEST: False}
    E_3 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: False, Directions.WEST: False}
    E_4 = {Directions.NORTH: True, Directions.SOUTH: True, Directions.EAST: False, Directions.WEST: False}
    pd = P_5(0, E_2, E_3, E_4)
    assert approx_equal(pd[(2, 5)], 0.5)
    assert approx_equal(pd[(4, 3)], 0.0)
    pd = P_5(0.3, E_2, E_3, E_4)
    assert approx_equal(pd[(2, 5)], 0.1739661245168835)
    assert approx_equal(pd[(4, 3)], 0.0787991740545979)
def test_P_6():
    E_1 = {Directions.NORTH: True, Directions.SOUTH: True, Directions.EAST: False, Directions.WEST: False}
    E_2 = {Directions.NORTH: True, Directions.SOUTH: True, Directions.EAST: False, Directions.WEST: False}
    E_3 = {Directions.NORTH: True, Directions.SOUTH: False, Directions.EAST: True, Directions.WEST: False}
    pd = P_6(0.2, E_1, E_2, E_3)
    assert approx_equal(pd[(False, False, True, True)], 0.15696739914079486)
    assert approx_equal(pd[(True, True, False, False)], 0.20610191744824477)
    pd = P_6(0., E_1, E_2, E_3)
    assert approx_equal(pd[(False, False, True, True)], 0.5)
    assert approx_equal(pd[(False, True, False, False)], 0.0)
def test_P_7():
    pd = P_7(0.0, True, False)
    assert approx_equal(pd[False], 0.7142857142857143)
    pd = P_7(0.3, False, False)
    assert approx_equal(pd[False], 0.5023529411764706)
    
test_P_1()
Explanation: Test functions
You can use the following functions to test your solutions.
End of explanation
<END_TASK>