def test_prepare_log(self): lg = EventLog() lg.add_trace(1, ['a', 'b', 'g', 'h', 'i', 'j', 'k']) lg.add_trace(2, ['a', 'b', 'g', 'h', 'j', 'i', 'k']) lg.add_trace(3, ['a', 'b', 'g', 'h', 'i', 'k']) lg.add_trace(4, ['a', 'b', 'g', 'h', 'j', 'k']) lg.add_trace(5, ['a', 'b', 'c', 'd', 'e', 'h', 'i', 'k']) lg.add_trace(6, ['a', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e', 'h', 'i', 'k']) miner = InductiveMiner(lg) result = [ ['a', 'b', 'g', 'h', 'i', 'j', 'k'], ['a', 'b', 'g', 'h', 'j', 'i', 'k'], ['a', 'b', 'g', 'h', 'i', 'k'], ['a', 'b', 'g', 'h', 'j', 'k'], ['a', 'b', 'c', 'd', 'e', 'h', 'i', 'k'], ['a', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e', 'h', 'i', 'k']] result.sort() miner.log.sort() self.assertListEqual(miner.log, result)
def __call__(self, activities_to_keep) -> EventLog: f = EventLog() for e in self.log: if e.get_activity_name() in activities_to_keep: f.add_event(e) self.log = f return self.log
def test_extended_example(self): lg = EventLog() lg.add_trace(1, ['submit application', # a 'review application', # b 'fast forwarding', # g 'final review', # h 'supervisor signature', # i 'sign application', # j 'close application']) # k lg.add_trace(2, ['submit application', # a 'review application', # b 'fast forwarding', # c 'final review', # h 'sign application', # j 'supervisor signature', # i 'close application']) # k lg.add_trace(3, ['submit application', # a 'review application', # b 'fast forwarding', # g 'final review', # h 'supervisor signature', # i 'close application']) # k lg.add_trace(4, ['submit application', # a 'review application', # b 'fast forwarding', # g 'final review', # h 'sign application', # j 'close application']) # k lg.add_trace(5, ['submit application', # a 'review application', # b 'check documents', # c 'check financial status', # d 'write report', # e 'final review', # h 'supervisor signature', # i 'close application']) # k lg.add_trace(6, ['submit application', # a 'review application', # b 'check documents', # c 'check financial status', # d 'write report', # e 'reject report', # f 'check documents', # c 'check financial status', # d 'write report', # e 'final review', # h 'supervisor signature', # i 'close application']) # k miner = InductiveMiner(lg) tree = miner.discover() g = Graph() g = g.from_log(miner.log) d = dot.draw_graph(g) dot.render_dot(d, 'dfg_process_tree') tree.print_tree() dot.draw_process_tree(tree, 'example', format='pdf')
def __call__(self, ending_activity) -> EventLog: f = EventLog() for t in self.log.get_traces(): if t[-1].get_activity_name() is ending_activity: for e in t: f.add_event(e) self.log = f return self.log
def test_find_loop(self): log = [['d', 'e'], ['d', 'e', 'f', 'g', 'd', 'e']] tree = ProcessTree(InductiveMiner(EventLog()), log, discover=False) split = tree.find_loop() list(map(lambda sub: sub.sort(), split)) print(split) self.assertListEqual(split, [['d', 'e'], ['f', 'g']])
def test_find_seq(self): log = [['a', 'x', 'b', 'c'], ['a', 'x', 'c', 'b'], ['a', 'x', 'd', 'e'], ['a', 'x', 'd', 'e', 'f', 'd', 'e']] tree = ProcessTree(InductiveMiner(EventLog()), log, discover=False) split = tree.find_seq() self.assertListEqual(split, [['a', 'x']]) self.fail()
def test_split_loop_cut(self): log = [['d', 'e', 'f', 'g', 'd', 'e'], ['d', 'e']] miner = InductiveMiner(EventLog()) ll, lr = miner.split_log([['d', 'e'], ['f', 'g']], Cut.LOOP, log) self.assertListEqual(ll, [['d', 'e']]) self.assertListEqual(lr, [['f', 'g'], []])
def test_loop_of_one(self): lg = EventLog() lg.add_trace(1, ['a', 'b', 'b', 'c']) lg.add_trace(2, ['a', 'c']) miner = InductiveMiner(lg) tree = miner.discover() print() tree.print_tree() dot.draw_process_tree(tree, 'single_loop', format='pdf')
def __call__(self, name: str, value) -> EventLog: f = EventLog() for e in self.log: if isinstance(value, list): if e[name] in value: f.add_event(e) else: if e[name] is value: f.add_event(e) self.log = f return self.log
def test_split_para_cut(self): log = [['a', 'b'], ['b', 'a'], ['a']] miner = InductiveMiner(EventLog()) ll, lr = miner.split_log([['a'], ['b']], Cut.PARA, log) self.assertListEqual(ll, [['a']]) self.assertListEqual(lr, [['b'], []])
def test_split_max_seq_cut(self): log = [['a', 'x', 'b', 'c'], ['a', 'x', 'c', 'b'], ['a', 'd', 'e'], ['a', 'x', 'd', 'e', 'f', 'd', 'e']] miner = InductiveMiner(EventLog()) max_seq_split = [['a'], ['x'], [['b', 'c'], ['d', 'e', 'f']]] logs = miner.split_log(max_seq_split, Cut.SEQ, log) print(logs)
def test_split_excl_cut(self): log = [['a', 'b'], ['d', 'e', 'f', 'd','e'], ['d', 'e']] miner = InductiveMiner(EventLog()) ll, lr = miner.split_log([['a', 'b'], ['d', 'e', 'f']], Cut.EXCL, log) self.assertListEqual(ll, [['a', 'b']]) self.assertListEqual(lr, [['d', 'e', 'f', 'd','e'], ['d', 'e']])
def test_find_para(self): log = [['a', 'b'], ['a', 'b'], ['b', 'a']] # log = [['supervisor signature', # i # 'sign application'], # j # ['sign application', # j # 'supervisor signature']] # i tree = ProcessTree(InductiveMiner(EventLog()), log, discover=False) split = tree.find_para() split.sort() print(split) self.assertListEqual(split, [['a'], ['b']])
def __call__(self, first_activity, second_activity) -> EventLog: f = EventLog() for t in self.log.get_traces(): contains_df = False for e1, e2 in zip(t[:-1], t[1:]): if e1.get_activity_name( ) is first_activity and e2.get_activity_name( ) is second_activity: contains_df = True break if contains_df: for e in t: f.add_event(e) self.log = f return self.log
def test_find__max_seq(self): log = [['a', 'x', 'b', 'c'], ['a', 'x', 'c', 'b'], ['a', 'x', 'd', 'e'], ['a', 'x', 'd', 'e', 'f', 'd', 'e']] tree = ProcessTree(InductiveMiner(EventLog()), log, discover=False) split = tree.find_seq() list(map(lambda sub: sub.sort(), split)) for ele in split: for sub in ele: if isinstance(sub, list): sub.sort() # split.sort() self.assertListEqual(split, [['a'], ['x'], [['b', 'c'], ['d', 'e', 'f']]])
def test_find_cuts(self): log4 = [['a', 'b', 'g', 'h', 'i', 'j', 'k'], ['a', 'b', 'g', 'h', 'j', 'i', 'k'], ['a', 'b', 'g', 'h', 'i', 'k'], ['a', 'b', 'g', 'h', 'j', 'k'], ['a', 'b', 'c', 'd', 'e', 'h', 'i', 'k'], ['a', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e', 'h', 'i', 'k']] log2 = [['a', 'b', 'c'], ['a', 'c', 'b'], ['a', 'd', 'e'], ['a', 'd', 'e', 'f', 'd', 'e']] miner = InductiveMiner(EventLog()) tree = ProcessTree(miner, log2) print() tree.print_tree() dot.draw_process_tree(tree)
def test_simple_example(self): lg = EventLog() lg.add_trace(1, ['a', 'b', 'g', 'h', 'i', 'j', 'k']) lg.add_trace(2, ['a', 'b', 'g', 'h', 'j', 'i', 'k']) lg.add_trace(3, ['a', 'b', 'g', 'h', 'i', 'k']) lg.add_trace(4, ['a', 'b', 'g', 'h', 'j', 'k']) lg.add_trace(5, ['a', 'b', 'c', 'd', 'e', 'h', 'i', 'k']) lg.add_trace(6, ['a', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e', 'h', 'i', 'k']) miner = InductiveMiner(lg) tree = miner.discover() tree.print_tree() dot.draw_process_tree(tree, format='pdf')
def test_split_seq_cut(self): log = [['a', 'x', 'b', 'c'], ['a', 'x', 'c', 'b'], ['a', 'x', 'd', 'e'], ['d', 'e'], ['a', 'x', 'd', 'e', 'f', 'd', 'e']] lg = EventLog() miner = InductiveMiner(lg) ll, lr = miner.split_log([['a', 'x'], ['b', 'c', 'd', 'e', 'f']], Cut.SEQ, log) self.assertListEqual(ll, [['a', 'x'], []]) self.assertListEqual(lr, [['b', 'c'], ['c', 'b'], ['d', 'e'], ['d', 'e', 'f', 'd', 'e']])
def test_tree_to_net(self): lg = EventLog() lg.add_trace(1, ['a', 'b', 'g', 'h', 'i', 'j', 'k']) lg.add_trace(2, ['a', 'b', 'g', 'h', 'j', 'i', 'k']) lg.add_trace(3, ['a', 'b', 'g', 'h', 'i', 'k']) lg.add_trace(4, ['a', 'b', 'g', 'h', 'j', 'k']) lg.add_trace(5, ['a', 'b', 'c', 'd', 'e', 'h', 'i', 'k']) lg.add_trace(6, ['a', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e', 'h', 'i', 'k']) miner = InductiveMiner(lg) tree = miner.discover() tree.print_tree() # dot.draw_process_tree(tree, format='pdf') net = miner.tree_to_petri_net(tree) dot.draw_petri_net(net, 'process_tree_to_net')
def __parse_xes_file(context, tree): log = None trace_idx = None event = None trace_count = 0 #for trace_id for action, elem in tqdm(context): if action == __START: # starting to read parent = tree[ elem.getparent()] if elem.getparent() in tree else None if elem.tag.endswith(c.STR): if parent is not None: tree = __parse_attribute(elem, parent, elem.get(c.KEY), elem.get(c.VAL), tree) continue elif elem.tag.endswith(c.DTE): try: date = __parse_date_ciso(elem.get(c.VAL)) tree = __parse_attribute(elem, parent, elem.get(c.KEY), date, tree) except TypeError: logging.info("failed to parse date: " + str(elem.get(c.VAL))) except ValueError: logging.info("failed to parse date: " + str(elem.get(c.VAL))) continue elif elem.tag.endswith(c.BOL): if parent is not None: str_val = str(elem.get(c.VAL)).lower() if str_val == 'true': bool_val = True elif str_val == 'false': bool_val = False else: raise ValueError("failed to parse bool: " + str(elem.get(c.VAL))) tree = __parse_attribute(elem, parent, elem.get(c.KEY), bool_val, tree) continue elif elem.tag.endswith(c.INT): if parent is not None: int_val = int(elem.get(c.VAL)) tree = __parse_attribute(elem, parent, elem.get(c.KEY), int_val, tree) continue elif elem.tag.endswith(c.FLT): if parent is not None: float_val = float(elem.get(c.VAL)) tree = __parse_attribute(elem, parent, elem.get(c.KEY), float_val, tree) continue elif elem.tag.endswith(c.EVE): if event is not None: raise SyntaxError( 'file contains <event> in another <event> tag') if trace_idx is None: raise SyntaxError( 'file contains a <event> element outside of a <trace> element (trace_id is None)' ) event = Event() tree[elem] = event continue elif elem.tag.endswith(c.TRC): if trace_idx is not None: raise SyntaxError( 'file contains <trace> in another <trace> tag') trace_idx = trace_count trace_count += 1 log.add_trace(trace_idx) tree[elem] = log.traces[trace_idx] continue elif elem.tag.endswith(c.EXT): if log is None: raise SyntaxError('extension found outside of <log> tag') if elem.get(c.NME) is not None and elem.get( c.PRX) is not None and elem.get(c.URI) is not None: log.extensions[elem.attrib[c.NME]] = { c.PRX: elem.attrib[c.PRX], c.URI: elem.attrib[c.URI] } continue elif elem.tag.endswith(c.GLB): if log is None: raise SyntaxError('global found outside of <log> tag') if elem.get(c.SCP) is not None: log.globals[elem.attrib[c.SCP]] = {} tree[elem] = log.globals[elem.get(c.SCP)] continue elif elem.tag.endswith(c.CLS): if log is None: raise SyntaxError('classifier found outside of <log> tag') if elem.get(c.KYS) is not None: name, attributes = elem.attrib[c.NME], elem.attrib[c.KYS] # resolve special case; refactor with __parse_classifier if "'" in attributes: attributes = re.findall(r'\'(.*?)\'', attributes) else: attributes = attributes.split() log.classifiers[name] = attributes continue elif elem.tag.endswith(c.LOG): if log is not None: raise SyntaxError('file contains > 1 <log> tags') log = EventLog() tree[elem] = log.attributes continue elif action == __END: __clear_element(elem, tree) if elem.tag.endswith(c.EVE): if trace_idx is not None: log.add_event(event, trace_idx) event = None continue elif elem.tag.endswith(c.TRC): trace_idx = None continue elif elem.tag.endswith(c.LOG): continue return log