Exemple #1
0
    def test_compare_relations(self):
        real_relations = [
            Relation(1, 0, 0),
            Relation(2, 0, 0),
            Relation(2, 4, 0),
        ]
        learned_relations = [
            Relation(2, 0, 0),
            Relation(0, 1, 0),
            Relation(1, 3, 0),
        ]
        expected_missing = [
            Relation(2, 4, 0),
        ]
        expected_added = [
            Relation(1, 3, 0),
        ]
        expected_inverted = [
            Relation(0, 1, 0),
        ]

        missing, added, inverted = EvaluateLearner.compare_relations(
            real_relations, learned_relations)

        RelationAssert.equal(self, expected_missing, missing,
                             'Missing relations')
        RelationAssert.equal(self, expected_added, added, 'Added relations')
        RelationAssert.equal(self, expected_inverted, inverted,
                             'Inverted relations')
Exemple #2
0
    def test_independent_effects(self):
        relations = Generator() \
            .add_uniform() \
            .add_function(lambda h: h.get_event()) \
            .add_linear() \
            .add_function(lambda h: h.get_event(3)) \
            .build_relations()

        expected = [
            Relation(1, 2, 0),
            Relation(3, 4, 0),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #3
0
    def test_circular_relations(self):
        relations = Generator() \
            .add_function(lambda h: round(h.e(2, delay=0))) \
            .add_function(lambda h: round(h.e(3, delay=1))) \
            .add_function(lambda h: round(h.e(4, delay=2))) \
            .add_function(lambda h: round(h.e(1, delay=3))) \
            .build_relations()

        expected = [
            Relation(2, 1, 0),
            Relation(3, 2, 1),
            Relation(4, 3, 2),
            Relation(1, 4, 3),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #4
0
    def test_different_event_types(self):
        event_function: Callable[[History], float] = lambda history: \
            1 if history.get_event() == 1 else history.get_event(2, delay=1)

        relations = Generator() \
            .add_uniform() \
            .add_discrete() \
            .add_function(event_function) \
            .add_linear() \
            .build_relations()

        expected = [
            Relation(1, 3, 0),
            Relation(2, 3, 1),
        ]

        RelationAssert.equal(self, expected, relations)
    def __build_relations(graph: PDAG, data: pd.DataFrame) -> List[Relation]:
        relations = []
        for edge in graph.edges:
            source = data.columns.get_loc(edge[0])
            target = data.columns.get_loc(edge[1])
            relations.append(Relation(source, target))

        return relations
Exemple #6
0
    def test_lambda_as_function(self):
        function1: Callable[[History], float] = lambda history: \
            1 if history.get_event(0) == 1 else 0

        function2 = lambda h: max([1, 4]) if h.get_event() == 1 else 0

        relations = Generator() \
            .add_function(function1) \
            .add_function(function2) \
            .build_relations()

        expected = [
            Relation(0, History.DEFAULT_POSITION, History.DEFAULT_DELAY),
            Relation(History.DEFAULT_POSITION, History.DEFAULT_POSITION + 1,
                     History.DEFAULT_DELAY),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #7
0
    def test_jump_shadows(self):
        relations = Generator() \
            .set_time('2020-02-20', step='1d') \
            .add_uniform(label='1') \
            .add_uniform(label='2') \
            .add_function(lambda h: h.e(0), label='3') \
            .add_function(lambda h: h.e(3) + h.e(2), shadow=True, label='4') \
            .add_function(lambda h: h.e(4), shadow=True, label='5') \
            .add_function(lambda h: h.e(5), label='6') \
            .build_relations(include_shadow=False)

        expected = [
            Relation(2, 6),
            Relation(0, 3),
            Relation(3, 6),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #8
0
    def test_shadows_doubles(self):
        relations = Generator() \
            .add_function(lambda h: h.e(4) + h.e(6), shadow=True, label='1') \
            .add_function(lambda h: h.e(1) + h.e(7), label='2') \
            .add_function(lambda h: h.e(1), label='3') \
            .add_uniform(label='4') \
            .add_uniform(label='5') \
            .add_uniform(label='6') \
            .add_uniform(label='6') \
            .build_relations(include_shadow=False)

        expected = [
            Relation(7, 2),
            Relation(4, 2),
            Relation(4, 3),
            Relation(6, 2),
            Relation(6, 3),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #9
0
    def _remove_shadow_events(relations: List[Relation],
                              events: List[EventInterface]):
        """
        Rebuild relations after removing shadow events
        TODO for now this removes the time delay from relations
        """
        final_paths = []
        # List all sources and targets into separate lists.
        sources, targets = zip(*((relation.source, relation.target)
                                 for relation in relations))
        # Remove targets from sources to keep only root sources.
        paths = [[[root] for root in set(sources) - set(targets)]]
        # No root left means a circular relation. Use any source then.
        if len(paths[0]) == 0:
            paths[0].append([sources[0]])

        # Build paths.
        depth = 1
        while depth > 0:
            paths.append([])
            for path in paths[depth - 1]:
                is_final = True
                for relation in relations:
                    # Stop at circular loops.
                    if path[-1] == relation.source and path[
                            -1] not in path[:-1]:
                        paths[depth].append([*path, relation.target])
                        is_final = False

                if is_final:
                    final_paths.append(path)

            depth = depth + 1 if len(paths[depth]) else -1

        # Remove shadow events.
        for path in final_paths:
            for item in path.copy():
                if events[item].shadow:
                    path.remove(item)

        # Rebuild relations.
        relations = []
        hashes = []
        for path in final_paths:
            for key in range(len(path) - 1):
                source = path[key]
                target = path[key + 1]
                relation_hash = f'{source}-{target}'
                if relation_hash in hashes:
                    continue
                hashes.append(relation_hash)
                relations.append(Relation(source, target))

        return relations
Exemple #10
0
    def test_lambda_as_argument(self):
        relations = Generator() \
            .add_uniform() \
            .add_uniform(6, 10).add_function(lambda h: h.get_event(2, delay=3)) \
            .build_relations()

        expected = [
            Relation(2, 3, 3),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #11
0
    def test_with_time(self):
        function1: Callable[[History], float] = lambda history: \
            1 if history.get_datetime() == 1 else history.get_event()

        def function2(h: History) -> float:
            return h.get_timestamp()

        relations = Generator() \
            .add_function(function1) \
            .add_function(function2) \
            .add_function(lambda v: v.get_datetime(delay=2)) \
            .build_relations()

        expected = [
            Relation(0, 1, 0),
            Relation(1, 1, 0),
            Relation(0, 2, 0),
            Relation(0, 3, 2),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #12
0
    def test_time_arguments(self):
        def func1(history: History) -> float:
            return history.get_datetime().weekday()

        def func2(history: History) -> float:
            return history.get_datetime(1).isocalendar()[1]

        def func3(history: History) -> float:
            return history.get_timestamp(delay=2)

        relations = Generator() \
            .set_time('2020-02-20', step='1d') \
            .add_function(func1, shadow=True) \
            .add_function(func2, shadow=True) \
            .add_function(func3, shadow=True) \
            .add_function(lambda h: h.get_event(1) * h.get_event(2, delay=2) * h.get_event(3)) \
            .build_relations()

        expected = [
            Relation(0, 1, 0),
            Relation(0, 2, 1),
            Relation(0, 3, 2),
            Relation(1, 4, 0),
            Relation(2, 4, 2),
            Relation(3, 4, 0),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #13
0
    def test_function_combinations(self):
        def effect_function(history: History) -> float:
            value = history.get_event()
            if history.get_event(201, delay=200):
                value *= 1.5
            elif history.get_event(position=301, delay=300, null_value=None):
                value *= 3
            elif history.get_event(delay=500):
                value *= 3
            elif history.get_event(delay=600, position=601):
                value *= 3
            value = history.get_event(401) + 4

            return value

        relations = Generator() \
            .add_function(effect_function) \
            .build_relations()

        expected = [
            Relation(History.DEFAULT_POSITION, History.DEFAULT_POSITION,
                     History.DEFAULT_DELAY),
            Relation(201, History.DEFAULT_POSITION, 200),
            Relation(301, History.DEFAULT_POSITION, 300),
            Relation(History.DEFAULT_POSITION, History.DEFAULT_POSITION, 500),
            Relation(601, History.DEFAULT_POSITION, 600),
            Relation(401, History.DEFAULT_POSITION, History.DEFAULT_DELAY),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #14
0
    def test_simple_relation_function(self):
        def effect_function(history: History) -> float:
            return history.get_event()

        relations = Generator() \
            .add_function(effect_function) \
            .build_relations()

        expected = [
            Relation(History.DEFAULT_POSITION, History.DEFAULT_POSITION,
                     History.DEFAULT_DELAY)
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #15
0
    def test_circular_relations_excluding_shadows(self):
        functions = [
            lambda h: round((h.e(2, delay=0) or 0), 0),
            lambda h: round((h.e(3, delay=1) or 0), 0),
            lambda h: round((h.e(4, delay=2) or 0), 0),
            lambda h: round((h.e(1, delay=3) or 0), 0),
        ]

        relations = Generator() \
            .add_function(functions[0]) \
            .add_function(functions[1]) \
            .add_function(functions[2], shadow=True) \
            .add_function(functions[3]) \
            .add_discrete(3) \
            .build_relations(include_shadow=False)

        expected = [
            Relation(2, 1, 0),
            Relation(1, 4, 0),
            Relation(4, 2, 0),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #16
0
    def test_function_short_variable(self):
        def effect_function1(h: History) -> float:
            return h.get_event()

        def effect_function2(var) -> float:
            return var.get_event(10, delay=20)

        def effect_function3(h) -> float:
            return h

        relations = Generator() \
            .add_function(effect_function1) \
            .add_function(effect_function2) \
            .add_function(effect_function3) \
            .build_relations()

        expected = [
            Relation(History.DEFAULT_POSITION, History.DEFAULT_POSITION,
                     History.DEFAULT_DELAY),
            Relation(10, History.DEFAULT_POSITION + 1, 20),
        ]

        RelationAssert.equal(self, expected, relations)
Exemple #17
0
    def __build_relation(self, event: Function) -> list:
        """ Extract relations from events source code """
        function_string = inspect.getsource(event.function)

        if re.search(rf'.*\.{self.__FUNC_METHOD}\(', function_string):
            scope_parts = re.split(r'([()])', function_string)
            key = 0
            while key < len(scope_parts):
                func_content = ''
                if re.search(rf'\.{self.__FUNC_METHOD}$', scope_parts[key]):
                    depth = 0
                    for local_part in scope_parts[key + 1:]:
                        key += 1
                        if local_part == '(':
                            depth += 1
                        if depth > 1 or local_part not in ['(', ')']:
                            func_content += local_part
                        if local_part == ')':
                            depth -= 1
                        if depth == 0:
                            break
                    function_string = func_content
                    break
                key += 1

        # Extract variable label.
        argument_groups = re.search(
            r'(.*def[^\n:]+\((.*?)\)|lambda *?(\w+))(.*)', function_string,
            re.DOTALL)
        function_arguments = argument_groups.group(2)
        if function_arguments is None:
            function_arguments = argument_groups.group(3)
        if function_arguments is None:
            return []

        function_content = argument_groups.group(4)

        var_name = re.split(r' *: *', function_arguments)[0]

        args = []
        # Extract all History method calls.
        regex = re.compile(
            rf'{var_name}\.(({self.__EVENT_METHODS})|(?P<time_method>{self.__TIME_METHODS}))'
            rf'\((?P<arguments>.*?)\)')

        for method_parts in regex.finditer(function_content):
            items = method_parts.groupdict()
            arguments_string = items['arguments']
            is_time_method = items['time_method'] is not None
            default_position = 0 if is_time_method else History.DEFAULT_POSITION
            default_argument = self.__DEFAULT_ARG_TIME if is_time_method else self.__DEFAULT_ARG_EVENT
            arg = {
                self.__ARG_POSITION: default_position,
                self.__ARG_DELAY: History.DEFAULT_DELAY
            }
            if arguments_string != '':
                arguments = re.split(" *, *", arguments_string)
                for argument in arguments:
                    arg_value = re.split(' *= *', argument)
                    if len(arg_value) == 1:
                        arg_value = [default_argument, arg_value[0]]
                    arg[arg_value[0]] = arg_value[1]

            args.append(
                Relation(source=int(arg[self.__ARG_POSITION]),
                         target=int(event.position),
                         delay=int(arg[self.__ARG_DELAY])))

        return args
    def __build_relations(bn_tree: gum.BayesNet) -> List[Relation]:
        relations = []
        for arc in bn_tree.arcs():
            relations.append(Relation(arc[0], arc[1]))

        return relations