def query(self, **kwds): # Ensure the evidence variables are actually # present invalid_vars = [v for v in kwds.keys() if v not in self.nodes] if invalid_vars: raise VariableNotInGraphError(invalid_vars) mu, sigma = self.get_joint_parameters() # Iteratively apply the evidence... result = dict() result['evidence'] = kwds for k, v in kwds.items(): x = MeansVector([[v]], names=[k]) sigma_yy, sigma_yx, sigma_xy, sigma_xx = (sigma.split(k)) mu_y, mu_x = mu.split(k) # See equations (6) and (7) of CK mu_y_given_x = MeansVector( (mu_y + sigma_yx * sigma_xx.I * (x - mu_x)).rows, names=mu_y.name_ordering) sigma_y_given_x = CovarianceMatrix( (sigma_yy - sigma_yx * sigma_xx.I * sigma_xy).rows, names=sigma_yy.name_ordering) sigma = sigma_y_given_x mu = mu_y_given_x result['joint'] = dict(mu=mu, sigma=sigma) return result
def test_get_joint_parameters(self, river_graph): mu, sigma = river_graph.get_joint_parameters() assert mu == MeansVector([[3], [4], [9], [14]], names=['a', 'b', 'c', 'd']) assert sigma == CovarianceMatrix( [[4, 4, 8, 12], [4, 5, 8, 13], [8, 8, 20, 28], [12, 13, 28, 42]], names=['a', 'b', 'c', 'd'])
def test_query(self, river_graph): result = river_graph.query(a=7) mu = result['joint']['mu'] sigma = result['joint']['sigma'] assert mu == MeansVector([[8], [17], [26]], names=['b', 'c', 'd']) assert sigma == CovarianceMatrix([[1, 0, 1], [0, 4, 4], [1, 4, 6]], names=['b', 'c', 'd']) result = river_graph.query(a=7, c=17) mu = result['joint']['mu'] sigma = result['joint']['sigma'] assert mu == MeansVector([[8], [26]], names=['b', 'd']) assert sigma == CovarianceMatrix([[1, 1], [1, 2]], names=['b', 'd']) result = river_graph.query(a=7, c=17, b=8) mu = result['joint']['mu'] sigma = result['joint']['sigma'] assert mu == MeansVector([[26]], names=['d']) assert sigma == CovarianceMatrix([[1]], names=['d'])
def build_gbn(*args, **kwds): '''Builds a Gaussian Bayesian Graph from a list of functions''' variables = set() name = kwds.get('name') variable_nodes = dict() factor_nodes = dict() if isinstance(args[0], list): # Assume the functions were all # passed in a list in the first # argument. This makes it possible # to build very large graphs with # more than 255 functions, since # Python functions are limited to # 255 arguments. args = args[0] for factor in args: factor_args = get_args(factor) variables.update(factor_args) node = GBNNode(factor) factor_nodes[factor.__name__] = node # Now lets create the connections # To do this we need to find the # factor node representing the variables # in a child factors argument and connect # it to the child node. # Note that calling original_factors # here can break build_gbn if the # factors do not correctly represent # a valid network. This will be fixed # in next release original_factors = get_original_factors(factor_nodes.values()) for var_name, factor in original_factors.items(): factor.variable_name = var_name for factor_node in factor_nodes.values(): factor_args = get_args(factor_node) parents = [ original_factors[arg] for arg in factor_args if original_factors[arg] != factor_node ] for parent in parents: connect(parent, factor_node) # Now process the raw_betas to create a dict for factor_node in factor_nodes.values(): # Now we want betas to always be a dict # but in the case that the node only # has one parent we will allow the user to specify # the single beta for that parent simply # as a number and not a dict. if hasattr(factor_node.func, 'raw_betas'): if isinstance(factor_node.func.raw_betas, Number): # Make sure that if they supply a number # there is only one parent assert len(get_args(factor_node)) == 2 betas = dict() for arg in get_args(factor_node): if arg != factor_node.variable_name: betas[arg] = factor_node.func.raw_betas factor_node.func.betas = betas else: factor_node.func.betas = factor_node.func.raw_betas gbn = GaussianBayesianGraph(original_factors, name=name) # Now for any conditional gaussian nodes # we need to tell the node function what the # parent parameters are so that the pdf can # be computed. sorted = gbn.get_topological_sort() joint_mu, joint_sigma = gbn.get_joint_parameters() for node in sorted: if hasattr(node.func, 'betas'): # This means its multivariate gaussian names = [n.variable_name for n in node.parents] + [node.variable_name] node.func.joint_mu = MeansVector.zeros((len(names), 1), names=names) for name in names: node.func.joint_mu[name] = joint_mu[name][0, 0] node.func.covariance_matrix = CovarianceMatrix.zeros( (len(names), len(names)), names) for row, col in xproduct(names, names): node.func.covariance_matrix[row, col] = joint_sigma[row, col] return gbn
def build_gbn(*args, **kwds): '''Builds a Gaussian Bayesian Graph from a list of functions''' variables = set() name = kwds.get('name') variable_nodes = dict() factor_nodes = dict() if isinstance(args[0], list): # Assume the functions were all # passed in a list in the first # argument. This makes it possible # to build very large graphs with # more than 255 functions, since # Python functions are limited to # 255 arguments. args = args[0] for factor in args: factor_args = get_args(factor) variables.update(factor_args) node = GBNNode(factor) factor_nodes[factor.__name__] = node # Now lets create the connections # To do this we need to find the # factor node representing the variables # in a child factors argument and connect # it to the child node. # Note that calling original_factors # here can break build_gbn if the # factors do not correctly represent # a valid network. This will be fixed # in next release original_factors = get_original_factors(list(factor_nodes.values())) for var_name, factor in list(original_factors.items()): factor.variable_name = var_name for factor_node in list(factor_nodes.values()): factor_args = get_args(factor_node) parents = [original_factors[arg] for arg in factor_args if original_factors[arg] != factor_node] for parent in parents: connect(parent, factor_node) # Now process the raw_betas to create a dict for factor_node in list(factor_nodes.values()): # Now we want betas to always be a dict # but in the case that the node only # has one parent we will allow the user to specify # the single beta for that parent simply # as a number and not a dict. if hasattr(factor_node.func, 'raw_betas'): if isinstance(factor_node.func.raw_betas, Number): # Make sure that if they supply a number # there is only one parent assert len(get_args(factor_node)) == 2 betas = dict() for arg in get_args(factor_node): if arg != factor_node.variable_name: betas[arg] = factor_node.func.raw_betas factor_node.func.betas = betas else: factor_node.func.betas = factor_node.func.raw_betas gbn = GaussianBayesianGraph(original_factors, name=name) # Now for any conditional gaussian nodes # we need to tell the node function what the # parent parameters are so that the pdf can # be computed. sorted = gbn.get_topological_sort() joint_mu, joint_sigma = gbn.get_joint_parameters() for node in sorted: if hasattr(node.func, 'betas'): # This means its multivariate gaussian names = [n.variable_name for n in node.parents] + [node.variable_name] node.func.joint_mu = MeansVector.zeros((len(names), 1), names=names) for name in names: node.func.joint_mu[name] = joint_mu[name][0, 0] node.func.covariance_matrix = CovarianceMatrix.zeros( (len(names), len(names)), names) for row, col in xproduct(names, names): node.func.covariance_matrix[row, col] = joint_sigma[row, col] return gbn
def test_assignment_of_joint_parameters(self, river_graph): assert river_graph.nodes['b'].func.joint_mu == MeansVector( [[3], [4]], names=['a', 'b']) assert river_graph.nodes[ 'b'].func.covariance_matrix == CovarianceMatrix([[4, 4], [4, 5]], names=['a', 'b'])