def test_table_expansion(self): bn = NetworkExamples.construct_basic_network() builder = CategoricalTableBuilder("HouseSize") builder.add_row(ValueFactory.create("Small"), 0.7) builder.add_row(ValueFactory.create("Big"), 0.2) builder.add_row(ValueFactory.create("None"), 0.1) node = ChanceNode("HouseSize", builder.build()) bn.add_node(node) bn.get_node("Burglary").add_input_node(node) assert bn.get_chance_node("Burglary").get_prob( Assignment(["HouseSize", "Small"]), ValueFactory.create(True)) == pytest.approx(0.001, abs=0.0001) assert bn.get_chance_node("Burglary").get_prob( Assignment(["HouseSize", "Big"]), ValueFactory.create(True)) == pytest.approx(0.001, abs=0.0001) bn.get_node("Alarm").add_input_node(node) assert bn.get_chance_node("Alarm").get_prob( Assignment(["Burglary", "Earthquake"]), ValueFactory.create(True)) == pytest.approx(0.95, abs=0.0001) assert bn.get_chance_node("Alarm").get_prob( Assignment(Assignment(["Burglary", "Earthquake"]), "HouseSize", ValueFactory.create("None")), ValueFactory.create(True)) == pytest.approx(0.95, abs=0.0001)
def system_utility_simulation(simulation_action_node_id, state): simulation_action_node_id += "'" negotiation_state = state.get_chance_node( 'negotiation_state').sample().get_value() u_u = str(state.get_chance_node('u_u_sim').get_distrib().get_best()) u_m = str(state.get_chance_node('u_m_sim').get_distrib().get_best()) current_step = str( state.get_chance_node('current_step').get_distrib().get_best()) utility_table = UtilityTable() if current_step == 'Negotiation' and ("selection" in u_u or "selection" in u_m): # selection: compute reward choice_system, _ = negotiation_state.system_model.selection( negotiation_state.system_model, negotiation_state.system_ctx) choice_user, _ = negotiation_state.user_model.selection( negotiation_state.user_model, negotiation_state.user_ctx) reward = compute_reward(negotiation_state.system_ctx, choice_user, choice_system) utility_table.set_util(Assignment('current_step', 'Terminated'), 1e-3) utility_table.set_util( Assignment(simulation_action_node_id, 'terminated'), reward) elif current_step == 'Negotiation': # general negotiation action_infos = negotiation_state.system_model.generate_action_set( negotiation_state.action_num) for sentence, lang_h, lang_hs, words in action_infos: sentence_assignment = Assignment(simulation_action_node_id, sentence) utility_table.set_util(Assignment(sentence_assignment), 1e-3) utility_table.set_custom_utility(action_infos, apply_changes_func, rollback_changes_func) return utility_table
def perform_turn(self, system_action): """ Performs the dialogue turn in the simulator. :param system_action: the last system action. """ with self._lock: turn_performed = False self.simulator_state.set_parameters(self.domain.get_parameters()) system_assign = Assignment(self.system.get_settings().system_output, system_action) self.simulator_state.add_to_state(system_assign) while len(self.simulator_state.get_new_variables()) > 0: to_process = self.simulator_state.get_new_variables() self.simulator_state.reduce() for model in self.domain.get_models(): if model.is_triggered(self.simulator_state, to_process): change = model.trigger(self.simulator_state) if change and model.is_blocking(): break if len(self.simulator_state.get_utility_node_ids()) > 0: reward = self.simulator_state.query_util() comment = 'Reward: ' + StringUtils.get_short_form(reward) self.system.display_comment(comment) self.system.get_state().add_evidence(Assignment('R(' + system_assign.add_primes() + ')', reward)) self.simulator_state.remove_nodes(self.simulator_state.get_utility_node_ids()) if self.add_new_observations(): turn_performed = True self.simulator_state.add_evidence(self.simulator_state.get_sample()) return turn_performed
def get_observations(self, state): """ Returns the possible observations that are expected to be perceived from the dialogue state :param state: the dialogue state from which to extract observations :return: the inferred observations """ prediction_nodes = set() for node_id in state.get_chance_node_ids(): if "^p" in node_id: prediction_nodes.add(node_id) # intermediary observations for node_id in prediction_nodes: if state.get_chance_node(node_id).has_descendant(prediction_nodes): prediction_nodes.remove(node_id) builder = MultivariateTableBuilder() if len(prediction_nodes) != 0: observations = state.query_prob(prediction_nodes) for a in observations.get_values(): new_a = Assignment() for var in a.get_variables(): new_a.add_pair(var.replace("^p", ""), a.get_value(var)) builder.add_row(new_a, observations.get_prob(a)) return builder.build()
def test_build_basic_network(self): bn = NetworkExamples.construct_basic_network() assert len(bn.get_nodes()) == 8 assert len(bn.get_node("Burglary").get_output_nodes()) == 3 assert len(bn.get_node("Alarm").get_output_nodes()) == 2 assert len(bn.get_node("Alarm").get_input_nodes()) == 2 assert len(bn.get_node("Util1").get_input_nodes()) == 2 assert len(bn.get_node("Burglary").get_values()) == 2 assert len(bn.get_node("Alarm").get_values()) == 2 assert len(bn.get_node("MaryCalls").get_values()) == 2 assert ValueFactory.create(True) in bn.get_node( "Burglary").get_values() assert bn.get_chance_node("Burglary").get_prob( ValueFactory.create(True)) == pytest.approx(0.001, abs=0.0001) assert bn.get_chance_node("Alarm").get_prob( Assignment(["Burglary", "Earthquake"]), ValueFactory.create(True)) == pytest.approx(0.95, abs=0.0001) assert bn.get_chance_node("JohnCalls").get_prob( Assignment("Alarm"), ValueFactory.create(True)) == pytest.approx(0.9, abs=0.0001) assert len(bn.get_action_node("Action").get_values()) == 3 assert bn.get_utility_node("Util2").get_utility( Assignment(Assignment("Burglary"), "Action", ValueFactory.create("DoNothing"))) == pytest.approx( -10, abs=0.0001)
def test_param_4(self): system = DialogueSystem(TestParameters.domain1) system.detach_module(ForwardPlanner) system.get_settings().show_gui = False system.start_system() rules = TestParameters.domain1.get_models()[1].get_rules() outputs = rules[0].get_output(Assignment("u_u", "my name is")) o = Effect(BasicEffect("u_u^p", "Pierre")) assert isinstance(outputs.get_parameter(o), SingleParameter) input = Assignment("theta_5", ValueFactory.create("[0.36, 0.24, 0.40]")) assert outputs.get_parameter(o).get_value(input) == pytest.approx(0.36, abs=0.01) system.get_state().remove_nodes(system.get_state().get_action_node_ids()) system.get_state().remove_nodes(system.get_state().get_utility_node_ids()) system.add_content("u_u", "my name is") system.get_state().remove_nodes(system.get_state().get_action_node_ids()) system.get_state().remove_nodes(system.get_state().get_utility_node_ids()) system.add_content("u_u", "Pierre") system.get_state().remove_nodes(system.get_state().get_action_node_ids()) system.get_state().remove_nodes(system.get_state().get_utility_node_ids()) system.add_content("u_u", "my name is") system.get_state().remove_nodes(system.get_state().get_action_node_ids()) system.get_state().remove_nodes(system.get_state().get_utility_node_ids()) system.add_content("u_u", "Pierre") assert system.get_state().query_prob("theta_5").to_continuous().get_function().get_mean()[0] == pytest.approx(0.3, abs=0.12)
def test_empirical_distrib(self): st = CategoricalTableBuilder("var1") st.add_row("val1", 0.6) st.add_row("val2", 0.4) builder = ConditionalTableBuilder("var2") builder.add_row(Assignment("var1", "val1"), "val1", 0.9) builder.add_row(Assignment("var1", "val1"), "val2", 0.1) builder.add_row(Assignment("var1", "val2"), "val1", 0.2) builder.add_row(Assignment("var1", "val2"), "val2", 0.8) bn = BNetwork() var1 = ChanceNode("var1", st.build()) bn.add_node(var1) var2 = ChanceNode("var2", builder.build()) var2.add_input_node(var1) bn.add_node(var2) sampling = SamplingAlgorithm(2000, 500) distrib = sampling.query_prob(bn, "var2", Assignment("var1", "val1")) assert distrib.get_prob("val1") == pytest.approx(0.9, abs=0.05) assert distrib.get_prob("val2") == pytest.approx(0.1, abs=0.05) distrib2 = sampling.query_prob(bn, "var2") assert distrib2.get_prob("val1") == pytest.approx(0.62, abs=0.05) assert distrib2.get_prob("val2") == pytest.approx(0.38, abs=0.05)
def test_dep_empirical_distrib_continuous(self): bn = BNetwork() builder = CategoricalTableBuilder("var1") builder.add_row(ValueFactory.create("one"), 0.7) builder.add_row(ValueFactory.create("two"), 0.3) var1 = ChanceNode("var1", builder.build()) bn.add_node(var1) continuous = ContinuousDistribution("var2", UniformDensityFunction(-1.0, 3.0)) continuous2 = ContinuousDistribution( "var2", GaussianDensityFunction(3.0, 10.0)) table = ConditionalTable("var2") table.add_distrib(Assignment("var1", "one"), continuous) table.add_distrib(Assignment("var1", "two"), continuous2) var2 = ChanceNode("var2", table) var2.add_input_node(var1) bn.add_node(var2) inference = InferenceChecks() inference.check_cdf(bn, "var2", -1.5, 0.021) inference.check_cdf(bn, "var2", 0., 0.22) inference.check_cdf(bn, "var2", 2., 0.632) inference.check_cdf(bn, "var2", 8., 0.98)
def test_switching(self): old_factor = SwitchingAlgorithm.max_branching_factor SwitchingAlgorithm.max_branching_factor = 4 network = NetworkExamples.construct_basic_network2() distrib = SwitchingAlgorithm().query_prob( network, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) assert isinstance(distrib, MultivariateTable) builder = CategoricalTableBuilder("n1") builder.add_row(ValueFactory.create("aha"), 1.0) n1 = ChanceNode("n1", builder.build()) network.add_node(n1) builder = CategoricalTableBuilder("n2") builder.add_row(ValueFactory.create("oho"), 0.7) n2 = ChanceNode("n2", builder.build()) network.add_node(n2) builder = CategoricalTableBuilder("n3") builder.add_row(ValueFactory.create("ihi"), 0.7) n3 = ChanceNode("n3", builder.build()) network.add_node(n3) network.get_node("Alarm").add_input_node(n1) network.get_node("Alarm").add_input_node(n2) network.get_node("Alarm").add_input_node(n3) distrib = SwitchingAlgorithm().query_prob( network, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) assert distrib.__class__ == EmpiricalDistribution network.remove_node(n1.get_id()) network.remove_node(n2.get_id()) distrib = SwitchingAlgorithm().query_prob( network, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) assert isinstance(distrib, MultivariateTable) n1 = ChanceNode( "n1", ContinuousDistribution("n1", UniformDensityFunction(-2.0, 2.0))) n2 = ChanceNode( "n2", ContinuousDistribution("n2", GaussianDensityFunction(-1.0, 3.0))) network.add_node(n1) network.add_node(n2) network.get_node("Earthquake").add_input_node(n1) network.get_node("Earthquake").add_input_node(n2) distrib = SwitchingAlgorithm().query_prob( network, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) assert isinstance(distrib, EmpiricalDistribution) SwitchingAlgorithm.max_branching_factor = old_factor
def construct_basic_network3(): network = NetworkExamples.construct_basic_network() network.remove_node("Action") ddn = ActionNode("Action") network.get_utility_node("Util1").add_input_node(ddn) network.get_utility_node("Util1").remove_utility( Assignment(Assignment("Burglary", False), Assignment("Action", "DoNothing"))) network.get_utility_node("Util2").add_input_node(ddn) network.add_node(ddn) return network
def test5(self): reduced_net = TestNetworkReduction.ve.reduce( TestNetworkReduction.network, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) reduced_net2 = TestNetworkReduction.iz.reduce( TestNetworkReduction.network, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) reduced_net.add_node( copy(TestNetworkReduction.network.get_node("Action"))) reduced_net.add_node( copy(TestNetworkReduction.network.get_node("Util1"))) reduced_net.add_node( copy(TestNetworkReduction.network.get_node("Util2"))) reduced_net.get_node("Util1").add_input_node( reduced_net.get_node("Burglary")) reduced_net.get_node("Util1").add_input_node( reduced_net.get_node("Action")) reduced_net.get_node("Util2").add_input_node( reduced_net.get_node("Burglary")) reduced_net.get_node("Util2").add_input_node( reduced_net.get_node("Action")) table1 = TestNetworkReduction.ve.query_util(reduced_net, "Action") table2 = TestNetworkReduction.ve.query_util( TestNetworkReduction.network, ["Action"], Assignment(["JohnCalls", "MaryCalls"])) for a in table1.get_table().keys(): assert table1.get_util(a) == pytest.approx(table2.get_util(a), abs=0.01) reduced_net2.add_node( copy(TestNetworkReduction.network.get_node("Action"))) reduced_net2.add_node( copy(TestNetworkReduction.network.get_node("Util1"))) reduced_net2.add_node( copy(TestNetworkReduction.network.get_node("Util2"))) reduced_net2.get_node("Util1").add_input_node( reduced_net2.get_node("Burglary")) reduced_net2.get_node("Util1").add_input_node( reduced_net2.get_node("Action")) reduced_net2.get_node("Util2").add_input_node( reduced_net2.get_node("Burglary")) reduced_net2.get_node("Util2").add_input_node( reduced_net2.get_node("Action")) table3 = TestNetworkReduction.ve.query_util(reduced_net2, ["Action"]) for a in table1.get_table().keys(): assert table1.get_util(a) == pytest.approx(table3.get_util(a), abs=0.8)
def increment_util(self, sample, utility): """ Adds a new utility value to the estimated table :param sample: the sample assignment :param utility: the utility value for the sample """ if sample not in self._table: self._table[Assignment(sample)] = UtilityEstimate(utility) else: self._table[Assignment(sample)].update(utility) self._variables.update(sample.get_variables())
def extend(self, alternatives): """ Extends the existing groundings with the alternative groundings :param alternatives: the next groundings to extend the current ones """ if alternatives.is_empty(): return new_groundings = set() for o in alternatives: for g in self._groundings: new_groundings.add(Assignment([o, g])) new_groundings.add(Assignment([g, o])) self._groundings = new_groundings
def add(self, single_assign): """ Adds a single assignment to the list of alternative groundings :param single_assign: the assignment """ if single_assign.is_empty(): return for g in self._groundings: if g.contains(single_assign): return self._groundings.add(single_assign) if not self.is_empty(): if Assignment() in self._groundings: self._groundings.remove(Assignment())
def test_template7(self): template1 = Template.create("here we have slot {A} and slot {B}") fillers = Assignment() fillers.add_pair("A", "apple") fillers.add_pair("B", "banana") assert template1.fill_slots(fillers) == "here we have slot apple and slot banana" fillers.remove_pair("B") assert Template.create(template1.fill_slots(fillers)).get_slots().pop() == "B"
def check_cdf(self, network, variable, value, expected): query = ProbQuery(network, [variable], Assignment()) distrib_1 = self._compute_prob( query, self._variable_elimination).get_marginal(variable).to_continuous() distrib_2 = self._compute_prob( query, self._sampling_algorithm_1).get_marginal(variable).to_continuous() assert isclose(expected, distrib_1.get_cumulative_prob(value), abs_tol=InferenceChecks.exact_threshold) try: assert isclose(expected, distrib_2.get_cumulative_prob(value), abs_tol=InferenceChecks.sampling_threshold) except AssertionError as e: distrib_2 = self._compute_prob( query, self._sampling_algorithm_2).get_marginal( variable).to_continuous() assert isclose(expected, distrib_2.get_cumulative_prob(value), abs_tol=InferenceChecks.sampling_threshold) if self._include_naive: distrib_3 = self._compute_prob( query, self._naive_inference).get_marginal(variable).to_continuous() assert isclose(expected, distrib_3.to_discrete().get_prob(value), abs_tol=InferenceChecks.exact_threshold)
def get_output(self, assignment): """ Returns the first rule output whose condition matches the input assignment provided as argument. The output contains the grounded list of effects associated with the satisfied condition. :param assignment: the input assignment :return: the matched rule output """ output = RuleOutput(self._rule_type) groundings = self.get_groundings(assignment) for g in groundings.get_alternatives(): full = Assignment([assignment, g ]) if not g.is_empty() else assignment match = None for c in self._cases: if c._condition.is_satisfied_by(full): match = c._output break if match is None: match = RuleOutput(self._rule_type) match = match.ground(full) output.add_output(match) return output
def get_groundings(self, param): """ Returns the groundings for the complex condition (which is the union of the groundings for all basic conditions). :return: the full set of groundings """ groundings = RuleGrounding() if self._operator == BinaryOperator.AND: for cond in self._sub_conditions: new_grounding = RuleGrounding() found_grounding = False for g in groundings.get_alternatives(): g2 = param if g.is_empty() else Assignment([param, g]) ground = cond.get_groundings(g2) found_grounding = found_grounding or not ground.is_failed() ground.extend(g) new_grounding.add(ground) if not found_grounding: new_grounding.set_as_failed() return new_grounding groundings = new_grounding elif self._operator == BinaryOperator.OR: alternatives = [] for cond in self._sub_conditions: alternatives.append(cond.get_groundings(param)) groundings.add(alternatives) return groundings
def test_empirical_distrib_continuous(self): continuous = ContinuousDistribution("var1", UniformDensityFunction(-1.0, 3.0)) bn = BNetwork() var1 = ChanceNode("var1", continuous) bn.add_node(var1) sampling = SamplingAlgorithm(2000, 200) distrib2 = sampling.query_prob(bn, "var1") assert len(distrib2.get_posterior( Assignment()).get_values()) == pytest.approx( Settings.discretization_buckets, abs=2) assert distrib2.to_continuous().get_cumulative_prob( -1.1) == pytest.approx(0, abs=0.001) assert distrib2.to_continuous().get_cumulative_prob( 1.0) == pytest.approx(0.5, abs=0.06) assert distrib2.to_continuous().get_cumulative_prob( 3.1) == pytest.approx(1.0, abs=0.00) assert continuous.get_prob_density(-2.0) == pytest.approx( distrib2.to_continuous().get_prob_density(-2.0), abs=0.1) assert continuous.get_prob_density(-0.5) == pytest.approx( distrib2.to_continuous().get_prob_density(-0.5), abs=0.1) assert continuous.get_prob_density(1.8) == pytest.approx( distrib2.to_continuous().get_prob_density(1.8), abs=0.1) assert continuous.get_prob_density(3.2) == pytest.approx( distrib2.to_continuous().get_prob_density(3.2), abs=0.1)
def query_prob(self, variable, include_evidence): """ Returns the probability distribution corresponding to the values of the state variable provided as argument. :param variable: the variable label to query :param include_evidence: whether to include or ignore the evidence in the dialogue state :return: the corresponding probability distribution """ if self.has_chance_node(variable): chance_node = self.get_chance_node(variable) if isinstance(chance_node.get_distrib(), IndependentDistribution) and chance_node.get_clique( ).isdisjoint(self._evidence.get_variables()): return chance_node.get_distrib() else: try: query_evidence = self._evidence if include_evidence else Assignment( ) return SwitchingAlgorithm().query_prob( self, variable, query_evidence) except Exception as e: self.log.warning("Error querying variable %s : %s" % (variable, e)) raise ValueError() else: self.log.warning("Variable %s not included in the dialogue state" % variable) raise ValueError()
def test_nbest(self): builder = CategoricalTableBuilder("test") builder.add_row("bla", 0.5) builder.add_row("blo", 0.1) table = builder.build() for _ in range(10): assert str(table.get_best()) == "bla" builder2 = MultivariateTableBuilder() builder2.add_row(Assignment("test", "bla"), 0.5) builder2.add_row(Assignment("test", "blo"), 0.1) table2 = builder2.build() for _ in range(10): assert str(table2.get_best().get_value("test")) == "bla"
def remove_from_state(self, variable_id): """ Removes the variable from the dialogue state :param variable_id: the node to remove """ with self._locks['remove_from_state']: self.add_to_state(Assignment(variable_id, ValueFactory.none()))
def test_network1bis(self): bn = NetworkExamples.construct_basic_network2() full_joint = NaiveInference.get_full_joint(bn, False) assert full_joint.get( Assignment([ "JohnCalls", "MaryCalls", "Alarm", "!Burglary", "!Earthquake" ])) == pytest.approx(0.000453599, abs=0.000001) assert full_joint.get( Assignment([ "!JohnCalls", "!MaryCalls", "!Alarm", "!Burglary", "!Earthquake" ])) == pytest.approx(0.6764828, abs=0.000001) naive = NaiveInference() query = naive.query_prob(bn, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) assert query.get_prob(Assignment("Burglary", False)) == pytest.approx(0.360657, abs=0.0001) assert query.get_prob(Assignment("Burglary", True)) == pytest.approx(0.639343, abs=0.0001) query2 = naive.query_prob(bn, ["Alarm", "Burglary"], Assignment(["Alarm", "MaryCalls"])) assert query2.get_prob(Assignment(["Alarm", "!Burglary" ])) == pytest.approx(0.3577609, abs=0.001)
def test_network1(self): bn = NetworkExamples.construct_basic_network() full_joint = NaiveInference.get_full_joint(bn, False) assert full_joint[Assignment( ["JohnCalls", "MaryCalls", "Alarm", "!Burglary", "!Earthquake"])] == pytest.approx(0.000628, abs=0.000001) assert full_joint.get( Assignment([ "!JohnCalls", "!MaryCalls", "!Alarm", "!Burglary", "!Earthquake" ])) == pytest.approx(0.9367428, abs=0.000001) naive = NaiveInference() query = naive.query_prob(bn, ["Burglary"], Assignment(["JohnCalls", "MaryCalls"])) assert query.get_prob(Assignment("Burglary", False)) == pytest.approx(0.71367, abs=0.0001) assert query.get_prob(Assignment("Burglary", True)) == pytest.approx(0.286323, abs=0.0001) query2 = naive.query_prob(bn, ["Alarm", "Burglary"], Assignment(["Alarm", "MaryCalls"])) assert query2.get_prob(Assignment(["Alarm", "!Burglary" ])) == pytest.approx(0.623974, abs=0.001)
def add(self, other): """ Adds a list of alternative groundings to the existing set :param other: the alternative groundings """ for other_assign in other._groundings: found = False for g in self._groundings: if g.contains(other_assign): found = True break if found: continue self._groundings.add(other_assign) if not self.is_empty(): if Assignment() in self._groundings: self._groundings.remove(Assignment())
def get_best(self): """ Returns the entry with the highest utility in the table :return: the entry with highest utility """ if len(self._table) == 0: return Assignment(), 0. return list(self.get_n_best(1).get_table().items())[0]
def sample(self, condition): """ Returns a sample value for the variable X given the conditional assignment :param condition: the conditional assignment for Y1,...Yn :return: the sampled value for X """ return self._cond_distrib.sample( Assignment([condition, self._uncond_distrib.sample()]))
def query_prob(self, network, query_vars): """ Computes the probability distribution for the query variables, assuming no additional evidence. :param network: the Bayesian network on which to perform the inference :param query_vars: the collection of query variables :return: the resulting probability distribution failed to deliver a result """ return self.query_prob(ProbQuery(network, query_vars, Assignment()))
def get_cached_output(self, param): """ Returns the output of the anchored rule (using the cache if the input assignment is a sample). :param param: the input assignment :return: the output of the rule """ if self._cache is None: assignment = Assignment([param, self._filled_slots]) return self._rule.get_output(assignment) elif param.size() > len(self._variables): param = param.get_trimmed(self._variables) assign = Assignment([param, self._filled_slots]) if assign not in self._cache: self._cache[assign] = self._rule.get_output(assign) return self._cache[assign]
def modify_variable_id(self, old_id, new_id): """ Modifies a variable label with a new one :param old_id: the old variable label :param new_id: the new label :return: """ new_table = dict() for assignment in self._table.keys(): new_assignment = Assignment() for variable in assignment.get_variables(): new_variable = new_id if variable == old_id else variable new_assignment.add_pair(new_variable, assignment.get_value(variable)) new_table[new_assignment] = self._table[assignment] self._table = new_table