What does "Exception: Loop doesn't have 2 childs" mean?
galenseilis opened this issue · 4 comments
I have an event log with 1034827 rows. After preparing it with pm4py.format_dataframe
and running pm4py.discover_process_tree_inductive
the result, I then ran pm4py.convert_to_bpmn
in which it seems to have run into Exception: Loop doesn't have 2 childs
.
I don't know the inner workings of PM4Py to infer what this means, but I know this code works on a handful of subsets of the data. Is 1034827 too much? Or is there a data quality issue that that needs to be addressed? Or something else?
Here is the part of my traceback concerning PM4Py (the rest is Kedro pipeline calls that I don't think have any relevance).
│ │
│ 17 │ │ │ name='mine_process_tree' │
│ 18 │ │ ), │
│ 19 │ │ node( │
│ > 20 │ │ │ func=lambda tree: pm4py.convert_to_bpmn(tree), │
│ 21 │ │ │ inputs='process_tree', │
│ 22 │ │ │ outputs='bpmn_model', │
│ 23 │ │ │ name='make_bpmn_model' │
│ │
\pm4py\convert.py:160 in convert_to_bpmn │
│ │
│ 157 │ │ return args[0] │
│ 158 │ elif isinstance(args[0], ProcessTree): │
│ 159 │ │ from pm4py.objects.conversion.process_tree.variants import to_bpmn │
│ > 160 │ │ return to_bpmn.apply(args[0]) │
│ 161 │ else: │
│ 162 │ │ # try to convert the object to a Petri net. Then, use the PM4Py PN-to-BPMN conve │
│ 163 │ │ # to get the BPMN object │
│ │
| \pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:257 in apply │
│ │
│ 254 │ end_event = BPMN.NormalEndEvent(name="end") │
│ 255 │ bpmn.add_node(start_event) │
│ 256 │ bpmn.add_node(end_event) │
│ > 257 │ bpmn, counts, _, _ = recursively_add_tree(tree, tree, bpmn, start_event, end_event, │
│ 258 │ bpmn = delete_tau_transitions(bpmn, counts) │
│ 259 │ │
│ 260 │ for node in bpmn.get_nodes(): │
│ │
| \pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:179 in recursively_add_tree │
│ │
│ 176 │ │ initial_intermediate_task = initial_event │
│ 177 │ │ bpmn, final_intermediate_task, counts = add_tau_task(bpmn, counts) │
│ 178 │ │ for i in range(len(tree_childs)): │
│ > 179 │ │ │ bpmn, counts, initial_connect, final_connect = recursively_add_tree(tree, tr │
│ 180 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ initial_ │
│ 181 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ final_in │
│ 182 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ rec_dept │
│ │
| \pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:156 in recursively_add_tree │
│ │
│ 153 │ elif tree.operator == Operator.PARALLEL: │
│ 154 │ │ bpmn, split_gateway, join_gateway, counts = add_parallel_gateway(bpmn, counts) │
│ 155 │ │ for subtree in tree_childs: │
│ > 156 │ │ │ bpmn, counts, x, y = recursively_add_tree(tree, subtree, bpmn, split_gateway │
│ 157 │ │ │ │ │ │ │ │ │ │ │ │ │ counts, │
│ 158 │ │ │ │ │ │ │ │ │ │ │ │ │ rec_depth + 1) │
│ 159 │ │ bpmn.add_flow(BPMN.Flow(initial_event, split_gateway)) │
│ │
| \pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:179 in recursively_add_tree │
│ │
│ 176 │ │ initial_intermediate_task = initial_event │
│ 177 │ │ bpmn, final_intermediate_task, counts = add_tau_task(bpmn, counts) │
│ 178 │ │ for i in range(len(tree_childs)): │
│ > 179 │ │ │ bpmn, counts, initial_connect, final_connect = recursively_add_tree(tree, tr │
│ 180 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ initial_ │
│ 181 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ final_in │
│ 182 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ rec_dept │
│ │
│ \pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:156 in recursively_add_tree │
│ │
│ 153 │ elif tree.operator == Operator.PARALLEL: │
│ 154 │ │ bpmn, split_gateway, join_gateway, counts = add_parallel_gateway(bpmn, counts) │
│ 155 │ │ for subtree in tree_childs: │
│ > 156 │ │ │ bpmn, counts, x, y = recursively_add_tree(tree, subtree, bpmn, split_gateway │
│ 157 │ │ │ │ │ │ │ │ │ │ │ │ │ counts, │
│ 158 │ │ │ │ │ │ │ │ │ │ │ │ │ rec_depth + 1) │
│ 159 │ │ bpmn.add_flow(BPMN.Flow(initial_event, split_gateway)) │
│ │
│\pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:179 in recursively_add_tree │
│ │
│ 176 │ │ initial_intermediate_task = initial_event │
│ 177 │ │ bpmn, final_intermediate_task, counts = add_tau_task(bpmn, counts) │
│ 178 │ │ for i in range(len(tree_childs)): │
│ > 179 │ │ │ bpmn, counts, initial_connect, final_connect = recursively_add_tree(tree, tr │
│ 180 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ initial_ │
│ 181 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ final_in │
│ 182 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ rec_dept │
│ │
│\pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:199 in recursively_add_tree │
│ │
│ 196 │ │ │ do = tree_childs[0] │
│ 197 │ │ │ redo = tree_childs[1] │
│ 198 │ │ │ bpmn, split, join, counts = add_xor_gateway(bpmn, counts) │
│ > 199 │ │ │ bpmn, counts, i, y = recursively_add_tree(tree, do, bpmn, join, split, count │
│ 200 │ │ │ bpmn, counts, x, y = recursively_add_tree(tree, redo, bpmn, split, join, cou │
│ 201 │ │ │ bpmn.add_flow(BPMN.Flow(initial_event, join)) │
│ 202 │ │ │ bpmn.add_flow(BPMN.Flow(split, final_event)) │
│ │
│ \pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:145 in recursively_add_tree │
│ │
│ 142 │ elif tree.operator == Operator.XOR: │
│ 143 │ │ bpmn, split_gateway, join_gateway, counts = add_xor_gateway(bpmn, counts) │
│ 144 │ │ for subtree in tree_childs: │
│ > 145 │ │ │ bpmn, counts, x, y = recursively_add_tree(tree, subtree, bpmn, split_gateway │
│ 146 │ │ │ │ │ │ │ │ │ │ │ │ │ counts, │
│ 147 │ │ │ │ │ │ │ │ │ │ │ │ │ rec_depth + 1) │
│ 148 │ │ bpmn.add_flow(BPMN.Flow(initial_event, split_gateway)) │
│ │
│\pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:156 in recursively_add_tree │
│ │
│ 153 │ elif tree.operator == Operator.PARALLEL: │
│ 154 │ │ bpmn, split_gateway, join_gateway, counts = add_parallel_gateway(bpmn, counts) │
│ 155 │ │ for subtree in tree_childs: │
│ > 156 │ │ │ bpmn, counts, x, y = recursively_add_tree(tree, subtree, bpmn, split_gateway │
│ 157 │ │ │ │ │ │ │ │ │ │ │ │ │ counts, │
│ 158 │ │ │ │ │ │ │ │ │ │ │ │ │ rec_depth + 1) │
│ 159 │ │ bpmn.add_flow(BPMN.Flow(initial_event, split_gateway)) │
│ │
│\pm4py\objects\conversion\process_tree\variants │
│ \to_bpmn.py:194 in recursively_add_tree │
│ │
│ 191 │ │
│ 192 │ elif tree.operator == Operator.LOOP: │
│ 193 │ │ if len(tree_childs) != 2: │
│ > 194 │ │ │ raise Exception("Loop doesn't have 2 childs") │
│ 195 │ │ else: │
│ 196 │ │ │ do = tree_childs[0] │
│ 197 │ │ │ redo = tree_childs[1]
Dear @galenseilis
Could you confirm you have the latest version of pm4py version 2.7.5?
Dear @galenseilis
Could you confirm you have the latest version of pm4py version 2.7.5?
Yes, I can confirm that:
>>> pm4py.__version__
'2.7.5'
Also, I am using Python 3.10.4, if that makes any difference. The OS is Windows Server 2019 Standard.
Thanks for signaling. We'll release a fix for this in the next release.
In the meanwhile, you can use the following workaround:
pm4py.convert_to_bpmn(*pm4py.convert_to_petri_net(tree))