def query_prob(self, query): """ Queries the probability distribution encoded in the Bayesian Network, given a set of query variables, and some evidence. :param query: the full query result :return: the corresponding multivariate table failed """ network = query.get_network() query_vars = set(query.get_query_vars()) evidence = query.get_evidence() full_joint = NaiveInference.get_full_joint(network, False) # TODO: Do I have to use TreeMap(Java) like data-structure? ... OrderedDict is not same with TreeMap query_values = OrderedDict() for node in network.get_chance_nodes(): if node.get_id() in query_vars: query_values[node.get_id()] = node.get_values() query_assignments = InferenceUtils.get_all_combinations(query_values) query_result = MultivariateTableBuilder() for query_assignment in query_assignments: sum = 0. for assignment in full_joint.keys(): if assignment.contains( query_assignment) and assignment.contains(evidence): sum += full_joint[assignment] query_result.add_row(query_assignment, sum) query_result.normalize() return query_result.build()
def get_ranking(self, input, min_diff): """ Returns the ranking of the given input sorted by utility :param input: the input to rank :param min_diff: the minimum difference between utilities :return: the rank of the given assignment in the utility table """ return InferenceUtils.get_ranking(self.get_table(), input, min_diff)
def get_n_best(self, n_best): """ Creates a table with a subset of the utility values, namely the N-best highest ones. :param n_best: the number of values to keep in the filtered table :return: the table of values, of size nbest """ filtered_table = InferenceUtils.get_n_best(self.get_table(), n_best) return UtilityTable(filtered_table)
def get_n_best(self, n_best): """ Returns a subset of the N values in the table with the highest probability. :param n_best: the number of values to select :return: the distribution with the subset of values """ return MultivariateTable( self._head_vars, InferenceUtils.get_n_best(self._table, n_best))
def __str__(self): """ Returns a string representation for the distribution :return: the string representation for the table. """ sorted_table = InferenceUtils.get_n_best(self.get_table(), len(self._table)) result = [] for key, value in sorted_table.items(): result.append('U(%s):=%f\n' % (str(key), value)) return ''.join(result)[:-1] if len(result) > 0 else ''
def __str__(self): """ Returns a string representation of the probability table :return: the string representation """ sorted_table = InferenceUtils.get_n_best(self._table, max(len(self._table), 1)) result = [] for key, value in sorted_table.items(): result.append('P(%s):=%f\n' % (str(key), value)) return ''.join(result)[:-1] if len(result) > 0 else ''
def prune_values(self, threshold): """ Prunes all table values that have a probability lower than the threshold. :param threshold: the threshold :return: true if at least one value has been pruned, false otherwise """ new_table = dict() changed = False for key in self._table.keys(): prob = self._table[key] if prob >= threshold: new_table[key] = prob else: changed = True if changed: InferenceUtils.normalize(new_table) self._table = new_table self._intervals = None return changed
def __str__(self): """ Returns a string representation of the probability table :return: the string representation """ sorted_table = InferenceUtils.get_n_best(self._table, max(len(self._table), 1)) result = '' for key, value in sorted_table.items(): result += 'P(%s=%s):=%f\n' % (self._variable, key, value) return result[:-1] if len(result) > 0 else result
def linearize(self): """ Extracts all alternative assignments of values for the variables in the range. This operation can be computational expensive, use with caution. :return: the set of alternative assignments """ if len(self._range) == 1: item_key = list(self._range.keys())[0] result = set() for item_value in self._range[item_key]: result.add(Assignment(item_key, item_value)) return result return InferenceUtils.get_all_combinations(self._range)
def get_n_best(self, n_best): """ Returns a subset of the N values in the table with the highest probability. :param n_best: the number of values to select :return: the distribution with the subset of values """ n_table = InferenceUtils.get_n_best(self._table, n_best) from bn.distribs.distribution_builder import CategoricalTableBuilder builder = CategoricalTableBuilder(self._variable) for v in n_table.keys(): builder.add_row(v, n_table[v]) return builder.build().to_discrete()
def query_util(self, query): """ Computes the utility distribution for the Bayesian network, depending on the value of the action variables given as parameters. :param query: the full query :return: the corresponding utility table """ network = query.get_network() query_vars = set(query.get_query_vars()) evidence = query.get_evidence() full_joint = NaiveInference.get_full_joint(network, True) # TODO: Do I have to use TreeMap(Java) like data-structure? ... OrderedDict is not same with TreeMap action_values = OrderedDict() for node in network.get_nodes(): if node.get_id() in query_vars: action_values[node.get_id()] = node.get_values() action_assignments = InferenceUtils.get_all_combinations(action_values) table = UtilityTable() for action_assignment in action_assignments: total_utility = 0. total_prob = 0. for joint_assignment in full_joint.keys(): if not joint_assignment.contains(evidence): continue total_utility_for_assignment = 0. state_and_action_assignment = Assignment( [joint_assignment, action_assignment]) for value_node in network.get_utility_nodes(): utility = value_node.get_utility( state_and_action_assignment) total_utility_for_assignment += utility total_utility += (total_utility_for_assignment * full_joint.get(joint_assignment)) total_prob += full_joint.get(joint_assignment) table.set_util(action_assignment, total_utility / total_prob) return table
def reduce(self, query): """ Reduces the Bayesian network to a subset of its variables. This reduction operates here by generating the possible conditional assignments for every retained variables, and calculating the distribution for each assignment. :param query: the reduction query :return: the reduced network """ network = query.get_network() query_vars = set(query.get_query_vars()) evidence = query.get_evidence() original_sorted_node_ids = network.get_sorted_node_ids() sorted_node_ids = list() for node_id in original_sorted_node_ids: if node_id in query_vars: sorted_node_ids.append(node_id) sorted_node_ids = list(reversed(sorted_node_ids)) reduced_network = BNetwork() for variable_id in sorted_node_ids: direct_ancestors = network.get_node(variable_id).get_ancestor_ids( query_vars) input_values = dict() for direct_ancestor in direct_ancestors: input_values[direct_ancestor] = network.get_node( variable_id).get_values() assignments = InferenceUtils.get_all_combinations(input_values) builder = ConditionalTableBuilder(variable_id) for assignment in assignments: new_evidence = Assignment([evidence, assignment]) result = self.query_prob(network, variable_id, new_evidence) builder.add_rows(assignment, result.get_table()) chance_node = ChanceNode(variable_id, builder.build()) for ancestor in direct_ancestors: chance_node.add_input_node(reduced_network.get_node(ancestor)) reduced_network.add_node(chance_node) return reduced_network
def generate_xml(self): """ Generates the XML representation for the table, for the document doc. :param doc: the XML document for which to generate the XML. :return: XML reprensetation """ var = Element("variable") var.set("id", self._variable.replace("'", "")) for v in InferenceUtils.get_n_best(self._table, len(self._table)).keys(): if v != ValueFactory.none(): value_node = Element("value") if self._table[v] < 0.99: value_node.set("prob", StringUtils.get_short_form(self._table[v])) value_node.text = str(v) var.append(value_node) return var
def get_values_linearise(self): """ Calculates the possible values for the output distribution via linearisation (more costly operation, but necessary in case of add effects). :return: the set of possible output values """ table = dict() for i in range(len(self._input_rules)): table[str(i)] = self._input_rules[i].get_effects() combinations = InferenceUtils.get_all_combinations(table) values = set() for cond in combinations: values.update(self.get_prob_distrib(cond).get_values()) if len(values) == 0: values.add(ValueFactory.none()) return values
def get_full_joint(network, include_actions): """ Computes the full joint probability distribution for the Bayesian Network :param network: the Bayesian network :param include_actions: whether to include action nodes or not :return: the resulting joint distribution """ # TODO: Do I have to use TreeMap(Java) like data-structure? ... OrderedDict is not same with TreeMap all_values = OrderedDict() for chance_node in network.get_chance_nodes(): all_values[chance_node.get_id()] = chance_node.get_values() if include_actions: for action_node in network.get_action_nodes(): all_values[action_node.get_id()] = action_node.get_values() full_assignments = InferenceUtils.get_all_combinations(all_values) result = dict() for assignment in full_assignments: joint_log_prob = 0. for chance_node in network.get_chance_nodes(): trimmed_condition = assignment.get_trimmed( chance_node.get_input_node_ids()) joint_log_prob += math.log10( chance_node.get_prob( trimmed_condition, assignment.get_value(chance_node.get_id()))) if include_actions: for action_node in network.get_action_nodes(): joint_log_prob += math.log10( action_node.get_prob( assignment.get_value(action_node.get_id()))) result[assignment] = pow(10, joint_log_prob) return result