Source code for mrftools.BruteForce

"""BruteForce class for exact inference of marginals and maximizing states."""
import itertools
import operator

import numpy as np


[docs]class BruteForce(object): """ Object that can do inference via ugly brute force. Recommended only for sanity checking and debugging using tiny examples. """ def __init__(self, markov_net): """ Initialize the brute force inference object for markov_net. :param markov_net: Markov net describing the probability distribution :type markov_net: MarkovNet """ self.mn = markov_net self.varBeliefs = dict() self.pairBeliefs = dict()
[docs] def compute_z(self): """ Compute the partition function by explicitly summing energy of all possible states. This is extremely expensive for anything but tiny Markov nets. :return: the partition function (normalizing constant) of the distribution :rtype: float """ z = 0.0 variables = list(self.mn.variables) num_states = [self.mn.num_states[var] for var in variables] arg_list = [range(s) for s in num_states] for state_list in itertools.product(*arg_list): states = dict() for i in range(len(variables)): states[variables[i]] = state_list[i] z += np.exp(self.mn.evaluate_state(states)) return z
[docs] def entropy(self): """ Compute the entropy of the distribution by explicitly accounting for every possible state. :return: entropy :rtype: float """ z = self.compute_z() log_z = np.log(z) h = 0.0 variables = list(self.mn.variables) num_states = [self.mn.num_states[var] for var in variables] arg_list = [range(s) for s in num_states] for state_list in itertools.product(*arg_list): states = dict() for i in range(len(variables)): states[variables[i]] = state_list[i] log_p = self.mn.evaluate_state(states) h -= (log_p - log_z) * np.exp(log_p - log_z) return h
[docs] def unary_marginal(self, var): """ Compute the marginal probabilities of a variable. :param var: variable whose marginals will be computed :type var: object :return: vector of marginal probabilities for var :rtype: array """ variables = list(self.mn.variables) num_states = [self.mn.num_states[v] for v in variables] p = np.zeros(self.mn.num_states[var]) arg_list = [range(s) for s in num_states] for state_list in itertools.product(*arg_list): states = dict() for i in range(len(variables)): states[variables[i]] = state_list[i] p[states[var]] += np.exp(self.mn.evaluate_state(states)) return p / np.sum(p)
[docs] def pairwise_marginal(self, var_i, var_j): """ Compute the joint marginal probabilities between two variables. :param var_i: first variable to marginalize over :type var_i: object :param var_j: second variable to marginalize over :type var_j: object :return: matrix representing the marginal probabilities of the two variables :rtype: ndarray """ variables = list(self.mn.variables) num_states = [self.mn.num_states[v] for v in variables] p = np.zeros((self.mn.num_states[var_i], self.mn.num_states[var_j])) arg_list = [range(s) for s in num_states] for state_list in itertools.product(*arg_list): states = dict() for i in range(len(variables)): states[variables[i]] = state_list[i] p[states[var_i], states[var_j]] += np.exp(self.mn.evaluate_state(states)) return p / np.sum(p)
[docs] def map_inference(self): """ Compute most probable state configurations, i.e., maximum a posteriori (MAP) inference by explicitly trying every possible state. :return: a matrix of one-hot indicator vectors for the maximizing states of all variables :rtype: ndarray """ variables = list(self.mn.variables) num_states = [self.mn.num_states[v] for v in variables] arg_list = [range(s) for s in num_states] map_dic = {} for state_list in itertools.product(*arg_list): states = dict() for i in range(len(variables)): states[variables[i]] = state_list[i] map_dic[state_list] = np.exp(self.mn.evaluate_state(states)) map_results = max(map_dic.items(), key=operator.itemgetter(1)) map_values = map_results[1] map_states = map_results[0] belief_mat = -np.inf * np.ones((max(num_states), len(variables))) for i in range(0, len(map_states)): belief_mat[map_states[i], i] = 0 # print belief_mat return belief_mat