def sample_global(self, global_state, variable, allowed_values): ''' This method can be used to sample from the density according to a global state containing values for all other variables that this node belongs to. @param global_state: A Dict (node -> value) that must hold a value for all variables that this density depends on. Except for the variable that it is directly associated with. @param variable: The variable that this density is directly associated with. @param allowed_values: A list of values that are allowed to be sampled. This is necessary because external evidence may restrict the value range. @returns: The sampled value. ''' node_value_pairs=[(node,global_state[node]) for node in self.variables if node != variable] probabilities=[self.get_probability(node_value_pairs+[(variable,value)]) for value in allowed_values] idx=weighted_random(probabilities) return allowed_values[idx]
def weighted_sample(network, evidence = {}): ''' Each nonevidence variable is sampled according to the conditional distribution given the values already sampled for the variable's parents, while a weight isaccumulated based on the likelihood for each evidence variable. See "Artificial Intelligence: A Modern Approach (Third edition)" by Stuart Russell and Peter Norvig (p. 534) Keyword arguments: network -- a Bayesian network evidence -- a dict of observed values Returns a new sample as tuple of state and weight (state, w). ''' w = 1.0 state = {} if not isinstance(network, primo.networks.BayesianNetwork): raise Exception("The given network is not an instance of BayesNet.") nodes = network.get_nodes_in_topological_sort() for node in nodes: #reduce this node's cpd parents = network.get_parents(node) if parents: evidence_tmp = [(parent, state[parent]) for parent in parents] reduced_cpd = node.get_cpd_reduced(evidence_tmp) else: reduced_cpd = node.get_cpd() # (re-)calulate weight if node in evidence: w *= reduced_cpd.get_table()[node.get_value_range().index(evidence[node])] state[node] = node.get_value_range().index(evidence[node]) else: # sample state new_state = weighted_random(reduced_cpd.get_table()) state[node] = node.get_value_range()[new_state] return (state, w)
def transition(self, network, state, extern_evidence): ''' Does one single state transition. @param network: A BayesNet. @param state: The current state of the BayesNet. Given as a Dict from RandomNode to Value @param extern_evidence: Evidence that is given by the user. This is a Dict from Node to Evidence. ''' nodes = network.get_nodes([]) nodes_to_resample = [ n for n in nodes if not n in extern_evidence.keys() or extern_evidence[n].get_unique_value() == None ] for node in nodes_to_resample: parents = network.get_parents(node) if parents: evidence = [(parent, state[parent]) for parent in parents] reduced_cpd = node.get_cpd_reduced(evidence) else: reduced_cpd = node.get_cpd() #reduce the children's cpds children = network.get_children(node) for child in children: #reduce this node's cpd parents = network.get_parents(child) evidence = [(parent, state[parent]) for parent in parents if parent != node] evidence.append((child, state[child])) reduced_child_cpd = child.get_cpd_reduced(evidence) reduced_cpd = reduced_cpd.multiplication(reduced_child_cpd) new_state = weighted_random(reduced_cpd.get_table()) state[node] = node.get_value_range()[new_state] return state
def sample_global(self, global_state, variable, allowed_values): ''' This method can be used to sample from the density according to a global state containing values for all other variables that this node belongs to. @param global_state: A Dict (node -> value) that must hold a value for all variables that this density depends on. Except for the variable that it is directly associated with. @param variable: The variable that this density is directly associated with. @param allowed_values: A list of values that are allowed to be sampled. This is necessary because external evidence may restrict the value range. @returns: The sampled value. ''' node_value_pairs = [(node, global_state[node]) for node in self.variables if node != variable] probabilities = [ self.get_probability(node_value_pairs + [(variable, value)]) for value in allowed_values ] idx = weighted_random(probabilities) return allowed_values[idx]
def transition(self, network, state, extern_evidence): ''' Does one single state transition. @param network: A BayesNet. @param state: The current state of the BayesNet. Given as a Dict from RandomNode to Value @param extern_evidence: Evidence that is given by the user. This is a Dict from Node to Evidence. ''' nodes = network.get_nodes([]) nodes_to_resample=[n for n in nodes if not n in extern_evidence.keys() or extern_evidence[n].get_unique_value() == None] for node in nodes_to_resample: parents=network.get_parents(node) if parents: evidence=[(parent,state[parent]) for parent in parents] reduced_cpd = node.get_cpd_reduced(evidence) else: reduced_cpd = node.get_cpd() #reduce the children's cpds children = network.get_children(node) for child in children: #reduce this node's cpd parents=network.get_parents(child) evidence=[(parent,state[parent]) for parent in parents if parent != node] evidence.append((child,state[child])) reduced_child_cpd = child.get_cpd_reduced(evidence) reduced_cpd = reduced_cpd.multiplication(reduced_child_cpd) new_state=weighted_random(reduced_cpd.get_table()) state[node]=node.get_value_range()[new_state] return state