Ejemplo n.º 1
0
def compute_min_backward_messages(phi, observations):
    num_time_steps = len(observations)
    reverse_transition_model = compute_reverse_transition_model()

    backward_messages = [None] * (num_time_steps - 1)
    backward_traceback_messages = [None] * (num_time_steps - 1)

    for time_step in range(num_time_steps - 2, -1, -1):
        backward_messages[time_step] = robot.Distribution()
        backward_traceback_messages[time_step] = robot.Distribution()

        for goal_state in all_possible_hidden_states:
            min_val = np.inf
            argmin = None

            for current_state in phi[time_step + 1]:
                current_val = \
                    phi[time_step + 1][current_state] + \
                    -careful_log(reverse_transition_model[current_state][goal_state])

                if time_step < num_time_steps - 2:
                    current_val += backward_messages[time_step +
                                                     1][current_state]

                if current_val < min_val:
                    min_val = current_val
                    argmin = current_state

            backward_messages[time_step][goal_state] = min_val
            backward_traceback_messages[time_step][goal_state] = argmin

    return backward_messages, backward_traceback_messages
Ejemplo n.º 2
0
def compute_min_forward_messages(phi, observations):
    num_time_steps = len(observations)

    forward_messages = [None] * (num_time_steps - 1)
    traceback_messages = [None] * (num_time_steps - 1)

    for time_step in range(num_time_steps - 1):
        forward_messages[time_step] = robot.Distribution()
        traceback_messages[time_step] = robot.Distribution()

        for goal_state in all_possible_hidden_states:
            min_val = np.inf
            argmin = None

            for current_state in phi[time_step]:
                current_val = \
                    phi[time_step][current_state] + \
                    -careful_log(transition_model(current_state)[goal_state])

                if time_step > 0:
                    current_val += forward_messages[time_step -
                                                    1][current_state]

                if current_val < min_val:
                    min_val = current_val
                    argmin = current_state

            forward_messages[time_step][goal_state] = min_val
            traceback_messages[time_step][goal_state] = argmin

    return forward_messages, traceback_messages
Ejemplo n.º 3
0
def particle_filter(prior_distribution,
                    transition_model,
                    observation_model,
                    observations,
                    num_particles=500):
    """
    Inputs
    ------
    prior_distribution: a distribution over states

    transition_model: a function that takes a hidden state and returns a
        Distribution for the next state

    observation_model: a function that takes a hidden state and returns a
        Distribution for the observation from that hidden state

    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    This function is a Python generator! It calculates outputs "on demand";
    the i-th output should be the marginal distribution for time step i.

    Please see these two pages on Python generators for more information:
      http://wiki.python.org/moin/Generators
      http://docs.python.org/2/tutorial/classes.html#generators

    For an example of a Python generator function, check out the function
    forward (for the forward algorithm) below.

    Key point: The output is *not* a list, so you can't use brackets [] to
    access the i-th entry. We've provided skeletal code so that it should be
    clear what you need to fill in.
    """
    num_time_steps = len(observations)

    # time step 0
    initial_marginal = robot.Distribution()
    # TODO: Your code here
    raise NotImplementedError

    yield initial_marginal  # do not modify this line

    # remaining time steps
    for n in range(1, num_time_steps):
        marginal = robot.Distribution()
        # TODO: Your code here
        raise NotImplementedError

        yield marginal  # do not modify this line
Ejemplo n.º 4
0
def generate_uniform_message():
    message = robot.Distribution()

    for state in all_possible_hidden_states:
        message[state] = 1 / len(all_possible_hidden_states)

    return message
Ejemplo n.º 5
0
def precompute_singleton_potentials(observations):
    num_time_steps = len(observations)
    phi = [None] * num_time_steps

    reverse_observation_model = compute_reverse_observation_model()

    for time_step in range(num_time_steps):
        phi[time_step] = robot.Distribution()
        observation = observations[time_step]

        if not observation:
            phi[time_step] = uniform_potential()
            continue

        for state in reverse_observation_model[observation]:
            potential = reverse_observation_model[observation][state]

            # time step 0 takes into account the prior dist.
            if time_step == 0:
                potential *= prior_distribution[state]

            if potential > 0:
                phi[time_step][state] = -careful_log(potential)

    return phi
Ejemplo n.º 6
0
def uniform_potential():
    potential = robot.Distribution()

    for state in all_possible_hidden_states:
        potential[state] = 0.1

    return potential
Ejemplo n.º 7
0
def initial_distribution():
    # returns a Distribution for the initial hidden state
    prior = robot.Distribution()
    prior['F'] = 0.50
    prior['B'] = 0.50
    prior.renormalize()
    return prior
Ejemplo n.º 8
0
def rev_transition_model(curState):
    # given a hidden state, return the Distribution for the prev hidden state
    revModel = robot.Distribution()
    for x in all_possible_hidden_states:
        tmp = transition_model(x)
        revModel[x] = tmp[curState]
    #revModel.renormalize()
    return revModel
def buildPhi(y):
    phi_X = robot.Distribution()
    for x in all_possible_hidden_states:
        if y is None:
            phi_X[x] = 1
        else:
            yPoss = observation_model(x)
            phi_X[x] = yPoss[y]
    return phi_X
Ejemplo n.º 10
0
def backward(alphaIn, phi_x, y):
    """compute the next forward message"""
    alphaPhi_X = robot.Distribution()
    for x, alphaX in alphaIn.items():
        yProb = phi_x[x]
        tmpProd = yProb * alphaX
        if tmpProd > 0:
            alphaPhi_X[x] = tmpProd

    # compute alpha out
    alphaOut = robot.Distribution()
    for x, alphaPhi in alphaPhi_X.items():
        x2Poss = rev_transition_model(x)
        # multiply and add x2Poss to o/p
        for x2Key, x2pVal in x2Poss.items():
            alphaOut[x2Key] += x2pVal * alphaPhi
        #print(alphaOut)
    return alphaOut
Ejemplo n.º 11
0
def observation_model(state):
    observed_states = robot.Distribution()
    if state == 'F':
        observed_states['H'] = 0.5
        observed_states['T'] = 0.5
    elif state == 'B':
        observed_states['H'] = 0.25
        observed_states['T'] = 0.75
    observed_states.renormalize()
    return observed_states
def mostLikely(phiLast, msgHat):
    finNode = robot.Distribution()
    for key in phiLast.keys():
        val2 = msgHat[key]
        if val2 == 0:
            val2 = np.inf
        finNode[key] = neglog(phiLast[key]) + val2
    minVal, minKey = myDictMin(finNode)
    mHat = minVal
    tBack = minKey
    return mHat, tBack
Ejemplo n.º 13
0
def transition_model(state):
    # given a hidden state, return the Distribution for the next hidden state
    next_states = robot.Distribution()

    # we can always stay where we are
    if state == 'F':
        next_states['F'] = .75
        next_states['B'] = .25
    elif state == 'B':
        next_states['F'] = .25
        next_states['B'] = .75
    next_states.renormalize()
    return next_states
Ejemplo n.º 14
0
def compute_reverse_transition_model():
    # initialize final distribution
    reverse_transitions = {}

    for state in all_possible_hidden_states:
        reverse_transitions[state] = robot.Distribution()

    # collect (unnormalized) reverse transition probabilities
    for start_state in all_possible_hidden_states:
        possible_goal_states = transition_model(start_state)

        for goal_state in possible_goal_states:
            reverse_transitions[goal_state][start_state] = \
                possible_goal_states[goal_state]

    return reverse_transitions
Ejemplo n.º 15
0
def compute_log_reverse_observation_model():
    # initialize final distribution
    reverse_observations = {}

    for observation in all_possible_observed_states:
        reverse_observations[observation] = robot.Distribution()

    # collect (unnormalized) observation-probabilities
    for state in all_possible_hidden_states:
        possible_observations = observation_model(state)

        for observation in possible_observations:
            reverse_observations[observation][state] = \
                careful_log(possible_observations[observation])

    return reverse_observations
Ejemplo n.º 16
0
def forward_backward(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of marginal distributions at each time step; each distribution
    should be encoded as a Distribution (see the Distribution class in
    robot.py and see how it is used in both robot.py and the function
    generate_data() above, and the i-th Distribution should correspond to time
    step i
    """

    num_time_steps = len(observations)
    forward_messages = [None] * num_time_steps
    forward_messages[0] = prior_distribution
    reverse_observation_model = compute_reverse_observation_model()

    # Compute the forward messages
    #print("  - compute forward messages...")

    # apply for every timestep
    for time_step in range(1, num_time_steps):
        forward_messages[time_step] = robot.Distribution()
        observation = observations[time_step - 1]

        # loop through all possible values of next state
        for goal_state in all_possible_hidden_states:
            probability_sum = 0

            if observation:
                # loop through all non-zero values of previous state
                for current_state in reverse_observation_model[observation]:
                    # multiply obs-model, trans-model, message
                    probability_sum += \
                        reverse_observation_model[observation][current_state] * \
                        transition_model(current_state)[goal_state] * \
                        forward_messages[time_step - 1][current_state]
            else:
                for current_state in forward_messages[time_step - 1]:
                    probability_sum += \
                        transition_model(current_state)[goal_state] * \
                        forward_messages[time_step - 1][current_state]

            if probability_sum > 0:
                forward_messages[time_step][goal_state] = probability_sum

    # Compute the backward messages
    # note: order will be reverse! backward_messages[0] will hold the message
    #       coming in to the *last* hidden state
    #print("  - compute backward messages")

    backward_messages = [None] * num_time_steps
    backward_messages[0] = generate_uniform_message()
    reverse_transition_model = compute_reverse_transition_model()

    # apply for every time step
    for time_step in range(1, num_time_steps):
        backward_messages[time_step] = robot.Distribution()
        observation = observations[num_time_steps - time_step]

        # create a table-entry for every possible value
        for goal_state in all_possible_hidden_states:
            probability_sum = 0

            if observation:
                # look only at non-zero values allowed by the observation
                for current_state in reverse_observation_model[observation]:
                    # multiply obs-model, reverse-trans-model, back-message
                    probability_sum += \
                        reverse_observation_model[observation][current_state] * \
                        reverse_transition_model[current_state][goal_state] * \
                        backward_messages[time_step - 1][current_state]
            else:
                for current_state in backward_messages[time_step - 1]:
                    probability_sum += \
                        reverse_transition_model[current_state][goal_state] * \
                        backward_messages[time_step - 1][current_state]

            if probability_sum > 0:
                backward_messages[time_step][goal_state] = probability_sum

    # Compute the marginals
    #print("  - compute marginals")

    marginals = [None] * num_time_steps  # remove this

    for time_step in range(0, num_time_steps):
        marginals[time_step] = robot.Distribution()
        observation = observations[time_step]

        for state in all_possible_hidden_states:
            if observation:
                probability = \
                    reverse_observation_model[observation][state] * \
                    forward_messages[time_step][state] * \
                    backward_messages[num_time_steps - 1 - time_step][state]
            else:
                probability = \
                    forward_messages[time_step][state] * \
                    backward_messages[num_time_steps - 1 - time_step][state]

            if probability > 0:
                marginals[time_step][state] = probability

    for px in marginals:
        px.renormalize()

    return marginals

## load wiki examples
#import dnaExample as dna
#all_possible_hidden_states = dna.get_all_hidden_states()
#all_possible_observed_states = dna.get_all_observed_states()
#prior_distribution = dna.initial_distribution()
#transition_model = dna.transition_model
#observation_model = dna.observation_model
#observationsStr = 'GGCACTGAA'.lower()
#observations = [x for x in observationsStr]

# %% computing m12
num_time_steps = len(observations)

phi1 = robot.Distribution()
obs1 = buildPhi(observations[0])
for x in obs1.keys():
    tmpProd= obs1[x] * prior_distribution[x]
    if tmpProd > 0:
        phi1[x] = tmpProd

# compute message 1 to 2
m12 = robot.Distribution()
tBack12 = {}
phi_use = phi1
for x2_state in all_possible_hidden_states:
    x1_collect = {}
    for x1_state, x1_value in phi_use.items():
        x2_x1_trans = transition_model(x1_state)
        trans_value = x2_x1_trans[x2_state]
Ejemplo n.º 18
0
def baum_welch(all_possible_hidden_states,
               all_possible_observed_states,
               observations):
    """
    Inputs
    ------
    all_possible_hidden_states: a list of possible hidden states

    all_possible_observed_states: a list of possible observed states

    observations: a list of observations, one per hidden state
                  (in this problem, we don't have any missing observations)


    Output
    ------
    A transition model and an observation model
    """
    ### Initialize
    transition_model = robot.uniform_transition_model
    observation_model = robot.spread_observation_model
    initial_state_distribution = robot.initial_distribution()

    num_time_steps = len(observations)

    convergence_reached = False
    while not convergence_reached:
        # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        ### YOUR CODE HERE: Estimate marginals & pairwise marginals
        pairwise_marginals = [None] * num_time_steps
        marginals = [None] * num_time_steps
        # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        ### Learning: estimate model parameters
        # maps states to distributions over possible next states
        transition_model_dict = {}

        # maps states to distributions over possible observations
        observation_model_dict = {}

        # initial
        initial_state_distribution = robot.Distribution()

        # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        # YOUR CODE HERE: Use the estimated marginals & pairwise marginals to
        # estimate the parameters.

        # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        new_transition_model = robot.make_transition_model(transition_model_dict)
        new_obs_model = robot.make_observation_model(observation_model_dict)
        ### Check for convergence
        if check_convergence(all_possible_hidden_states,
                             transition_model,
                             new_transition_model):
            convergence_reached = True
        transition_model = new_transition_model
        observation_model = new_obs_model

    return (transition_model,
            observation_model,
            initial_state_distribution,
            marginals)
Ejemplo n.º 19
0
def forward_backward(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of marginal distributions at each time step; each distribution
    should be encoded as a Distribution (see the Distribution class in
    robot.py and see how it is used in both robot.py and the function
    generate_data() above, and the i-th Distribution should correspond to time
    step i
    """

    # -------------------------------------------------------------------------
    # YOUR CODE GOES HERE
    #

    num_time_steps = len(observations)
    num_hidden_states = len(all_possible_hidden_states)

    # TODO: Compute the forward messages
    forward_messages = np.zeros((num_time_steps, num_hidden_states))
    for i in range(num_hidden_states):
        forward_messages[0,
                         i] = prior_distribution[all_possible_hidden_states[i]]

    # Create a dictionary to index observed states
    observation_index_dict = {
        all_possible_observed_states[i]: i
        for i in range(len(all_possible_observed_states))
    }

    # Create a transition dictionary based on all possible hidden states
    transition_dict = {}
    for i in all_possible_hidden_states:
        transition_dict[i] = {}
        transitions = transition_model(i)
        for j in all_possible_hidden_states:
            if j in transitions:
                transition_dict[i][j] = transitions[j]
            else:
                transition_dict[i][j] = 0

    # Convert transition dictionary to a numpy array
    A = np.array([[transition_dict[i][j] for j in all_possible_hidden_states]
                  for i in all_possible_hidden_states])

    # Create an emission dictionary based on all possible hidden states
    emission_dict = {}
    for i in all_possible_hidden_states:
        emission_dict[i] = {}
        obs = observation_model(i)
        for j in all_possible_observed_states:
            if j in obs:
                emission_dict[i][j] = obs[j]
            else:
                emission_dict[i][j] = 0

    # Convert emission dictionary to a numpy array
    B = np.array([[emission_dict[i][j] for j in all_possible_observed_states]
                  for i in all_possible_hidden_states])

    # Iterate through observations and calculate forward messages
    for o in range(num_time_steps - 1):
        if observations[o] == None:
            forward_messages[o + 1, :] = (forward_messages[o]) @ A
        else:
            obs = observation_index_dict[observations[o]]
            forward_messages[o + 1, :] = (B[:, obs] * forward_messages[o]) @ A

    # TODO: Compute the backward messages
    backward_messages = np.zeros(
        (num_time_steps, len(all_possible_hidden_states)))
    backward_messages[num_time_steps - 1, :] = 1 / num_hidden_states

    # Iterate through observations in reverse order and calculate backwards messages
    for o in reversed(range(1, num_time_steps)):
        if observations[o] == None:
            backward_messages[o - 1, :] = (backward_messages[o]) @ A.T
        else:
            obs = observation_index_dict[observations[o]]
            backward_messages[o -
                              1, :] = (B[:, obs] * backward_messages[o]) @ A.T

    # TODO: Compute the marginals
    marginals = [None] * num_time_steps  # remove this
    marginal_matrix = np.zeros((num_time_steps, num_hidden_states))

    for o in range(num_time_steps):
        if observations[o] == None:
            marginal = forward_messages[o, :] * backward_messages[o, :]
        else:
            obs = observation_index_dict[observations[o]]
            marginal = forward_messages[o, :] * backward_messages[
                o, :] * B[:, obs]
        marginal_dist = robot.Distribution()
        for m in range(num_hidden_states):
            marginal_dist[all_possible_hidden_states[m]] = marginal[m]
        marginal_dist.renormalize()
        marginals[o] = marginal_dist

    return marginals
Ejemplo n.º 20
0
def forward_backward(all_possible_hidden_states, all_possible_observed_states,
                     prior_distribution, transition_model, observation_model,
                     observations):
    """
    Inputs
    ------
    all_possible_hidden_states: a list of possible hidden states

    all_possible_observed_states: a list of possible observed states

    prior_distribution: a distribution over states

    transition_model: a function that takes a hidden state and returns a
        Distribution for the next state

    observation_model: a function that takes a hidden state and returns a
        Distribution for the observation from that hidden state

    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of marginal distributions at each time step; each distribution
    should be encoded as a Distribution (see the Distribution class in
    robot.py and see how it is used in both robot.py and the function
    generate_data() above, and the i-th Distribution should correspond to time
    step i
    """

    num_time_steps = len(observations)
    marginals = [None] * num_time_steps

    alphas = []
    print "Calculating forward messages..."
    for i in range(num_time_steps - 1):
        X = robot.Distribution()
        for a in all_possible_hidden_states:
            msum = 0
            if observations[i] == None:
                for b in all_possible_hidden_states:
                    if i == 0:
                        msum += prior_distribution[b] * transition_model(b)[a]
                    else:
                        msum += alphas[i - 1][b] * transition_model(b)[a]
            else:
                for b in possible_states(observations[i]):
                    if i == 0:
                        msum += prior_distribution[b] * observation_model(b)[
                            observations[i]] * transition_model(b)[a]
                    else:
                        msum += alphas[i - 1][b] * observation_model(b)[
                            observations[i]] * transition_model(b)[a]
            X[a] = msum
        alphas.append(X)

    betas = []
    print "Calculating backward messages..."
    for i in range(num_time_steps - 1):
        X = robot.Distribution()
        for a in all_possible_hidden_states:
            msum = 0
            if observations[num_time_steps - 1 - i] is None:
                for b in all_possible_hidden_states:
                    if i == 0:
                        msum += transition_model(a)[b]
                    else:
                        msum += betas[i - 1][b] * transition_model(a)[b]
            else:
                for b in possible_states(observations[num_time_steps - 1 - i]):
                    if i == 0:
                        msum += observation_model(b)[observations[
                            num_time_steps - 1 - i]] * transition_model(a)[b]
                    else:
                        msum += betas[i - 1][b] * observation_model(b)[
                            observations[num_time_steps - 1 -
                                         i]] * transition_model(a)[b]
            X[a] = msum
        betas.append(X)
    betas = betas[::-1]

    for i in range(num_time_steps):
        X = robot.Distribution()
        for a in all_possible_hidden_states:
            if observations[i] is None:
                if i == 0:
                    X[a] = prior_distribution[a] * betas[i][a]
                elif i == num_time_steps - 1:
                    X[a] = alphas[i - 1][a]
                else:
                    X[a] = alphas[i][a] * betas[i][a]
            else:
                if i == 0:
                    X[a] = prior_distribution[a] * observation_model(a)[
                        observations[i]] * betas[i][a]
                elif i == num_time_steps - 1:
                    X[a] = alphas[i -
                                  1][a] * observation_model(a)[observations[i]]
                else:
                    X[a] = alphas[i][a] * observation_model(a)[
                        observations[i]] * betas[i][a]
        X.renormalize()
        marginals[i] = X

    return marginals
Ejemplo n.º 21
0
def Viterbi(all_possible_hidden_states, all_possible_observed_states,
            prior_distribution, transition_model, observation_model,
            observations):
    """
    Inputs
    ------
    See the list inputs for the function forward_backward() above.

    Output
    ------
    A list of esimated hidden states, each encoded as a tuple
    (<x>, <y>, <action>)
    """

    num_time_steps = len(observations)
    estimated_hidden_states = [None] * num_time_steps  # remove this

    messages = []
    tracebacks = []
    for i in range(num_time_steps - 1):
        X = robot.Distribution()
        Y = robot.Distribution()
        for a in all_possible_hidden_states:
            m_max = 0
            max_state = None

            if observations[i] is not None:
                for b in possible_states(observations[i]):
                    if i == 0:
                        temp = prior_distribution[b] * observation_model(b)[
                            observations[i]] * transition_model(b)[a]
                    else:
                        temp = messages[i - 1][b] * observation_model(b)[
                            observations[i]] * transition_model(b)[a]
                    if temp >= m_max:
                        m_max = temp
                        max_state = b
            else:
                for b in all_possible_hidden_states:
                    if i == 0:
                        temp = prior_distribution[b] * transition_model(b)[a]
                    else:
                        temp = messages[i - 1][b] * transition_model(b)[a]
                    if temp >= m_max:
                        m_max = temp
                        max_state = b

            X[a] = m_max
            Y[a] = max_state
        messages.append(X)
        tracebacks.append(Y)

    x_hat = None
    m_max = 0
    for a in all_possible_hidden_states:
        temp = messages[98][a] * observation_model(a)[observations[99]]
        if temp > m_max:
            m_max = temp
            x_hat = a
    estimated_hidden_states[99] = x_hat

    for i in range(num_time_steps - 2, -1, -1):
        x_hat = tracebacks[i][x_hat]
        estimated_hidden_states[i] = x_hat

    return estimated_hidden_states
def second_best(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of esimated hidden states, each encoded as a tuple
    (<x>, <y>, <action>)
    """

    # -------------------------------------------------------------------------
    # YOUR CODE GOES HERE
    #

    num_time_steps = len(observations)

    # Basically for each (possible) hidden state at time step i, we need to
    # keep track of the best previous hidden state AND the second best
    # previous hidden state--where we need to keep track of TWO back pointers
    # per (possible) hidden state at each time step!

    messages = []  # best values so far
    messages2 = []  # second-best values so far
    back_pointers = []  # per time step per hidden state, we now need
    # *two* back-pointers

    # -------------------------------------------------------------------------
    # Fold observations into singleton potentials
    #
    phis = []  # phis[n] is the singleton potential for node n
    for n in range(num_time_steps):
        potential = robot.Distribution()
        observed_state = observations[n]
        if n == 0:
            for hidden_state in prior_distribution:
                value = prior_distribution[hidden_state]
                if observed_state is not None:
                    value *= observation_model(hidden_state)[observed_state]
                if value > 0:  # only store entries with nonzero prob.
                    potential[hidden_state] = value
        else:
            for hidden_state in all_possible_hidden_states:
                if observed_state is None:
                    # singleton potential should be identically 1
                    potential[hidden_state] = 1.
                else:
                    value = observation_model(hidden_state)[observed_state]
                    if value > 0:  # only store entries with nonzero prob.
                        potential[hidden_state] = value
        phis.append(potential)

    # -------------------------------------------------------------------------
    # Forward pass
    #

    # handle initial time step differently
    initial_message = {}
    for hidden_state in prior_distribution:
        value = -careful_log(phis[0][hidden_state])
        if value < np.inf:  # only store entries with nonzero prob.
            initial_message[hidden_state] = value
    messages.append(initial_message)
    initial_message2 = {}  # there is no second-best option
    messages2.append(initial_message2)

    # rest of the time steps
    for n in range(1, num_time_steps):
        prev_message = messages[-1]
        prev_message2 = messages2[-1]
        new_message = {}
        new_message2 = {}
        new_back_pointers = {}  # need to store 2 per possible hidden state

        # only look at possible hidden states given observation
        for hidden_state in phis[n]:
            values = []
            # each entry in values will be a tuple of the form:
            # (<value>, <previous hidden state>,
            #  <which back pointer we followed>),
            # where <which back pointer we followed> is 0 (best back pointer)
            # or 1 (second-best back pointer)

            # iterate through best previous values
            for prev_hidden_state in prev_message:
                value = prev_message[prev_hidden_state] - \
                    careful_log(transition_model(prev_hidden_state)[
                        hidden_state]) - \
                    careful_log(phis[n][hidden_state])
                if value < np.inf:
                    # only store entries with nonzero prob.
                    values.append((value, prev_hidden_state, 0))

            # also iterate through second-best previous values
            for prev_hidden_state in prev_message2:
                value = prev_message2[prev_hidden_state] - \
                    careful_log(transition_model(prev_hidden_state)[
                        hidden_state]) - \
                    careful_log(phis[n][hidden_state])
                if value < np.inf:
                    # only store entries with nonzero prob.
                    values.append((value, prev_hidden_state, 1))

            if len(values) > 0:
                # this part could actually be sped up by not using a sorting
                # algorithm...
                sorted_values = sorted(values, key=lambda x: x[0])
                best_value, best_prev_hidden_state, which_back_pointer = \
                    sorted_values[0]

                # for the best value, the back pointer should *always* be 0,
                # meaning that we follow the best back pointer and not the
                # second best
                if len(values) > 1:
                    best_value2, best_prev_hidden_state2, which_back_pointer2\
                        = sorted_values[1]
                else:
                    best_value2 = np.inf
                    best_prev_hidden_state2 = None
                    which_back_pointer2 = None

                new_message[hidden_state] = best_value
                new_message2[hidden_state] = best_value2
                new_back_pointers[hidden_state] = \
                    ((best_prev_hidden_state, which_back_pointer),
                     (best_prev_hidden_state2, which_back_pointer2))

        messages.append(new_message)
        messages2.append(new_message2)
        back_pointers.append(new_back_pointers)

    # -------------------------------------------------------------------------
    # Backward pass (follow back-pointers)
    #

    # handle last time step differently
    values = []
    for hidden_state, value in messages[-1].items():
        values.append((value, hidden_state, 0))
    for hidden_state, value in messages2[-1].items():
        values.append((value, hidden_state, 1))

    divergence_time_step = -1

    if len(values) > 1:
        # this part could actually be sped up by not using a sorting
        # algorithm...
        sorted_values = sorted(values, key=lambda x: x[0])

        second_best_value, hidden_state, which_back_pointer = sorted_values[1]
        estimated_hidden_states = [hidden_state]

        # rest of the time steps
        for t in range(num_time_steps - 2, -1, -1):
            hidden_state, which_back_pointer = \
                back_pointers[t][hidden_state][which_back_pointer]
            estimated_hidden_states.insert(0, hidden_state)
    else:
        # this happens if there isn't a second best option, which should mean
        # that the only possible option (the MAP estimate) is the only
        # solution with 0 error
        estimated_hidden_states = [None] * num_time_steps

    return estimated_hidden_states
Ejemplo n.º 23
0
def forward_backward(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of marginal distributions at each time step; each distribution
    should be encoded as a Distribution (see the Distribution class in
    robot.py and see how it is used in both robot.py and the function
    generate_data() above, and the i-th Distribution should correspond to time
    step i
    """

    # -------------------------------------------------------------------------
    # YOUR CODE GOES HERE
    #
    num_time_steps = len(observations)
    #    forward_messages = [None] * num_time_steps
    #    forward_messages[0] = prior_distribution
    initial_dist = np.full(440, 1. / 440)
    transition = np.zeros((440, 440))
    obs_matrix = np.zeros((440, 96))
    forward_messages = np.zeros((num_time_steps, 440))

    backward_messages = np.zeros((num_time_steps, 440))
    backward_messages[num_time_steps - 1, :] = np.full(440, 1. / 440)

    for i, x in enumerate(all_possible_hidden_states):
        forward_messages[0,
                         i] = prior_distribution[all_possible_hidden_states[i]]
        for k, v in transition_model(x).items():
            transition[i, hidden_dict[k]] = v
        for k, v in observation_model(x).items():
            obs_matrix[i, obs_dict[k]] = v
    global trans_mat, emit_mat, observes
    trans_mat = transition
    emit_mat = obs_matrix
    observes = observations
    emission = []
    for i, obs in enumerate(observations[:-1]):

        if obs:
            emission = emit_mat[:, obs_dict[obs]]
        else:
            emission = np.ones(emit_mat[:, 1].shape)

        forward_messages[i +
                         1, :] = (emission * forward_messages[i]) @ trans_mat
        forward_messages[i + 1, :] = forward_messages[
            i + 1, :] / forward_messages[i + 1, :].sum()
    for i, obs in enumerate(observations[:0:-1]):
        if obs:
            emission = emit_mat[:, obs_dict[obs]]
        else:
            emission = np.ones(emit_mat[:, 1].shape)
        backward_messages[-(i + 2), :] = (
            emission * backward_messages[-(i + 1)]) @ trans_mat.T
        backward_messages[-(i + 2), :] = backward_messages[
            -(i + 2), :] / backward_messages[-(i + 2), :].sum()

    global alphas, betas
    alphas = forward_messages
    betas = backward_messages

    dist_list = []
    for i, obs in enumerate(observations):
        if obs:
            emission = emit_mat[:, obs_dict[obs]]
        else:
            emission = np.ones(emit_mat[:, 1].shape)

        marginal = alphas[i] * betas[i] * emission
        marginal = marginal / marginal.sum()
        temp_dist = robot.Distribution()
        for ind, val in enumerate(marginal):
            temp_dist[all_possible_hidden_states[ind]] = val
        dist_list.append(temp_dist)

    return dist_list
Ejemplo n.º 24
0
def forward_backward(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of marginal distributions at each time step; each distribution
    should be encoded as a Distribution (see the Distribution class in
    robot.py and see how it is used in both robot.py and the function
    generate_data() above, and the i-th Distribution should correspond to time
    step i
    """
    num_time_steps = len(observations)
    forward_messages = [None] * num_time_steps

    B = {}
    state_from_observation = {} #dictionary {observation: [state1, state2, ...]} - for each observation all states from which it can be observed
    for state in all_possible_hidden_states:
        model = observation_model(state)
        for obs in model.keys():
            if obs not in state_from_observation:
                state_from_observation[obs] = []
            state_from_observation[obs].append(state)
            B[(state, obs)] = model[obs] 
    #previous_states = {}
    next_states = {}
    A = {}
    for state in all_possible_hidden_states:
        transition_matrix = transition_model(state)
        if state not in next_states:
            next_states[state] = []
        for state_next in transition_matrix.keys():
            #if state_next not in previous_states:
            #    previous_states[state_next] = []
            #previous_states[state_next].append(state)
            next_states[state].append(state_next)
            A[(state, state_next)] = transition_matrix[state_next]

    #computing forward messages
    states_amount = len(all_possible_hidden_states)
    #forward_messages[0] = prior_distribution
    #forward_messages[0] = robot.Distribution()
    forward_messages[0] = prior_distribution
    for i in range(1, num_time_steps, 1):
        observation = observations[i-1]
        forward_messages[i] = robot.Distribution()
        if observation:
            for state_next in all_possible_hidden_states:
                for state_current in state_from_observation[observation]:
                    m = forward_messages[i-1].get(state_current,0) * A.get((state_current,state_next),0) * B.get((state_current, observation), 0)
                    if m > 0:               
                        forward_messages[i][state_next] += m
        else:
            for state_next in all_possible_hidden_states:
                for state_current in forward_messages[i-1].keys():
                    m = forward_messages[i-1].get(state_current,0) * A.get((state_current,state_next),0)
                    if m > 0:               
                        forward_messages[i][state_next] += m
        forward_messages[i].renormalize()
        #print i, forward_messages[i]

    backward_messages = [None] * num_time_steps
    backward_messages[num_time_steps-1] = robot.Distribution()
    for state in all_possible_hidden_states:
        backward_messages[num_time_steps-1][state] = 1./states_amount
    for i in range(num_time_steps-2, -1, -1):
        observation = observations[i+1]
        backward_messages[i] = robot.Distribution()
        if observation:
            for state_current in all_possible_hidden_states:
                for state_next in state_from_observation[observation]:
                    m = B.get((state_next, observation), 0) * A.get((state_current, state_next), 0) * backward_messages[i+1].get(state_next, 0)
                    if m > 0:
                        backward_messages[i][state_current] += m
        else:
             for state_current in all_possible_hidden_states:
                for state_next in backward_messages[i+1].keys():
                    m = A.get((state_current, state_next), 0) * backward_messages[i+1].get(state_next, 0)
                    if m > 0:
                        backward_messages[i][state_current] += m
        backward_messages[i].renormalize()
        #print observation, i, backward_messages[i]
    
    marginals = [None] * num_time_steps # remove this
    marginals[0] = robot.Distribution()
    for state in backward_messages[0]:
        m = backward_messages[0].get(state,0) * B.get((state, observations[0]), 0) * prior_distribution.get(state, 0)
        if m > 0:
            marginals[0][state] = m
    marginals[0].renormalize()
    
    marginals[num_time_steps-1] = robot.Distribution()
    observation = observations[num_time_steps-1]
    for state in forward_messages[num_time_steps-1]:
        if observation:
            m = forward_messages[num_time_steps-1].get(state,0) * B.get((state, observation), 0)
        else:
            m = forward_messages[num_time_steps-1].get(state,0)
        if m > 0:
            marginals[num_time_steps-1][state] = m
    marginals[num_time_steps-1].renormalize()
    
    for i in range(1, num_time_steps-1, 1):
        observation = observations[i]
        marginals[i] = robot.Distribution()
        if observation:
            for state in state_from_observation[observation]:
                m = B.get((state, observation), 0) * forward_messages[i].get(state,0) * backward_messages[i].get(state,0)
                if m > 0:
                    marginals[i][state] = m
        else:
            for state in backward_messages[i]:
                m = forward_messages[i].get(state,0) * backward_messages[i].get(state,0)
                if m > 0:
                    marginals[i][state] = m
        marginals[i].renormalize()
    
    #print observation_model((3,3,'stay'))
    #print transition_model((3,3,'stay'))
    #print observation_model((3,3,'up'))
    #print transition_model((3,3,'up'))

    return marginals
def forward_backward(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of marginal distributions at each time step; each distribution
    should be encoded as a Distribution (see the Distribution class in
    robot.py and see how it is used in both robot.py and the function
    generate_data() above, and the i-th Distribution should correspond to time
    step i
    """

    # -------------------------------------------------------------------------
    # YOUR CODE GOES HERE
    #

    num_time_steps = len(observations)
    forward_messages = [None] * num_time_steps
    forward_messages[0] = prior_distribution
    # TODO: Compute the forward messages


    for i in range(num_time_steps - 1):
        forward_messages[i+1] = robot.Distribution()
        if (observations[i] != None):
            current_obs = posterior_observed_matrix[observations[i]]

            dist_to_add = robot.Distribution()
            for tup in current_obs:
                key_a = [a for a, b in forward_messages[i].items() if a[0:2] == tup]
                if key_a != []:
                    for item in key_a:
                        new_prob = forward_messages[i][item] * current_obs[tup]
                        temp_dist = transition_model(item)
                        for k in temp_dist:
                            new_val = temp_dist[k] * new_prob
                            dist_to_add[k] += new_val
        else:
            dist_to_add = robot.Distribution()
            for tup in forward_messages[i]:
                temp_dist = transition_model(tup)
                for key in temp_dist:
                    dist_to_add[key] += temp_dist[key] * forward_messages[i][tup]

        forward_messages[i+1].update(dist_to_add)
        forward_messages[i+1].renormalize()



    #print ('complete')
    #print (forward_messages[3])
    backward_messages = [None] * num_time_steps
    backward_messages[-1] = robot.Distribution()

    for state in all_possible_hidden_states:
        backward_messages[-1][state] = 1.0 / len(all_possible_hidden_states)
    

    # Because there is no posterior_transition_model, I'm forced to 
    # either a) make one myself or b) fill out an entire transition
    # matrix just so I can transpose it. B is a tremendous waste of 
    # space but much faster to code, so I'm trying it.


    for i in reversed(range(num_time_steps - 1)):
        backward_messages[i] = robot.Distribution()
        if (observations[i+1] != None):
            next_obs = posterior_observed_matrix[observations[i+1]]

            dist_to_add = robot.Distribution()
            for tup in next_obs:
                key_a = [a for a, b in backward_messages[i+1].items() if a[0:2] == tup]
                if key_a != []:
                    for item in key_a:
                        new_prob = backward_messages[i+1][item] * next_obs[tup]
                        temp_dist = posterior_transition_matrix[item]
                        for k in temp_dist:
                            new_val = temp_dist[k] * new_prob
                            dist_to_add[k] += new_val
        else:
            dist_to_add = robot.Distribution()
            for tup in backward_messages[i+1]:
                temp_dist = posterior_transition_matrix[tup]
                for key in temp_dist:
                    dist_to_add[key] += temp_dist[key] * backward_messages[i+1][tup]

        backward_messages[i].update(dist_to_add)
        backward_messages[i].renormalize()

    #print (backward_messages[3])


    marginals = [None] * num_time_steps # remove this
    # TODO: Compute the marginals 
    for i in range(num_time_steps):

        marginals[i] = robot.Distribution()
        shared_keys = robot.Distribution()

        for key in forward_messages[i]:
            if (key in backward_messages[i]):
                shared_keys[key] = forward_messages[i][key] * backward_messages[i][key]
        
        if (observations[i] != None):
            current_obs = posterior_observed_matrix[observations[i]]
            for tup in current_obs:
                key_a = [a for a, b in shared_keys.items() if a[0:2] == tup]
                if key_a != []:
                    for item in key_a:
                        new_prob = current_obs[tup] * shared_keys[item]
                        marginals[i][item] = new_prob
        else:
            marginals[i].update(shared_keys)

        marginals[i].renormalize()
    return marginals
# - transition_model: a function that takes a hidden state and returns a
#     Distribution for the next state
# - observation_model: a function that takes a hidden state and returns a
#     Distribution for the observation from that hidden state
all_possible_hidden_states = robot.get_all_hidden_states()
all_possible_observed_states = robot.get_all_observed_states()
prior_distribution = robot.initial_distribution()
transition_model = robot.transition_model
observation_model = robot.observation_model

observed_matrix = {}

for state in all_possible_observed_states:
    x,y = state
    new_tuple = (x,y,'stay')
    observed_matrix[state] = robot.Distribution()
    observed_matrix[state] = observation_model(new_tuple)

posterior_observed_matrix = {}

for i in observed_matrix:
    for j in observed_matrix[i]:
        if (j not in posterior_observed_matrix):
            posterior_observed_matrix[j] = robot.Distribution()
        posterior_observed_matrix[j][i] = observed_matrix[i][j]

transition_matrix = {}

for state in all_possible_hidden_states:
    transition_matrix[state] = robot.Distribution()
    transition_matrix[state] = transition_model(state)
Ejemplo n.º 27
0
def Viterbi(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of esimated hidden states, each encoded as a tuple
    (<x>, <y>, <action>)
    """
    num_time_steps = len(observations)
    if num_time_steps == 1: return MAP_estimate(observations)

    estimated_hidden_states = [None] * num_time_steps

    # fold in observations
    phi = precompute_singleton_potentials(observations)

    # compute forward-messages
    forward_messages = [None] * (num_time_steps - 1)
    traceback_messages = [None] * (num_time_steps - 1)

    for time_step in range(num_time_steps - 1):
        forward_messages[time_step] = robot.Distribution()
        traceback_messages[time_step] = robot.Distribution()

        for goal_state in all_possible_hidden_states:
            min_val = np.inf
            argmin = None

            for current_state in phi[time_step]:
                current_val = \
                    phi[time_step][current_state] + \
                    -careful_log(transition_model(current_state)[goal_state])

                if time_step > 0:
                    current_val += forward_messages[time_step -
                                                    1][current_state]

                if current_val < min_val:
                    min_val = current_val
                    argmin = current_state

            forward_messages[time_step][goal_state] = min_val
            traceback_messages[time_step][goal_state] = argmin

    # compute maximum value at the root
    min_val = np.inf
    argmin = None

    for state in phi[num_time_steps - 1]:
        current_val = \
            phi[num_time_steps - 1][state] + \
            forward_messages[num_time_steps - 2][state]

        if current_val < min_val:
            min_val = current_val
            argmin = state

    estimated_hidden_states[num_time_steps - 1] = argmin

    # follow the traceback
    for time_step in range(num_time_steps - 2, -1, -1):
        estimated_hidden_states[time_step] = \
            traceback_messages[time_step][estimated_hidden_states[time_step + 1]]

    return estimated_hidden_states
def myneglog(pDist):
    pDist = pDist.copy()
    pOut = robot.Distribution()
    for key, val in pDist.items():
        pOut[key] = -1*careful_log(val)
    return pOut
Ejemplo n.º 29
0
def Viterbi(all_possible_hidden_states, all_possible_observed_states,
            prior_distribution, transition_model, observation_model,
            observations):

    num_time_steps = len(observations)

    noinfo = robot.Distribution()
    for k in all_possible_hidden_states:
        noinfo[k] = 1.0

    epyx = {}
    for y in all_possible_observed_states:
        epyx[y] = robot.Distribution()
        for x in all_possible_hidden_states:
            v = observation_model(x)[y]
            if v != 0:
                epyx[y][x] = v
        epyx[y].renormalize()

    phiprime = [None] * len(observations)
    phiprime[0] = robot.Distribution(prior_distribution.copy())
    for i in range(1, len(observations)):
        phiprime[i] = robot.Distribution(noinfo.copy())
    for i in range(len(observations)):
        if observations[i] != None:
            for k in noinfo:
                phiprime[i][k] = phiprime[i][k] * epyx[observations[i]][k]
            phiprime[i].renormalize()
    for i in range(len(observations)):
        for k in noinfo:
            if phiprime[i][k] == 0:
                del phiprime[i][k]

    num_time_steps = len(observations)
    forward_messages = [None] * num_time_steps
    table = [None] * num_time_steps
    for i in range(num_time_steps):
        forward_messages[i] = robot.Distribution()
        table[i] = robot.Distribution()
    forward_messages[0] = noinfo.copy()
    for i in range(1, num_time_steps):
        mf = robot.Distribution(forward_messages[i - 1].copy())
        for k in mf:
            mf[k] = mf[k] * phiprime[i - 1][k]  #fold
        for k in mf.keys():
            if mf[k] == 0:
                del mf[k]  #fold
        mf.renormalize()
        for k in mf:
            nexf = transition_model(k)
            for kn in nexf:
                if forward_messages[i].get(kn, 0) < nexf[kn] * mf[k]:
                    forward_messages[i][kn] = nexf[kn] * mf[k]
                    table[i][kn] = k
        forward_messages[i].renormalize()

    xt = robot.Distribution()
    for k in forward_messages[-1]:
        xt[k] = forward_messages[-1][k] * phiprime[-1].get(k, 0)

    xmap = []
    maxval = max(xt.values())
    for k in xt:
        if xt[k] == maxval:
            x = k
    xmap.append(x)

    for i in range(1, num_time_steps):
        j = num_time_steps - i
        xpre = table[j][xmap[-1]]
        xmap.append(xpre)

    xmap.reverse()

    estimated_hidden_states = xmap

    return estimated_hidden_states
def forward_backward(observations):
    """
    Input
    -----
    observations: a list of observations, one per hidden state
        (a missing observation is encoded as None)

    Output
    ------
    A list of marginal distributions at each time step; each distribution
    should be encoded as a Distribution (see the Distribution class in
    robot.py and see how it is used in both robot.py and the function
    generate_data() above, and the i-th Distribution should correspond to time
    step i
    """

    # -------------------------------------------------------------------------
    # YOUR CODE GOES HERE
    #

    num_time_steps = len(observations)
    # forward_messages[i] is P([state at i] and y's before i)
    forward_messages = [prior_distribution]
    for t in range(num_time_steps - 1):
        # Incorporate the t-th observation.
        if observations[t] is not None:
            prob_given_y = robot.Distribution()
            for state, prob in forward_messages[t].items():
                prob_given_y[state] \
                    = prob * observation_model(state)[observations[t]]
            prob_given_y.renormalize()
        else:
            prob_given_y = forward_messages[t]

        # Take a step forward in time, using the transition model.
        next_dist = robot.Distribution()
        for state, prob in prob_given_y.items():
            for new_state, trans_prob in transition_model(state).items():
                next_dist[new_state] += prob * trans_prob
        next_dist.renormalize()
        forward_messages.append(next_dist)

    # Make the reverse transition dictionary, to make backward messages
    # easier.
    backwards_transitions = collections.defaultdict(robot.Distribution)
    for state_1 in all_possible_hidden_states:
        for state_2, prob in transition_model(state_1).items():
            backwards_transitions[state_2][state_1] += prob

    # backward messages[i] is P(y's after i | state at i)
    backward_messages = [None] * num_time_steps
    uniform = robot.Distribution()
    for s in all_possible_hidden_states:
        uniform[s] = 1
    uniform.renormalize()
    backward_messages[-1] = uniform
    for t in range(num_time_steps - 1, 0, -1):
        if observations[t] is not None:
            prob_given_y = robot.Distribution()
            for state, prob in backward_messages[t].items():
                prob_given_y[state] = prob * \
                    observation_model(state)[observations[t]]
            prob_given_y.renormalize()
        else:
            prob_given_y = backward_messages[t]

        prev_dist = robot.Distribution()
        for state, prob in prob_given_y.items():
            for past_state, trans_prob in backwards_transitions[state].items():
                prev_dist[past_state] += prob * trans_prob
        prev_dist.renormalize()
        backward_messages[t - 1] = prev_dist

    # Finally, compute marginals.
    marginals = []
    for t in range(num_time_steps):
        marginal_t = robot.Distribution()
        for state in all_possible_hidden_states:
            product = forward_messages[t][state] * backward_messages[t][state]
            if observations[t] is not None:
                product *= observation_model(state)[observations[t]]
            if product > 0:
                marginal_t[state] = product
        marginal_t.renormalize()
        marginals.append(marginal_t)

    return marginals