def detect_loop_cut(self):
        """
        Detect loop cut
        """
        start_activities = self.start_activities
        if len(start_activities) == 0:
            start_activities = infer_start_activities_from_prev_connections_and_current_dfg(self.initial_dfg, self.dfg,
                                                                                            self.activities)
        end_activities = self.end_activities

        end_activities = list(set(end_activities) - set(start_activities))

        if len(end_activities) == 0:
            end_activities = infer_end_activities_from_succ_connections_and_current_dfg(self.initial_dfg, self.dfg,
                                                                                        self.activities)
            end_activities = list(set(end_activities) - set(start_activities))
            if len(end_activities) == 0:
                end_activities = infer_end_activities_from_succ_connections_and_current_dfg(self.initial_dfg, self.dfg,
                                                                                            self.activities,
                                                                                            include_self=False)
        all_end_activities = copy(end_activities)
        end_activities = list(set(end_activities) - set(start_activities))
        end_activities_that_are_also_start = list(set(all_end_activities) - set(end_activities))

        do_part = []
        redo_part = []
        dangerous_redo_part = []
        exit_part = []

        for sa in start_activities:
            do_part.append(sa)
        for ea in end_activities:
            exit_part.append(ea)

        for act in self.activities:
            if act not in start_activities and act not in end_activities:
                input_connected_activities = get_all_activities_connected_as_input_to_activity(self.dfg, act)
                output_connected_activities = get_all_activities_connected_as_output_to_activity(self.dfg, act)
                if set(output_connected_activities).issubset(start_activities) and set(start_activities).issubset(
                        output_connected_activities):
                    if len(input_connected_activities.intersection(exit_part)) > 0:
                        dangerous_redo_part.append(act)
                    redo_part.append(act)
                else:
                    do_part.append(act)

        if len(do_part) > 0 and (len(redo_part) > 0 or len(exit_part)) > 0:
            if len(redo_part) > 0:
                return [True, [do_part + exit_part, redo_part], len(end_activities_that_are_also_start) > 0]
            else:
                return [True, [do_part, redo_part + exit_part], len(end_activities_that_are_also_start) > 0]

        return [False, [], []]
    def check_sa_ea_for_each_branch(self, conn_components):
        """
        Checks if each branch of the parallel cut has a start
        and an end node of the subgraph

        Parameters
        --------------
        conn_components
            Parallel cut

        Returns
        -------------
        boolean
            True if each branch of the parallel cut has a start and an end node
        """
        parallel_cut_sa = list(
            set(self.initial_start_activities).union(
                infer_start_activities_from_prev_connections_and_current_dfg(
                    self.initial_dfg,
                    self.dfg,
                    self.activities,
                    include_self=False)).intersection(self.activities))
        parallel_cut_ea = list(
            set(self.initial_end_activities).union(
                infer_end_activities_from_succ_connections_and_current_dfg(
                    self.initial_dfg,
                    self.dfg,
                    self.activities,
                    include_self=False)).intersection(self.activities))

        if conn_components is None:
            return False

        for comp in conn_components:
            comp_sa_ok = False
            comp_ea_ok = False

            for sa in parallel_cut_sa:
                if sa in comp:
                    comp_sa_ok = True
                    break
            for ea in parallel_cut_ea:
                if ea in comp:
                    comp_ea_ok = True
                    break

            if not (comp_sa_ok and comp_ea_ok):
                return False

        return True
Exemple #3
0
    def __init__(self, dfg, master_dfg, initial_dfg, activities, counts, rec_depth, noise_threshold=0,
                 initial_start_activities=None, initial_end_activities=None):
        """
        Constructor

        Parameters
        -----------
        dfg
            Directly follows graph of this subtree
        master_dfg
            Original DFG
        initial_dfg
            Referral directly follows graph that should be taken in account adding hidden/loop transitions
        activities
            Activities of this subtree
        counts
            Shared variable
        rec_depth
            Current recursion depth
        noise_threshold
            Noise threshold
        initial_start_activities
            Start activities of the log
        initial_end_activities
            End activities of the log
        """
        self.master_dfg = copy(master_dfg)
        self.initial_dfg = copy(initial_dfg)
        self.counts = counts
        self.rec_depth = rec_depth
        self.noise_threshold = noise_threshold
        self.initial_start_activities = initial_start_activities
        if self.initial_start_activities is None:
            self.initial_start_activities = infer_start_activities(master_dfg)
        self.initial_end_activities = initial_end_activities
        if self.initial_end_activities is None:
            self.initial_end_activities = infer_end_activities(master_dfg)

        self.second_iteration = None
        self.activities = None
        self.dfg = None
        self.outgoing = None
        self.ingoing = None
        self.self_loop_activities = None
        self.initial_ingoing = None
        self.initial_outgoing = None
        self.activities_direction = None
        self.activities_dir_list = None
        self.negated_dfg = None
        self.negated_activities = None
        self.negated_outgoing = None
        self.negated_ingoing = None
        self.detected_cut = None
        self.children = None
        self.must_insert_skip = False
        self.need_loop_on_subtree = False

        self.initialize_tree(dfg, initial_dfg, activities)

        # start/end activities of the initial log intersected with the current set of activities
        self.initial_start_activities = list(set(self.initial_start_activities).intersection(set(self.activities)))
        self.initial_end_activities = list(set(self.initial_end_activities).intersection(set(self.activities)))

        if rec_depth > 0:
            self.start_activities = list(
                set(self.initial_start_activities).union(infer_start_activities(self.dfg)).union(
                    infer_start_activities_from_prev_connections_and_current_dfg(self.initial_dfg, self.dfg,
                                                                                 self.activities)).intersection(
                    self.activities))
            self.end_activities = list(set(self.initial_end_activities).union(infer_end_activities(self.dfg)).union(
                infer_end_activities_from_succ_connections_and_current_dfg(self.initial_dfg, self.dfg,
                                                                           self.activities)).intersection(
                self.activities))
        else:
            self.start_activities = self.initial_start_activities
            self.end_activities = self.initial_end_activities

        self.detect_cut()