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 apply_alp(self, previous_situation: Perception, action: int, situation: Perception, time: int, population: ClassifiersList, match_set: ClassifiersList) -> None: """ The Anticipatory Learning Process. Handles all updates by the ALP, insertion of new classifiers in pop and possibly matchSet, and deletion of inadequate classifiers in pop and possibly matchSet. :param previous_situation: :param action: :param situation: :param time: :param population: :param match_set: """ new_list = ClassifiersList(cfg=self.cfg) new_cl: Optional[Classifier] = None was_expected_case = False delete_count = 0 for cl in self: cl.increase_experience() cl.set_alp_timestamp(time) if cl.does_anticipate_correctly(previous_situation, situation): new_cl = expected_case(cl, previous_situation, time) was_expected_case = True else: new_cl = unexpected_case(cl, previous_situation, situation, time) if cl.is_inadequate(): # Removes classifier from population, match set # and current list delete_count += 1 lists = [x for x in [population, match_set, self] if x] for lst in lists: lst.safe_remove(cl) if new_cl is not None: new_cl.tga = time self.add_alp_classifier(new_cl, new_list) # No classifier anticipated correctly - generate new one if not was_expected_case: new_cl = cover(previous_situation, action, situation, time, self.cfg) self.add_alp_classifier(new_cl, new_list) # Merge classifiers from new_list into self and population self.extend(new_list) population.extend(new_list) if match_set is not None: new_matching = [ cl for cl in new_list if cl.condition.does_match(situation) ] match_set.extend(new_matching)
def test_should_handle_unexpected_case_1(self, cfg): # given cls = Classifier(action=2, cfg=cfg) p0 = Perception('01100000') p1 = Perception('10100010') time = 14 new_cls = unexpected_case(cls, p0, p1, time) # Quality should be decreased assert 0.475 == cls.q # Should be marked with previous perception for mark_attrib in cls.mark: assert 1 == len(mark_attrib) assert '0' in cls.mark[0] assert '1' in cls.mark[1] assert '1' in cls.mark[2] assert '0' in cls.mark[3] assert '0' in cls.mark[4] assert '0' in cls.mark[5] assert '0' in cls.mark[6] assert '0' in cls.mark[7] # New classifier should not be the same object assert cls is not new_cls # Check attributes of a new classifier assert Condition('01####0#') == new_cls.condition assert 2 == new_cls.action assert Effect('10####1#') == new_cls.effect # There should be no mark for mark_attrib in new_cls.mark: assert 0 == len(mark_attrib) assert 0.5 == new_cls.q assert cls.r == new_cls.r assert time == new_cls.tga assert time == new_cls.talp
def test_should_handle_unexpected_case_6(self, cfg): # given cls = Classifier(condition='0#1####1', action=2, effect='1#0####0', quality=0.38505, reward=1.20898, immediate_reward=0, experience=11, tga=95, talp=873, tav=71.3967, cfg=cfg) cls.mark[1].update(['1']) cls.mark[3].update(['1']) cls.mark[4].update(['0', '1']) cls.mark[5].update(['1']) cls.mark[6].update(['0', '1']) p0 = Perception('01111101') p1 = Perception('11011110') time = 873 # when new_cls = unexpected_case(cls, p0, p1, time) # then assert new_cls is not None assert Condition('0#1###01') == new_cls.condition assert Effect('1#0###10') == new_cls.effect assert abs(0.5 - new_cls.q) < 0.1 assert abs(1.20898 - new_cls.r) < 0.1 assert abs(0 - new_cls.ir) < 0.1 assert abs(71.3967 - new_cls.tav) < 0.1 assert 1 == new_cls.exp assert 1 == new_cls.num assert time == new_cls.tga assert time == new_cls.talp
def test_should_handle_unexpected_case_5(self, cfg): # given cls = Classifier(condition='00####1#', action=2, effect='########', quality=0.129, reward=341.967, immediate_reward=130.369, experience=201, tga=129, talp=9628, tav=25.08, cfg=cfg) cls.mark[2].add('2') cls.mark[3].add('1') cls.mark[4].add('1') cls.mark[5].add('0') cls.mark[7].add('0') p0 = Perception('00211010') p1 = Perception('00001110') time = 9628 # when new_cls = unexpected_case(cls, p0, p1, time) # then assert new_cls is not None assert Condition('0021#01#') == new_cls.condition assert Effect('##00#1##') == new_cls.effect assert abs(0.5 - new_cls.q) < 0.1 assert abs(341.967 - new_cls.r) < 0.1 assert abs(130.369 - new_cls.ir) < 0.1 assert abs(25.08 - new_cls.tav) < 0.1 assert 1 == new_cls.exp assert 1 == new_cls.num assert time == new_cls.tga assert time == new_cls.talp
def test_should_handle_unexpected_case_3(self, cfg): cls = Classifier(condition='#####1#0', effect='#####0#1', quality=0.475, cfg=cfg) cls.mark[0].add('1') cls.mark[1].add('1') cls.mark[2].add('0') cls.mark[3].add('1') cls.mark[5].add('1') cls.mark[7].add('1') p0 = Perception('11001110') p1 = Perception('01110000') time = 20 new_cls = unexpected_case(cls, p0, p1, time) # Quality should be decreased assert 0.45125 == cls.q # No classifier should be generated here assert new_cls is None
def apply_alp(population: ClassifiersList, match_set: ClassifiersList, action_set: ClassifiersList, p0: Perception, action: int, p1: Perception, time: int, theta_exp: int, cfg: Configuration) -> None: """ The Anticipatory Learning Process. Handles all updates by the ALP, insertion of new classifiers in pop and possibly matchSet, and deletion of inadequate classifiers in pop and possibly matchSet. Parameters ---------- population match_set action_set p0: Perception action: int p1: Perception time: int theta_exp cfg: Configuration Returns ------- """ new_list = ClassifiersList() new_cl: Optional[Classifier] = None was_expected_case = False delete_count = 0 for cl in action_set: cl.increase_experience() cl.update_application_average(time) if cl.does_anticipate_correctly(p0, p1): new_cl = alp_acs2.expected_case(cl, p0, time) was_expected_case = True else: new_cl = alp_acs2.unexpected_case(cl, p0, p1, time) if cl.is_inadequate(): # Removes classifier from population, match set # and current list delete_count += 1 lists = [ x for x in [population, match_set, action_set] if x ] for lst in lists: lst.safe_remove(cl) if new_cl is not None: new_cl.tga = time alp.add_classifier(new_cl, action_set, new_list, theta_exp) # No classifier anticipated correctly - generate new one if not was_expected_case: new_cl = alp_acs2.cover(p0, action, p1, time, cfg) alp.add_classifier(new_cl, action_set, new_list, theta_exp) # Merge classifiers from new_list into self and population action_set.extend(new_list) population.extend(new_list) if match_set is not None: new_matching = [ cl for cl in new_list if matching(cl.condition, p1) ] match_set.extend(new_matching)