def __get_end_activity_set_binary_tree(pt: ProcessTree, ea_set=None) -> Set[str]: assert pt.children is None or len(pt.children) <= 2 if ea_set is None: ea_set = set() if is_leaf(pt) and not is_tau_leaf(pt): ea_set.add(pt.label) elif not is_tau_leaf(pt): assert len(pt.children) == 2 tau_in_language_sub_pt_1 = __check_empty_sequence_accepted( pt.children[0]) tau_in_language_sub_pt_2 = __check_empty_sequence_accepted( pt.children[1]) if pt.operator == Operator.SEQUENCE: if not tau_in_language_sub_pt_2: return __get_end_activity_set_binary_tree( pt.children[1], ea_set) else: for c in pt.children: ea_set.union(__get_end_activity_set_binary_tree(c, ea_set)) elif pt.operator == Operator.PARALLEL or pt.operator == Operator.XOR: for c in pt.children: ea_set.union(__get_end_activity_set_binary_tree(c, ea_set)) elif pt.operator == Operator.LOOP: if not tau_in_language_sub_pt_1: return __get_end_activity_set_binary_tree( pt.children[0], ea_set) else: for c in pt.children: ea_set.union(__get_end_activity_set_binary_tree(c, ea_set)) return ea_set
def get_number_inner_nodes(pt: ProcessTree) -> int: if is_leaf(pt): return 0 else: res = 1 for c in pt.children: res += get_number_inner_nodes(c) return res
def __get_activity_set(pt: ProcessTree, a_set=None) -> Set[str]: if a_set is None: a_set = set() if is_leaf(pt): a_set.add(pt.label) else: for c in pt.children: __get_activity_set(c, a_set) return a_set
def get_process_tree_height(pt: ProcessTree) -> int: """ calculates from the given node the max height downwards :param pt: process tree node :return: height """ if is_leaf(pt): return 1 else: return 1 + max([get_process_tree_height(x) for x in pt.children])
def can_close(tree: ProcessTree, state: ProcessTreeState) -> bool: if ptu.is_leaf(tree): return ptu.is_in_state(tree, ProcessTree.OperatorState.OPEN, state) elif ptu.is_any_operator_of(tree, {Operator.SEQUENCE, Operator.PARALLEL, Operator.XOR}): return frozenset(map(lambda child: state[(id(child), child)], tree.children)) == { ProcessTree.OperatorState.CLOSED} elif ptu.is_any_operator_of(tree, {Operator.OR}): return frozenset(map(lambda child: state[(id(child), child)], tree.children)) == { ProcessTree.OperatorState.CLOSED, ProcessTree.OperatorState.FUTURE} elif ptu.is_operator(tree, Operator.LOOP): return ptu.is_in_state(tree.children[0], ProcessTree.OperatorState.CLOSED, state) and ptu.is_in_state( tree.children[1], ProcessTree.OperatorState.FUTURE, state)
def shortest_path_to_close(tree: ProcessTree, state: ProcessTreeState) -> Tuple[ List[Tuple[ProcessTree, ProcessTree.OperatorState]], ProcessTreeState]: if ptu.is_in_state(tree, ProcessTree.OperatorState.CLOSED, state): return list(), state fast_path, fast_state = close_vertex(tree, state) if fast_state is not None: return fast_path, fast_state path, state = shortest_path_to_open(tree, state) if ptu.is_leaf(tree): e_path, state = close_vertex(tree, state) path.extend(e_path) return path, state elif ptu.is_any_operator_of(tree, {Operator.SEQUENCE, Operator.PARALLEL}): for c in tree.children: e_path, state = shortest_path_to_close(c, state) path.extend(e_path) elif ptu.is_operator(tree, Operator.LOOP): if state[(id(tree.children[0]), tree.children[0])] in {ProcessTree.OperatorState.ENABLED, ProcessTree.OperatorState.OPEN}: e_path, state = shortest_path_to_close(tree.children[0], state) path.extend(e_path) elif state[(id(tree.children[1]), tree.children[1])] in {ProcessTree.OperatorState.ENABLED, ProcessTree.OperatorState.OPEN}: e_path, state = shortest_path_to_close(tree.children[1], state) path.extend(e_path) e_path, state = shortest_path_to_open(tree.children[0], state) path.extend(e_path) e_path, state = shortest_path_to_close(tree.children[0], state) path.extend(e_path) elif tree.operator in {Operator.XOR, Operator.OR}: busy = False for c in tree.children: if state[(id(c), c)] in {ProcessTree.OperatorState.ENABLED, ProcessTree.OperatorState.OPEN}: e_path, state = shortest_path_to_close(c, state) path.extend(e_path) busy = True if not busy: cur_path, cur_state, cur_path_costs = list(), copy.copy(state), sys.maxsize for c in tree.children: if state[(id(c), c)] != ProcessTree.OperatorState.CLOSED: candidate_p, candidate_s = shortest_path_to_close(c, state) candidate_costs = len(list(filter(lambda t: t[0].operator is None and t[0].label is not None and t[ 1] == ProcessTree.OperatorState.OPEN, candidate_p))) if candidate_costs < cur_path_costs: cur_path, cur_state, cur_path_costs = candidate_p, candidate_s, candidate_costs path.extend(cur_path) state = cur_state e_path, state = close_vertex(tree, state) path.extend(e_path) return path, state
def __check_empty_sequence_accepted(pt: ProcessTree) -> bool: if is_leaf(pt): if is_tau_leaf(pt): return True else: return False else: assert len(pt.children) == 2 if pt.operator == Operator.SEQUENCE or pt.operator == Operator.PARALLEL: return __check_empty_sequence_accepted(pt.children[0]) and __check_empty_sequence_accepted(pt.children[1]) elif pt.operator == Operator.XOR: return __check_empty_sequence_accepted(pt.children[0]) or __check_empty_sequence_accepted(pt.children[1]) else: assert pt.operator == Operator.LOOP return __check_empty_sequence_accepted(pt.children[0])