def test_repr(self): fd1 = fdict(a=1, b=2) T.assert_equal(repr(fd1), "fdict({'a': 1, 'b': 2})") T.assert_equal(eval(repr(fd1)), fd1) fd2 = fdict(c=3, **fd1) T.assert_equal(repr(fd2), "fdict({'a': 1, 'c': 3, 'b': 2})") T.assert_equal(eval(repr(fd2)), fd2)
def test_can_hash(self): # Only immutable objects are hashable, and hashable objects can be dict keys. fd1 = fdict(a=1, b=2) fd2 = fdict({'a':1, 'b':2}) mydict = {fd1:1} mydict[fd2] = 2 T.assert_equal(mydict[fd1], 2)
def test_dunder_init(self): fd = fdict(a=1) assert fd == {'a': 1}, dict(fd) # Implemented naively, __init__ would re-set the value of our immutable object. fd.__init__(b=2) assert fd == {'a': 1}, dict(fd)
def test_cheap_hash(self): import mock import __builtin__ with mock.patch.object(__builtin__, 'hash', wraps=hash) as mock_hash: fd = fdict(a=1) T.assert_equal((('a', 1),).__hash__(), fd.__hash__()) T.assert_equal(1, mock_hash.call_count) T.assert_equal((('a', 1),).__hash__(), fd.__hash__()) T.assert_equal(1, mock_hash.call_count)
def copy(mcs, children=None, properties=None): """Return an (altered) copy of this object.""" # Make a copy, with altered children and/or properties attributes. attrs = mcs.__dict__.copy() if children is not None: attrs['children'] = tuple(children) if properties: attrs['properties'] = fdict(mcs.properties).update(properties) attrs['properties'] = fdict( (key, val) for key, val in attrs['properties'].items() if val is not token.undefined) mcs_copy = super(tokenType, mcs).__new__( # Inherit attributes of the copied class mcs, mcs.__name__, (token, ), attrs, ) return mcs_copy
def test_no_vars(self): """ To allocate a .__dict__ attribute of this object means that we're allocating a second, mutable dictionary as part of our frozendict. This would be a waste of memory as well as yielding pretty nonsensical semantics wrt immutability. """ fd = fdict(a=1) with T.assert_raises(TypeError): vars(fd) with T.assert_raises(AttributeError): fd.__dict__
def copy(mcs, children=None, properties=None): """Return an (altered) copy of this object.""" # Make a copy, with altered children and/or properties attributes. attrs = mcs.__dict__.copy() if children is not None: attrs['children'] = tuple(children) if properties: attrs['properties'] = fdict(mcs.properties).update(properties) attrs['properties'] = fdict( (key, val) for key, val in attrs['properties'].items() if val is not token.undefined ) mcs_copy = super(tokenType, mcs).__new__( # Inherit attributes of the copied class mcs, mcs.__name__, (token,), attrs, ) return mcs_copy
def test_update(self): ################################ # a b c d e f g h i j k l m n o # * * * * * * * * # * * * * * * * * # * * * * * * * * # * * * * * * * * fd = fdict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8) fd2 = fd.update( dict(a=9, b=10, c=11, d=12, i=13, j=14, k=15, l=16), ( (key, val) for key, val in zip( ('a', 'b', 'e', 'f', 'i', 'j', 'm', 'n'), range(17, 25), ) ), a=25, c=26, e=27, g=28, i=29, k=30, m=31, o=32 ) expected = dict( a=25, b=18, c=26, d=12, e=27, f=20, g=28, h=8, i=29, j=22, k=30, l=16, m=31, n=24, o=32, ) assert fd2 == expected
def test___WALTER_2015___RoboAI___MidTerm_Q1(): """test: WALTER (2015) "Planning, Learning & Estimation in Robotics & A.I.": Mid-Term Exam, Question 1""" # Number of Time Periods T = 2 state_prior = PMF(dict.fromkeys((('S', 0),)), {fdict({('S', 0): 1}): 1 / 3, fdict({('S', 0): 2}): 1 / 3, fdict({('S', 0): 3}): 1 / 3}) state_transition_template = PMF(dict.fromkeys((('S', -1), ('S', 0))), {fdict({('S', -1): 1, ('S', 0): 1}): .2, fdict({('S', -1): 1, ('S', 0): 2}): .3, fdict({('S', -1): 1, ('S', 0): 3}): .5, fdict({('S', -1): 2, ('S', 0): 1}): .2, fdict({('S', -1): 2, ('S', 0): 2}): .7, fdict({('S', -1): 2, ('S', 0): 3}): .1, fdict({('S', -1): 3, ('S', 0): 1}): .4, fdict({('S', -1): 3, ('S', 0): 2}): .2, fdict({('S', -1): 3, ('S', 0): 3}): .4}, cond={('S', -1): None}) observation_template = PMF(dict.fromkeys((('S', 0), ('Z', 0))), {fdict({('S', 0): 1, ('Z', 0): 1}): .6, fdict({('S', 0): 1, ('Z', 0): 2}): .1, fdict({('S', 0): 1, ('Z', 0): 3}): .3, fdict({('S', 0): 2, ('Z', 0): 1}): .1, fdict({('S', 0): 2, ('Z', 0): 2}): .7, fdict({('S', 0): 2, ('Z', 0): 3}): .2, fdict({('S', 0): 3, ('Z', 0): 1}): .2, fdict({('S', 0): 3, ('Z', 0): 2}): .3, fdict({('S', 0): 3, ('Z', 0): 3}): .5}, cond={('S', 0): None}) hmm = HMM('S', 'Z', state_prior, state_transition_template, observation_template) # Set up Probability Factors / Joint Probability Distributions print('\nPROBLEM SETUPS:\n') print('Prob(S_0) =') hmm.state_prior_pdf.pprint() for t in range(1, T + 1): print('Prob(S_%i | S_%i) =' % (t, t - 1)) hmm.transition_pdf(t).pprint() for t in range(T + 1): print('Prob(Z_%i | S_%i) =' % (t, t)) hmm.observation_pdf(t).pprint() all_z = {0: 2, 1: 3, 2: 1} print('actual z values =\n', all_z) print('\nFORWARD-BACKWARD ALGORITHM:\n') print('"Forward" Probabilities:\n') forward = hmm.forward_pdf(range(T + 1), all_z) for t in range(T + 1): print('Prob(S_%i, z up to z_%i) =' % (t, t)) forward[t].pprint() alpha_0 = PMF(dict.fromkeys((('S', 0), ('Z', 0))), {fdict({('S', 0): 1, ('Z', 0): 2}): .1 / 3, fdict({('S', 0): 2, ('Z', 0): 2}): .7 / 3, fdict({('S', 0): 3, ('Z', 0): 2}): .3 / 3}, scope={('Z', 0): 2}) forward_0___check = forward[0].allclose(alpha_0) alpha_1 = PMF(dict.fromkeys((('S', 1), ('Z', 0), ('Z', 1))), {fdict({('S', 1): 1, ('Z', 0): 2, ('Z', 1): 3}): .084 / 3, fdict({('S', 1): 2, ('Z', 0): 2, ('Z', 1): 3}): .116 / 3, fdict({('S', 1): 3, ('Z', 0): 2, ('Z', 1): 3}): .12 / 3}, scope={('Z', 0): 2, ('Z', 1): 3}) forward_1___check = forward[1].allclose(alpha_1) alpha_2 = PMF(dict.fromkeys((('S', 2), ('Z', 0), ('Z', 1), ('Z', 2))), {fdict({('S', 2): 1, ('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}): .0528 / 3, fdict({('S', 2): 2, ('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}): .013 / 3, fdict({('S', 2): 3, ('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}): .0203 / 3}, scope={('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}) forward_2___check = forward[2].allclose(alpha_2, atol=1e-2) print('"Backward" Probabilities:\n') backward = hmm.backward_factor(range(T + 1), all_z) for t in reversed(range(T + 1)): # Recursively compute Backward factors print('Prob(z_%i to %i | S_%i) =' % (t + 1, T, t)) backward[t].pprint() beta_2 = PMF(dict.fromkeys((('S', 2),)), {fdict({('S', 2): 1}): 1., fdict({('S', 2): 2}): 1., fdict({('S', 2): 3}): 1.}, cond={('S', 2): None}) backward_2___check = backward[2].allclose(beta_2) beta_1 = PMF(dict.fromkeys((('S', 1), ('Z', 2))), {fdict({('S', 1): 1, ('Z', 2): 1}): .25, fdict({('S', 1): 2, ('Z', 2): 1}): .21, fdict({('S', 1): 3, ('Z', 2): 1}): .34}, cond={('S', 1): None}, scope={('Z', 2): 1}) backward_1___check = backward[1].allclose(beta_1) beta_0 = PMF(dict.fromkeys((('S', 0), ('Z', 1), ('Z', 2))), {fdict({('S', 0): 1, ('Z', 1): 3, ('Z', 2): 1}): .1126, fdict({('S', 0): 2, ('Z', 1): 3, ('Z', 2): 1}): .0614, fdict({('S', 0): 3, ('Z', 1): 3, ('Z', 2): 1}): .1064}, cond={('S', 0): None}, scope={('Z', 1): 3, ('Z', 2): 1}) backward_0___check = backward[0].allclose(beta_0) print('Probability of each X conditional on all z values:\n') infer_state = hmm.infer_state(range(T + 1), all_z) for t in range(T + 1): print('Prob(S_%i | all z) =' % t) infer_state[t].pprint() infer_0 = PMF(dict.fromkeys((('S', 0), ('Z', 0), ('Z', 1), ('Z', 2))), {fdict({('S', 0): 1}): .0038, fdict({('S', 0): 2}): .0143, fdict({('S', 0): 3}): .0106}, cond={('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}).norm() infer_0.pprint() infer_0___check = infer_state[0].allclose(infer_0, atol=1e-1) infer_1 = PMF(dict.fromkeys((('S', 1), ('Z', 0), ('Z', 1), ('Z', 2))), {fdict({('S', 1): 1}): .007, fdict({('S', 1): 2}): .0081, fdict({('S', 1): 3}): .0136}, cond={('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}).norm() infer_1.pprint() infer_1___check = infer_state[1].allclose(infer_1, atol=1e-2) infer_2 = PMF(dict.fromkeys((('S', 2), ('Z', 0), ('Z', 1), ('Z', 2))), {fdict({('S', 2): 1}): .0176, fdict({('S', 2): 2}): .0043, fdict({('S', 2): 3}): .0068}, cond={('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}).norm() infer_2.pprint() infer_2___check = infer_state[2].allclose(infer_2, atol=1e-1) print('MAP of each X:\n') for t in range(T + 1): print('MAP Prob(S_%i | all z) =' % t) infer_state[t].max().pprint() print('\nVITERBI ALGORITHM:\n') all_z = [[2]] all_z += [all_z[0] + [3]] all_z += [all_z[1] + [1]] map_joint_distributions = [] for t in range(T + 1): print('Most Likely Joint Distribution with actual z values up to z_%i:' % t) map_joint_distributions += [hmm.max_a_posteriori_joint_distributions(all_z[t])] map_joint_distributions[t].pprint() map_0 = PMF(dict.fromkeys((('S', 0), ('Z', 0))), {fdict({('S', 0): 2, ('Z', 0): 2}): .7 / 3}, scope={('Z', 0): 2}) map_0___check = map_joint_distributions[0].allclose(map_0) map_1 = PMF(dict.fromkeys((('S', 0), ('Z', 0), ('S', 1), ('Z', 1))), {fdict({('S', 0): 2, ('Z', 0): 2, ('S', 1): 2, ('Z', 1): 3}): .0327}, scope={('Z', 0): 2, ('Z', 1): 3}) map_1___check = map_joint_distributions[1].allclose(map_1, atol=1e-3) map_2 = PMF(dict.fromkeys((('S', 0), ('Z', 0), ('S', 1), ('Z', 1), ('S', 2), ('Z', 2))), {fdict({('S', 0): 3, ('Z', 0): 2, ('S', 1): 3, ('Z', 1): 3, ('S', 2): 1, ('Z', 2): 1}): .0048}, scope={('Z', 0): 2, ('Z', 1): 3, ('Z', 2): 1}) map_2___check = map_joint_distributions[2].allclose(map_2) map_state_sequence = hmm.max_a_posteriori_state_sequence(all_z[2]) print(map_state_sequence) map_state_sequence___answer = [3, 3, 1] map_state_sequence___check = map_state_sequence == map_state_sequence___answer assert forward_0___check & forward_1___check & forward_2___check &\ backward_0___check & backward_1___check & backward_2___check &\ infer_0___check & infer_1___check & infer_2___check &\ map_0___check & map_1___check & map_2___check & map_state_sequence___check
def test_is_immutable2(self): # some simple frozendict implementations would mutate here. fd = fdict(a=1) with T.assert_raises(TypeError): dict.update(fd, {'a':2})
def test_no_attribute_deletion(self): fd = fdict() with T.assert_raises(AttributeError): del fd.copy
def test___WALTER_2015___RoboAI___ProbSet1_Q1(): """test: WALTER (2015) "Planning, Learning & Estimation in Robotics & A.I.": Problem Set 1, Question 1""" p_C = PMF(dict.fromkeys(('C',)), {fdict(C='a'): .3, fdict(C='n'): .5, fdict(C='l'): .2}) p_T1_on_C = PMF(dict.fromkeys(('C', 'T1')), {fdict(C='a', T1=0): .3, fdict(C='a', T1=1): .7, fdict(C='n', T1=0): .5, fdict(C='n', T1=1): .5, fdict(C='l', T1=0): .8, fdict(C='l', T1=1): .2}, cond=dict(C=None)) p_T2_on_C = PMF(dict.fromkeys(('C', 'T2')), {fdict(C='a', T2=0): .2, fdict(C='a', T2=1): .8, fdict(C='n', T2=0): .6, fdict(C='n', T2=1): .4, fdict(C='l', T2=0): .9, fdict(C='l', T2=1): .1}, cond=dict(C=None)) p_D_on_T1_T2 = PMF(dict.fromkeys(('T1', 'T2', 'D')), {fdict(T1=0, T2=0, D=0): 1., fdict(T1=0, T2=0, D=1): .0, fdict(T1=0, T2=1, D=0): 1., fdict(T1=0, T2=1, D=1): .0, fdict(T1=1, T2=0, D=0): .0, fdict(T1=1, T2=0, D=1): 1., fdict(T1=1, T2=1, D=0): .0, fdict(T1=1, T2=1, D=1): 1.}, cond=dict(T1=None, T2=None)) p_T1 = (p_C * p_T1_on_C).marg('C') p_T1.pprint() p_T1___answer = PMF(dict.fromkeys(('T1',)), {fdict(T1=0): .5, fdict(T1=1): .5}) p_T1___check = p_T1.allclose(p_T1___answer) p_T2 = (p_C * p_T2_on_C).marg('C') p_T2.pprint() p_T2___answer = PMF(dict.fromkeys(('T2',)), {fdict(T2=0): .54, fdict(T2=1): .46}) p_T2___check = p_T2.allclose(p_T2___answer) p_T1_T2 = (p_C * p_T1_on_C * p_T2_on_C).marg('C') p_T1_T2.pprint() p_T1_T2___answer = PMF(dict.fromkeys(('T1', 'T2')), {fdict(T1=0, T2=0): .312, fdict(T1=0, T2=1): .188, fdict(T1=1, T2=0): .228, fdict(T1=1, T2=1): .272}) p_T1_T2___check = p_T1_T2.allclose(p_T1_T2___answer) p_T1_p_T2 = p_T1 * p_T2 p_T1_p_T2.pprint() p_T1_T2_on_C_equal_n = (p_C * p_T1_on_C * p_T2_on_C).cond(C='n').norm() p_T1_T2_on_C_equal_n.pprint() p_T1_T2_on_C_equal_n___answer = PMF(dict.fromkeys(('C', 'T1', 'T2')), {fdict(T1=0, T2=0): .3, fdict(T1=0, T2=1): .2, fdict(T1=1, T2=0): .3, fdict(T1=1, T2=1): .2}, cond=dict(C='n')) p_T1_T2_on_C_equal_n___check = p_T1_T2_on_C_equal_n.allclose(p_T1_T2_on_C_equal_n___answer) p_T1_on_C_equal_n = p_T1_on_C.at(C='n') p_T1_on_C_equal_n.pprint() p_T2_on_C_equal_n = p_T2_on_C.at(C='n') p_on_T1_T2_and_D_equal_1 = p_D_on_T1_T2.cond(D=1) p_T1_T2_on_C_equal_n_and_D_equal_1 = (p_T1_on_C_equal_n * p_T2_on_C_equal_n * p_on_T1_T2_and_D_equal_1).norm() p_T1_T2_on_C_equal_n_and_D_equal_1.pprint() p_T1_T2_on_C_equal_n_and_D_equal_1___alternative =\ (p_C * p_T1_on_C * p_T2_on_C * p_D_on_T1_T2).cond(C='n', D=1).norm() p_T1_T2_on_C_equal_n_and_D_equal_1___alternative.pprint() p_T1_T2_on_C_equal_n_and_D_equal_1___answer = PMF(dict.fromkeys(('C', 'T1', 'T2', 'D')), {fdict(T1=0, T2=0): .0, fdict(T1=0, T2=1): .0, fdict(T1=1, T2=0): .6, fdict(T1=1, T2=1): .4}, cond=dict(C='n', D=1)) p_T1_T2_on_C_equal_n_and_D_equal_1___answer.pprint() p_T1_T2_on_C_equal_n_and_D_equal_1___check =\ p_T1_T2_on_C_equal_n_and_D_equal_1.allclose(p_T1_T2_on_C_equal_n_and_D_equal_1___alternative, p_T1_T2_on_C_equal_n_and_D_equal_1___answer) assert p_T1___check & p_T2___check & p_T1_T2___check & p_T1_T2_on_C_equal_n___check &\ p_T1_T2_on_C_equal_n_and_D_equal_1___check
def test_no_attributes_allowed(self): fd = fdict() with T.assert_raises(AttributeError): fd.x = 1
def test_is_immutable(self): fd = fdict(a=1) T.assert_equal(fd['a'], 1) with T.assert_raises(TypeError): fd['a'] = 2
def test_cheap_copy(self): fd = fdict() T.assert_is(fd, fd.copy())
class tokenType(type): """The type for token classes.""" children = () properties = fdict() undefined = object() def __repr__(cls): return pformat(cls.__primitive__()) def __primitive__(mcs): # This is (so far) primarily to make the structure easily viewable for debugging. result = (mcs.__name__, ) if mcs.children: result += tuple(mcs.children) if mcs.properties: result += (dict(mcs.properties), ) return result def __eq__(cls, other): if isinstance(other, tokenType): return cls.__primitive__() == other.__primitive__() else: return NotImplemented def __ne__(cls, other): if isinstance(other, tokenType): return cls.__primitive__() != other.__primitive__() else: return NotImplemented def __len__(cls): return len(cls.children) def __iter__(cls): return iter(cls.children) def copy(mcs, children=None, properties=None): """Return an (altered) copy of this object.""" # Make a copy, with altered children and/or properties attributes. attrs = mcs.__dict__.copy() if children is not None: attrs['children'] = tuple(children) if properties: attrs['properties'] = fdict(mcs.properties).update(properties) attrs['properties'] = fdict( (key, val) for key, val in attrs['properties'].items() if val is not token.undefined) mcs_copy = super(tokenType, mcs).__new__( # Inherit attributes of the copied class mcs, mcs.__name__, (token, ), attrs, ) return mcs_copy # Be immutable. def __setattr__(cls, key, value=None): raise TypeError( "{name} objects are read-only".format(name=type(cls).__name__)) def __delattr__(cls, key): raise TypeError( "{name} objects are read-only".format(name=type(cls).__name__)) def __getattribute__(cls, attr): """Emulate type_getattro() in Objects/typeobject.c, except descriptors can be bound to classes too. """ if attr == '__new__': val = type.__getattribute__(cls, attr) # python specifies type.__new__ as a special case. sadface. # Otherwise you get the metaclass as the first *two* arguments. result = val.__get__(None, type(cls)) else: val = object.__getattribute__(cls, attr) if hasattr(val, '__get__'): result = val.__get__(cls, type(cls)) else: result = val return result
def test___WALTER_2015___RoboAI___MidTerm_Q2(): """test: WALTER (2015) "Planning, Learning & Estimation in Robotics & A.I.": Mid-Term Exam, Question 2""" p_B = PMF(dict.fromkeys(('B',)), {fdict(B=0): .7, fdict(B=1): .3}) p_E = PMF(dict.fromkeys(('E',)), {fdict(E=0): .5, fdict(E=1): .5}) p_A_on_E = PMF(dict.fromkeys(('A', 'E')), {fdict(E=0, A=0): .9, fdict(E=0, A=1): .1, fdict(E=1, A=0): .1, fdict(E=1, A=1): .9}, cond=dict(E=None)) p_C_on_A_B = PMF(dict.fromkeys(('A', 'B', 'C')), {fdict(A=0, B=0, C=0): .9, fdict(A=0, B=0, C=1): .1, fdict(A=0, B=1, C=0): .2, fdict(A=0, B=1, C=1): .8, fdict(A=1, B=0, C=0): .3, fdict(A=1, B=0, C=1): .7, fdict(A=1, B=1, C=0): .1, fdict(A=1, B=1, C=1): .9}, cond=dict(A=None, B=None)) p_D_on_C = PMF(dict.fromkeys(('C', 'D')), {fdict(C=0, D=0): .6, fdict(C=0, D=1): .4, fdict(C=1, D=0): .4, fdict(C=1, D=1): .6}, cond=dict(C=None)) p_C_equal_1_on_A_equal_1 = (p_B * p_C_on_A_B.at(A=1, C=1)).marg('B') p_C_equal_1_on_A_equal_1.pprint() p_C_equal_1_on_A_equal_1___answer = PMF(dict.fromkeys(('A', 'C')), {fdict(C=1): .76}, cond=dict(A=1), scope=dict(C=1)) p_C_equal_1_on_A_equal_1___check = p_C_equal_1_on_A_equal_1.allclose(p_C_equal_1_on_A_equal_1___answer) p_A = (p_E * p_A_on_E).marg('E') p_A.pprint() p_A___answer = PMF(dict.fromkeys(('A',)), {fdict(A=0): .5, fdict(A=1): .5}) p_A___check = p_A.allclose(p_A___answer) p_C_on_B_equal_1 = (p_A * p_C_on_A_B.at(B=1)).marg('A') p_C_on_B_equal_1.pprint() p_C_on_B_equal_1___answer = PMF(dict.fromkeys(('B', 'C')), {fdict(C=0): .15, fdict(C=1): .85}, cond=dict(B=1)) p_C_on_B_equal_1___check = p_C_on_B_equal_1.allclose(p_C_on_B_equal_1___answer) p_D_equal_1_on_B_equal_1 = (p_C_on_B_equal_1 * p_D_on_C.at(D=1)).marg('C') p_D_equal_1_on_B_equal_1.pprint() p_D_equal_1_on_B_equal_1___answer = PMF(dict.fromkeys(('B', 'D')), {fdict(D=1): .57}, cond=dict(B=1), scope=dict(D=1)) p_D_equal_1_on_B_equal_1___check = p_D_equal_1_on_B_equal_1.allclose(p_D_equal_1_on_B_equal_1___answer) p_C = (p_A * p_B * p_C_on_A_B).marg('A', 'B') p_C.pprint() p_C___answer = PMF(dict.fromkeys(('C',)), {fdict(C=0): .9 * .5 * .7 + .2 * .5 * .3 + .3 * .5 * .7 + .1 * .5 * .3, fdict(C=1): .1 * .5 * .7 + .8 * .5 * .3 + .7 * .5 * .7 + .9 * .5 * .3}) p_C___check = p_C.allclose(p_C___answer) p_D_equal_1 = (p_C * p_D_on_C.at(D=1)).marg('C') p_D_equal_1.pprint() p_D_equal_1___answer = PMF(dict.fromkeys(('D',)), {fdict(D=1): .4 * (.9 * .5 * .7 + .2 * .5 * .3 + .3 * .5 * .7 + .1 * .5 * .3) + .6 * (.1 * .5 * .7 + .8 * .5 * .3 + .7 * .5 * .7 + .9 * .5 * .3)}, scope=dict(D=1)) p_D_equal_1___check = p_D_equal_1.allclose(p_D_equal_1___answer) p_A_C_on_B = p_A * p_C_on_A_B p_C_on_B = p_A_C_on_B.marg('A') p_B_C_D = p_B * p_C_on_B * p_D_on_C p_B_D = p_B_C_D.marg('C') p_B_equal_1_on_D_equal_1 = p_B_D.cond(D=1).norm().at(B=1) p_B_equal_1_on_D_equal_1.pprint() p_B_equal_1_on_D_equal_1___answer = PMF(dict.fromkeys(('B', 'D')), {fdict(B=1): .337}, cond=dict(D=1), scope=dict(B=1)) p_B_equal_1_on_D_equal_1___check = p_B_equal_1_on_D_equal_1.allclose(p_B_equal_1_on_D_equal_1___answer, atol=1e-3) assert p_C_equal_1_on_A_equal_1___check & p_A___check & p_C_on_B_equal_1___check &\ p_D_equal_1_on_B_equal_1___check & p_C___check & p_D_equal_1___check & p_B_equal_1_on_D_equal_1___check
def test___WALTER_2015___RoboAI___ProbSet1_Q4(): """test: WALTER (2015) "Planning, Learning & Estimation in Robotics & A.I.": Problem Set 1, Question 4""" # Number of Time Periods T = 3 state_prior = PMF(dict.fromkeys((('X', 0),)), {fdict({('X', 0): 0}): .5, fdict({('X', 0): 1}): .5}) state_transition_template = PMF(dict.fromkeys((('X', -1), ('X', 0))), {fdict({('X', -1): 0, ('X', 0): 0}): .6, fdict({('X', -1): 0, ('X', 0): 1}): .4, fdict({('X', -1): 1, ('X', 0): 0}): .3, fdict({('X', -1): 1, ('X', 0): 1}): .7}, cond={('X', -1): None}) observation_template = PMF(dict.fromkeys((('X', 0), ('Z', 0))), {fdict({('X', 0): 0, ('Z', 0): 0}): .8, fdict({('X', 0): 0, ('Z', 0): 1}): .2, fdict({('X', 0): 1, ('Z', 0): 0}): .2, fdict({('X', 0): 1, ('Z', 0): 1}): .8}, cond={('X', 0): None}) hmm = HMM('X', 'Z', state_prior, state_transition_template, observation_template) # Set up Probability Factors / Joint Probability Distributions print('\nPROBLEM SETUPS:\n') print('Prob(X_0) =') hmm.state_prior_pdf.pprint() for t in range(1, T + 1): print('Prob(X_%i | X_%i) =' % (t, t - 1)) hmm.transition_pdf(t).pprint() for t in range(T + 1): print('Prob(Z_%i | X_%i) =' % (t, t)) hmm.observation_pdf(t).pprint() all_z = {0: 0, 1: 0, 2: 1, 3: 0} print('actual z values =\n', all_z) # PART (A): FORWARD-BACKWARD ALGORITHM print('\nFORWARD-BACKWARD ALGORITHM:\n') print('"Forward" Probabilities:\n') forward = hmm.forward_pdf(range(T + 1), all_z) for t in range(T + 1): print('Prob(X_%i, z up to z_%i) =' % (t, t)) forward[t].pprint() alpha_0 = PMF(dict.fromkeys((('X', 0), ('Z', 0))), {fdict({('X', 0): 0, ('Z', 0): 0}): .4, fdict({('X', 0): 1, ('Z', 0): 0}): .1}, scope={('Z', 0): 0}) forward_0___check = forward[0].allclose(alpha_0) alpha_1 = PMF(dict.fromkeys((('X', 1), ('Z', 0), ('Z', 1))), {fdict({('X', 1): 0, ('Z', 0): 0, ('Z', 1): 0}): .216, fdict({('X', 1): 1, ('Z', 0): 0, ('Z', 1): 0}): .046}, scope={('Z', 0): 0, ('Z', 1): 0}) forward_1___check = forward[1].allclose(alpha_1) alpha_2 = PMF(dict.fromkeys((('X', 2), ('Z', 0), ('Z', 1), ('Z', 2))), {fdict({('X', 2): 0, ('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1}): .0287, fdict({('X', 2): 1, ('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1}): .0949}, scope={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1}) forward_2___check = forward[2].allclose(alpha_2, atol=1e-3) alpha_3 = PMF(dict.fromkeys((('X', 3), ('Z', 0), ('Z', 1), ('Z', 2), ('Z', 3))), {fdict({('X', 3): 0, ('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}): .0365, fdict({('X', 3): 1, ('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}): .0156}, scope={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}) forward_3___check = forward[3].allclose(alpha_3, atol=1e-2) print('"Backward" Probabilities:\n') backward = hmm.backward_factor(range(T + 1), all_z) for t in reversed(range(T + 1)): # Recursively compute Backward factors print('Prob(z_%i to %i | X_%i) =' % (t + 1, T, t)) backward[t].pprint() beta_3 = PMF(dict.fromkeys((('X', 3),)), {fdict({('X', 3): 0}): 1., fdict({('X', 3): 1}): 1.}, cond={('X', 3): None}) backward_3___check = backward[3].allclose(beta_3) beta_2 = PMF(dict.fromkeys((('X', 2), ('Z', 3))), {fdict({('X', 2): 0, ('Z', 3): 0}): .56, fdict({('X', 2): 1, ('Z', 3): 0}): .38}, cond={('X', 2): None}, scope={('Z', 3): 0}) backward_2___check = backward[2].allclose(beta_2) beta_1 = PMF(dict.fromkeys((('X', 1), ('Z', 2), ('Z', 3))), {fdict({('X', 1): 0, ('Z', 2): 1, ('Z', 3): 0}): .1888, fdict({('X', 1): 1, ('Z', 2): 1, ('Z', 3): 0}): .2464}, cond={('X', 1): None}, scope={('Z', 2): 1, ('Z', 3): 0}) backward_1___check = backward[1].allclose(beta_1) beta_0 = PMF(dict.fromkeys((('X', 0), ('Z', 1), ('Z', 2), ('Z', 3))), {fdict({('X', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}): .1103, fdict({('X', 0): 1, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}): .0798}, cond={('X', 0): None}, scope={('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}) backward_0___check = backward[0].allclose(beta_0, atol=1e-3) print('Probability of each X conditional on all z values:\n') infer_state = hmm.infer_state(range(T + 1), all_z) for t in range(4): print('Prob(X_%i | all z) =' % t) infer_state[t].pprint() infer_0 = PMF(dict.fromkeys((('X', 0), ('Z', 0), ('Z', 1), ('Z', 2), ('Z', 3))), {fdict({('X', 0): 0}): .4 * .1103, fdict({('X', 0): 1}): .1 * .0798}, cond={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}).norm() infer_0.pprint() infer_0___check = infer_state[0].allclose(infer_0, atol=1e-3) infer_1 = PMF(dict.fromkeys((('X', 1), ('Z', 0), ('Z', 1), ('Z', 2), ('Z', 3))), {fdict({('X', 1): 0}): .216 * .1888, fdict({('X', 1): 1}): .046 * .2464}, cond={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}).norm() infer_1.pprint() infer_1___check = infer_state[1].allclose(infer_1) infer_2 = PMF(dict.fromkeys((('X', 2), ('Z', 0), ('Z', 1), ('Z', 2), ('Z', 3))), {fdict({('X', 2): 0}): .0287 * .56, fdict({('X', 2): 1}): .0949 * .38}, cond={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}).norm() infer_2.pprint() infer_2___check = infer_state[2].allclose(infer_2, atol=1e-3) infer_3 = PMF(dict.fromkeys((('X', 3), ('Z', 0), ('Z', 1), ('Z', 2), ('Z', 3))), {fdict({('X', 3): 0}): .0365, fdict({('X', 3): 1}): .0156}, cond={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}).norm() infer_3.pprint() infer_3___check = infer_state[3].allclose(infer_3, atol=1e-2) print('MAP of each X:\n') for t in range(T + 1): print('MAP Prob(X_%i | all z) =' % t) infer_state[t].max().pprint() # PART (B): VITERBI ALGORITHM print('\nVITERBI ALGORITHM:\n') all_z = [[0]] all_z += [all_z[0] + [0]] all_z += [all_z[1] + [1]] all_z += [all_z[2] + [0]] map_joint_distributions = [] for t in range(T + 1): print('Most Likely Joint Distribution with actual z values up to z_%i:' % t) map_joint_distributions += [hmm.max_a_posteriori_joint_distributions(all_z[t])] map_joint_distributions[t].pprint() map_0 = PMF(dict.fromkeys((('X', 0), ('Z', 0))), {fdict({('X', 0): 0, ('Z', 0): 0}): .4}, scope={('Z', 0): 0}) map_0___check = map_joint_distributions[0].allclose(map_0) map_1 = PMF(dict.fromkeys((('X', 0), ('Z', 0), ('X', 1), ('Z', 1))), {fdict({('X', 0): 0, ('Z', 0): 0, ('X', 1): 0, ('Z', 1): 0}): .192}, scope={('Z', 0): 0, ('Z', 1): 0}) map_1___check = map_joint_distributions[1].allclose(map_1) map_2 = PMF(dict.fromkeys((('X', 0), ('Z', 0), ('X', 1), ('Z', 1), ('X', 2), ('Z', 2))), {fdict({('X', 0): 0, ('Z', 0): 0, ('X', 1): 0, ('Z', 1): 0, ('X', 2): 1, ('Z', 2): 1}): .0614}, scope={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1}) map_2___check = map_joint_distributions[2].allclose(map_2, atol=1e-3) map_3 = PMF(dict.fromkeys((('X', 0), ('Z', 0), ('X', 1), ('Z', 1), ('X', 2), ('Z', 2), ('X', 3), ('Z', 3))), {fdict({('X', 0): 0, ('Z', 0): 0, ('X', 1): 0, ('Z', 1): 0, ('X', 2): 1, ('Z', 2): 1, ('X', 3): 0, ('Z', 3): 0}): .0147}, scope={('Z', 0): 0, ('Z', 1): 0, ('Z', 2): 1, ('Z', 3): 0}) map_3___check = map_joint_distributions[3].allclose(map_3, atol=1e-2) map_state_sequence = hmm.max_a_posteriori_state_sequence(all_z[3]) pprint(map_state_sequence) map_state_sequence___answer = [0, 0, 1, 0] map_state_sequence___check = map_state_sequence == map_state_sequence___answer assert forward_0___check & forward_1___check & forward_2___check & forward_3___check &\ backward_0___check & backward_1___check & backward_2___check & backward_3___check &\ infer_0___check & infer_1___check & infer_2___check & infer_3___check &\ map_0___check & map_1___check & map_2___check & map_3___check & map_state_sequence___check
def test_len(self): fd1 = fdict(a=1, b=2) T.assert_equal(len(fd1), 2) fd2 = fdict(c=3, **fd1) T.assert_equal(len(fd2), 3)
def test___WALTER_2015___RoboAI___ProbSet1_Q2(alpha=.6): # Symbol('alpha') """test: WALTER (2015) "Planning, Learning & Estimation in Robotics & A.I.": Problem Set 1, Question 2""" p_S0_S1 = PMF(dict.fromkeys(('S0', 'S1')), {fdict(S0=0, S1=0): .9, fdict(S0=0, S1=1): .1, fdict(S0=1, S1=0): .1, fdict(S0=1, S1=1): .9}) p_S1_S2 = PMF(dict.fromkeys(('S1', 'S2')), {fdict(S1=0, S2=0): alpha, fdict(S1=0, S2=1): 1. - alpha, fdict(S1=1, S2=0): 1. - alpha, fdict(S1=1, S2=1): alpha}) p_S2_S3 = PMF(dict.fromkeys(('S2', 'S3')), {fdict(S2=0, S3=0): alpha, fdict(S2=0, S3=1): 1. - alpha, fdict(S2=1, S3=0): 1. - alpha, fdict(S2=1, S3=1): alpha}) p_S3_S4 = PMF(dict.fromkeys(('S3', 'S4')), {fdict(S3=0, S4=0): .9, fdict(S3=0, S4=1): .1, fdict(S3=1, S4=0): .1, fdict(S3=1, S4=1): .9}) p_S1_on_S0_equal_1 = p_S0_S1.cond(S0=1) p_S3_on_S4_equal_0 = p_S3_S4.cond(S4=0) p_S1_on_S0_equal_1_and_S4_equal_0 = (p_S1_on_S0_equal_1 * p_S1_S2 * p_S2_S3 * p_S3_on_S4_equal_0)\ .marg('S2', 'S3').norm() p_S1_on_S0_equal_1_and_S4_equal_0.pprint() lambda_0 = lambda a: .09 * (2 * a ** 2 - 2 * a + 1) + .02 * a * (1. - a) lambda_1 = lambda a: .09 * (2 * a ** 2 - 2 * a + 1) + 1.62 * a * (1. - a) p_S1_on_S0_equal_1_and_S4_equal_0___answer = PMF(dict.fromkeys(('S0', 'S1', 'S4')), {fdict(S1=0): lambda_0(alpha), fdict(S1=1): lambda_1(alpha)}, cond=dict(S0=1, S4=0)).norm() assert p_S1_on_S0_equal_1_and_S4_equal_0.allclose(p_S1_on_S0_equal_1_and_S4_equal_0___answer)
def train_hmm(training_data_sequences): state_prior_counts = {} observation_counts = {} transition_counts = {} for i in range(len(training_data_sequences)): data_sequence = training_data_sequences[i] xy = [data_sequence.iloc[0]['xy']] ob = [data_sequence.iloc[0]['ob']] if fdict({('xy', 0): xy[0]}) in state_prior_counts: state_prior_counts[fdict({('xy', 0): xy[0]})] += 1. else: state_prior_counts[fdict({('xy', 0): xy[0]})] = 1. if fdict({('xy', 0): xy[0], ('ob', 0): ob[0]}) in observation_counts: observation_counts[fdict({('xy', 0): xy[0], ('ob', 0): ob[0]})] += 1. else: observation_counts[fdict({('xy', 0): xy[0], ('ob', 0): ob[0]})] = 1. for t in range(1, len(data_sequence)): xy += [data_sequence.iloc[t]['xy']] ob += [data_sequence.iloc[t]['ob']] if fdict({('xy', -1): xy[t - 1], ('xy', 0): xy[t]}) in transition_counts: transition_counts[fdict({('xy', -1): xy[t - 1], ('xy', 0): xy[t]})] += 1. else: transition_counts[fdict({('xy', -1): xy[t - 1], ('xy', 0): xy[t]})] = 1. if fdict({('xy', 0): xy[t], ('ob', 0): ob[t]}) in observation_counts: observation_counts[fdict({('xy', 0): xy[t], ('ob', 0): ob[t]})] += 1. else: observation_counts[fdict({('xy', 0): xy[t], ('ob', 0): ob[t]})] = 1. state_prior_minus_log_counts = {k: -log(v) for k, v in state_prior_counts.items()} transition_minus_log_counts = {k: -log(v) for k, v in transition_counts.items()} observation_minus_log_counts = {k: -log(v) for k, v in observation_counts.items()} state_prior = PMF(dict.fromkeys((('xy', 0), ('ob', 0))), state_prior_minus_log_counts).norm() transition_template = PMF(dict.fromkeys((('xy', -1), ('xy', 0))), transition_minus_log_counts, conditions={('xy', -1): None}).norm() observation_template = PMF(dict.fromkeys((('xy', 0), ('ob', 0))), observation_minus_log_counts, conditions={('xy', 0): None}).norm() return state_prior, transition_template, observation_template