def test_should_create_new_classifier_with_covering( self, _p0, _p1, _child_cond, _child_effect, cfg): # given cfg.cover_noise = 0.0 p0 = Perception(_p0, oktypes=(float, )) p1 = Perception(_p1, oktypes=(float, )) action = random.randint(0, cfg.number_of_possible_actions) time = random.randint(0, 100) # when new_cl = cover(p0, action, p1, time, cfg) # then assert new_cl is not None assert new_cl.condition == Condition(_child_cond, cfg) assert new_cl.action == action assert new_cl.effect == Effect(_child_effect, cfg) assert new_cl.q == .5 assert new_cl.r == 0 assert new_cl.ir == 0 assert new_cl.tav == 0 assert new_cl.tga == time assert new_cl.talp == time # assert new_cl.num == 1 assert new_cl.exp == 0
def test_should_handle_unexpected_case_2(self, cfg): # given cls = Classifier(condition='#######0', action=4, quality=0.4, cfg=cfg) cls.mark[0].update([0, 1]) cls.mark[1].update([0, 1]) cls.mark[2].update([0, 1]) cls.mark[3].update([0, 1]) cls.mark[4].update([1]) cls.mark[5].update([0, 1]) cls.mark[6].update([0, 1]) p0 = Perception('11101010') p1 = Perception('10011101') time = 94 # when new_cl = unexpected_case(cls, p0, p1, time) # then assert new_cl.condition == Condition('#110#010') assert new_cl.effect == Effect('#001#101') assert new_cl.is_marked() is False assert time == new_cl.tga assert time == new_cl.talp assert abs(cls.q - 0.38) < 0.01
def _run_trial_explore(self, env, trials, current_trial) -> TrialMetrics: logger.debug("** Running trial explore ** ") # Initial conditions steps = 0 raw_state = env.reset() state = self.cfg.environment_adapter.to_genotype(raw_state) action = env.action_space.sample() last_reward = 0 prev_state = Perception.empty() selected_cl = None prev_selected_cl = None done = False while not done: state = Perception(state) match_set = self.population.form_match_set(state) if steps > 0: alp.apply(prev_state, state, selected_cl, self.population) rl.bucket_brigade_update( selected_cl, prev_selected_cl, last_reward) prev_selected_cl = selected_cl # TODO: you can do it better if random.random() < self.cfg.epsilon: selected_cl = random.choice(match_set) else: selected_cl = self._best_cl(match_set) action = selected_cl.action iaction = self.cfg.environment_adapter.to_lcs_action(action) logger.debug("\tExecuting action: [%d]", action) prev_state = Perception(state) raw_state, last_reward, done, _ = env.step(iaction) state = self.cfg.environment_adapter.to_genotype(raw_state) state = Perception(state) if done: alp.apply(prev_state, state, selected_cl, self.population) rl.bucket_brigade_update( selected_cl, prev_selected_cl, last_reward) steps += 1 return TrialMetrics(steps, last_reward)
def test_search_one_backward_step_3(self, cfg): # given gs = GoalSequenceSearcher() start = "01111111" goal = "10111111" gs.forward_perceptions.append(Perception(start)) gs.backward_perceptions.append(Perception(goal)) reliable_classifiers = ClassifiersList( Classifier(condition="#1######", action=1, effect="#0######", cfg=cfg), Classifier(condition="0#######", action=1, effect="1#######", cfg=cfg)) forward_size = 1 forward_point = 0 # when act_seq, size = gs._search_one_backward_step(reliable_classifiers, forward_size, forward_point) # then assert act_seq is None assert len(gs.backward_classifiers) == 2
def _run_trial_exploit(self, env, trials, current_trial) -> TrialMetrics: logger.debug("** Running trial exploit **") # Initial conditions steps = 0 raw_state = env.reset() state = self.cfg.environment_adapter.to_genotype(raw_state) action = env.action_space.sample() last_reward = 0 prev_state = Perception.empty() selected_cl = None prev_selected_cl = None done = False while not done: state = Perception(state) match_set = self.population.form_match_set(state) selected_cl = self._best_cl(match_set) action = selected_cl.action iaction = self.cfg.environment_adapter.to_lcs_action(action) logger.debug("\tExecuting action: [%d]", action) raw_state, last_reward, done, _ = env.step(iaction) state = self.cfg.environment_adapter.to_genotype(raw_state) state = Perception(state) steps += 1 return TrialMetrics(steps, last_reward)
def test_should_anticipate_correctly(self, cfg): # given cls = Classifier(effect='#1####0#', cfg=cfg) p0 = Perception('00001111') p1 = Perception('01001101') # then assert cls.does_anticipate_correctly(p0, p1) is True
def test_should_specialize(self, _p0, _p1, _effect, is_specializable, cfg): # given p0 = Perception(_p0, oktypes=(float, )) p1 = Perception(_p1, oktypes=(float, )) effect = Effect(_effect, cfg=cfg) # then assert effect.is_specializable(p0, p1) is is_specializable
def test_should_detect_correctable_classifier(self, _c, _e, _p0, _p1, _result, cfg): cl = Classifier(condition=_c, effect=_e, cfg=cfg) p0 = Perception(_p0) p1 = Perception(_p1) assert cl.can_be_corrected(p0, p1) is _result
def test_should_anticipate_change(self, _effect, _p0, _p1, _result, cfg): # given p0 = Perception(_p0, oktypes=(float, )) p1 = Perception(_p1, oktypes=(float, )) c = Classifier(effect=_effect, cfg=cfg) # then assert c.does_anticipate_correctly(p0, p1) is _result
def test_should_detect_correct_anticipation_1(self, cfg): # Classifier is not predicting any change, all pass-through effect # should predict correctly # given cls = Classifier(effect=Effect('########'), cfg=cfg) p0 = Perception('00001111') p1 = Perception('00001111') # then assert cls.does_anticipate_correctly(p0, p1) is True
def test_does_specify_only_changes_backwards(self, _p0, _p1, _e, _result): # given back_ant = Perception(_p0) sit = Perception(_p1) effect = Effect(_e) # when result = effect.does_specify_only_changes_backwards(back_ant, sit) # then assert result is _result
def test_should_check_if_specializable_6(self): # given p0 = Perception(['0', '0', '1', '1', '0', '0', '0', '0']) p1 = Perception(['0', '0', '1', '1', '0', '0', '0', '0']) effect = Effect(['#', '1', '0', '#', '#', '#', '1', '1']) # when res = effect.is_specializable(p0, p1) # then assert res is False
def test_does_match(self, _p0, _p1, _e, _result): # given p0 = Perception(_p0) p1 = Perception(_p1) effect = Effect(_e) # when result = effect.does_match(p0, p1) # then assert result is _result
def test_should_detect_correct_anticipation_6(self, cfg): # Case when effect predicts situation incorrectly # given cls = Classifier(effect=Effect( ['#', '#', '1', '#', '0', '#', '0', '#']), cfg=cfg) p0 = Perception(['0', '0', '0', '1', '1', '0', '1', '0']) p1 = Perception(['0', '0', '1', '1', '0', '0', '0', '0']) # then assert cls.does_anticipate_correctly(p0, p1) is True
def test_search_goal_sequence_1(self): # given gs = GoalSequenceSearcher() start = Perception("11111111") goal = Perception("11111110") empty_list = ClassifiersList() # when result = gs.search_goal_sequence(empty_list, start=start, goal=goal) # then assert result == []
def test_should_detect_correct_anticipation_2(self, cfg): # Introduce two changes into situation and effect (should # also predict correctly) # given cls = Classifier(effect=Effect( ['#', '1', '#', '#', '#', '#', '0', '#']), cfg=cfg) p0 = Perception(['0', '0', '0', '0', '1', '1', '1', '1']) p1 = Perception(['0', '1', '0', '0', '1', '1', '0', '1']) # then assert cls.does_anticipate_correctly(p0, p1) is True
def test_should_predict_successfully_1(self, cfg): # given action = 5 cls = Classifier(condition='1#0111#1', action=action, effect='0#1000#0', quality=0.94, cfg=cfg) p0 = Perception('11011101') p1 = Perception('01100000') # then assert cls.predicts_successfully(p0, action, p1) is True
def test_should_handle_pass_through_symbol(self, cfg): # A case when there was no change in perception but effect has no # pass-through symbol # given cls = Classifier(effect=Effect( ['#', '0', '#', '#', '#', '#', '#', '#']), cfg=cfg) p0 = Perception(['0', '0', '0', '0', '1', '1', '1', '1']) p1 = Perception(['0', '0', '0', '0', '1', '1', '1', '1']) # then assert cls.does_anticipate_correctly(p0, p1) is False
def reliable_cl_exists(env, population, ctrl_bits=None) -> bool: p1 = env.render('ansi') # state after executing action p1 = [str(x) for x in p1] # cast to strings p0 = p1[:-1] + ['0'] # initial state correct_answer = get_correct_answer(p0, ctrl_bits) # true action reliable_classifiers = [c for c in population if c.is_reliable()] return any([1 for cl in reliable_classifiers if cl.predicts_successfully( Perception(p0), correct_answer, Perception(p1))])
def test_should_specialize(self, cfg): # given p0 = Perception([random.random()] * 2, oktypes=(float, )) p1 = Perception([random.random()] * 2, oktypes=(float, )) cl = Classifier(cfg=cfg) # when cl.specialize(p0, p1) # then for condition_ubr, effect_ubr in zip(cl.condition, cl.effect): assert condition_ubr.lower_bound == condition_ubr.upper_bound assert effect_ubr.lower_bound == effect_ubr.upper_bound
def test_should_specialize(self, _p0, _p1, _init_cond, _init_effect, _res_cond, _res_effect, cfg): # given cls = Classifier(condition=Condition(_init_cond), effect=Effect(_init_effect), cfg=cfg) p0 = Perception(_p0) p1 = Perception(_p1) # when cls.specialize(p0, p1, leave_specialized=False) # then assert cls.condition == Condition(_res_cond) assert cls.effect == Effect(_res_effect)
def test_should_handle_expected_case_3(self, cfg): # given p0 = Perception('00110000') time = 26 cls = Classifier(action=5, quality=0.46, cfg=cfg) cls.mark[0].add('0') cls.mark[1].add('1') cls.mark[2].add('0') cls.mark[3].add('1') cls.mark[4].add('0') cls.mark[5].add('1') cls.mark[6].add('1') cls.mark[7].add('1') # when new_cls = expected_case(cls, p0, time) # then assert new_cls is not None # One `random` attribute gets specified assert 1 == new_cls.condition.specificity assert Effect('########') == new_cls.effect assert 5 == new_cls.action assert new_cls.is_marked() is False assert 0.5 == new_cls.q
def test_should_handle_expected_case_4(self, cfg): # given p0 = Perception('11101101') time = 703 cls = Classifier(condition='1##01#0#', action=7, effect='0##10#1#', quality=0.47, cfg=cfg) cls.mark[1].update(['0', '2']) cls.mark[2].update(['1']) cls.mark[5].update(['0', '1']) cls.mark[7].update(['1']) # when new_cls = expected_case(cls, p0, time) # then assert new_cls is not None # One `random` attribute gets specified assert new_cls.condition.specificity in [4, 5] assert Effect('0##10#1#') == new_cls.effect assert 7 == new_cls.action assert new_cls.is_marked() is False assert 0.5 == new_cls.q
def test_should_complement_mark_from_perception(self, cfg): # Given p0 = Perception(['0', '1', '1', '1', '0', '1', '1', '1']) mark = PMark(cfg) mark[0].add('1') mark[2].add('1') mark[3].add('1') mark[6].add('1') # When mark.complement_marks(p0) # Then assert 2 == len(mark[0]) assert '0' in mark[0] assert '1' in mark[0] assert 1 == len(mark[2]) assert '1' in mark[2] assert 1 == len(mark[3]) assert '1' in mark[3] assert 1 == len(mark[6]) assert '1' in mark[6]
def test_should_get_differences_4(self, cfg): # given p0 = Perception(['1', '1', '1', '1', '1', '0', '1', '0']) mark = PMark(cfg) mark[0].update(['0', '1']) mark[1].update(['0', '1']) mark[3].update(['0', '1']) mark[4].update(['0', '1']) mark[6].update(['0', '1']) mark[7].update(['0']) # when diff = mark.get_differences(p0) # then assert diff is not None assert 5 == diff.specificity assert '1' == diff[0] assert '1' == diff[1] assert '#' == diff[2] assert '1' == diff[3] assert '1' == diff[4] assert '#' == diff[5] assert '1' == diff[6] assert '#' == diff[7]
def test_should_get_differences_3(self, cfg): # Given p0 = Perception(['0', '1', '1', '0', '0', '0', '0', '0']) mark = PMark(cfg) mark[0].update(['0', '1']) mark[1].update(['1']) mark[2].update(['0', '1']) mark[3].update(['1']) mark[4].update(['0', '1']) mark[5].update(['1']) mark[6].update(['0', '1']) mark[7].update(['1']) for _ in range(100): # When diff = mark.get_differences(p0) # Then assert diff is not None assert '#' == diff[0] assert '#' == diff[1] assert '#' == diff[2] assert '#' == diff[4] assert '#' == diff[6] assert 1 == diff.specificity
def test_add_ga_classifier_increase_numerosity(self): # given cfg = acs2.Configuration( classifier_length=8, number_of_possible_actions=4) cl_1 = acs2.Classifier(action=2, condition='1#######', cfg=cfg) cl_2 = acs2.Classifier(action=3, cfg=cfg) cl_3 = acs2.Classifier(action=4, cfg=cfg) population = acs2.ClassifiersList(*[cl_1, cl_2, cl_3]) match_set = acs2.ClassifiersList(*[cl_1]) action_set = acs2.ClassifiersList(*[cl_1]) cl = acs2.Classifier(action=2, condition='1#######', cfg=cfg) # when p0 = Perception('10101010') ga.add_classifier(cl, p0, population, match_set, action_set, do_subsumption=True, theta_exp=cfg.theta_exp) # then assert cl_1.num == 2 assert acs2.ClassifiersList(*[cl_1, cl_2, cl_3]) == population assert acs2.ClassifiersList(*[cl_1]) == match_set assert acs2.ClassifiersList(*[cl_1]) == action_set
def test_should_add_classifier(self): # given cfg = acs2.Configuration( classifier_length=8, number_of_possible_actions=4) cl_1 = acs2.Classifier(action=1, cfg=cfg) cl_3 = acs2.Classifier(action=3, cfg=cfg) cl_4 = acs2.Classifier(action=4, cfg=cfg) population = acs2.ClassifiersList(*[cl_1, cl_3, cl_4]) match_set = acs2.ClassifiersList() action_set = acs2.ClassifiersList(*[cl_1]) p0 = Perception('10101010') cl = acs2.Classifier( action=1, condition='1#######', cfg=cfg) # when ga.add_classifier(cl, p0, population, match_set, action_set, do_subsumption=True, theta_exp=cfg.theta_exp) # then assert acs2.ClassifiersList(*[cl_1, cl_3, cl_4, cl]) == population assert acs2.ClassifiersList(*[cl]) == match_set assert acs2.ClassifiersList(*[cl_1, cl]) == action_set
def test_should_fail_on_invalid_type(self): # given obs = ["f", "o", 0] # when & then with pytest.raises(AssertionError) as _: Perception(obs)
def test_should_specialize(self, cfg): # given p0 = Perception(np.random.random(2), oktypes=(float, )) p1 = Perception(np.random.random(2), oktypes=(float, )) cl = Classifier(cfg=cfg) # when cl.specialize(p0, p1) # then enc_p0 = list(map(cfg.encoder.encode, p0)) enc_p1 = list(map(cfg.encoder.encode, p1)) for i, (c_ubr, e_ubr) in enumerate(zip(cl.condition, cl.effect)): assert c_ubr.lower_bound <= enc_p0[i] <= c_ubr.upper_bound assert e_ubr.lower_bound <= enc_p1[i] <= e_ubr.upper_bound