Skip to content

Commit 74f5ada

Browse files
Merge branch 'release' into next_2717
2 parents ff68799 + 93ffd5c commit 74f5ada

File tree

1 file changed

+24
-67
lines changed
  • pm4py/algo/discovery/inductive/cuts

1 file changed

+24
-67
lines changed

pm4py/algo/discovery/inductive/cuts/loop.py

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -310,79 +310,36 @@ class LoopCutDFG(LoopCut[IMDataStructureDFG]):
310310
@classmethod
311311
def project(
312312
cls,
313-
obj: IMDataStructureDFG,
313+
obj: IMDataStructureUVCL,
314314
groups: List[Collection[Any]],
315315
parameters: Optional[Dict[str, Any]] = None,
316316
) -> List[IMDataStructureDFG]:
317-
"""
318-
Project the original DFG onto the loop cut groups.
319-
320-
groups[0] is the 'do' part, groups[1:] are one or more 'redo' parts.
321-
322-
Semantics:
323-
- For every group, we keep all intra-group edges with their original weights.
324-
- For the 'do' part: start/end activities are the original start/end activities restricted to the group.
325-
- For each 'redo' part: start activities are the group nodes that have incoming edges from outside the group;
326-
end activities are the group nodes that have outgoing edges to outside the group. We aggregate their
327-
frequencies from the boundary edges. If none are found (edge-case), we fall back to marking all nodes
328-
as both start and end with weight 1 to keep the sub-DFG well-formed.
329-
- Skippability: do-part is NOT skippable (must run at least once in a loop).
330-
Every redo-part IS skippable (redo can repeat zero times).
331-
"""
332-
original: DFG = obj.dfg
333-
334-
# Precompute for convenience/performance
335-
edges = original.graph # Dict[(a,b) -> weight]
336-
start_acts = original.start_activities # Dict[a -> weight]
337-
end_acts = original.end_activities # Dict[a -> weight]
338-
339-
group_sets = [set(g) for g in groups]
340-
dfgs: List[DFG] = []
341-
skippable: List[bool] = [False] + [True] * max(0, (len(groups) - 1))
342-
343-
for idx, g in enumerate(group_sets):
344-
sub = DFG()
345-
346-
# 1) Copy intra-group edges with their weights
347-
for (a, b), w in edges.items():
317+
dfg = obj.dfg
318+
dfgs = []
319+
skippable = [False, False]
320+
for gind, g in enumerate(groups):
321+
dfn = DFG()
322+
for a, b in dfg.graph:
348323
if a in g and b in g:
349-
sub.graph[(a, b)] = w
350-
351-
if idx == 0:
352-
# 2) DO part: restrict original start/end to the group
353-
for a, w in start_acts.items():
324+
dfn.graph[(a, b)] = dfg.graph[(a, b)]
325+
if b in dfg.start_activities and a in dfg.end_activities:
326+
skippable[1] = True
327+
if gind == 0:
328+
for a in dfg.start_activities:
354329
if a in g:
355-
sub.start_activities[a] = w
356-
for a, w in end_acts.items():
330+
dfn.start_activities[a] = dfg.start_activities[a]
331+
else:
332+
skippable[0] = True
333+
for a in dfg.end_activities:
357334
if a in g:
358-
sub.end_activities[a] = w
359-
else:
360-
# 3) REDO part: derive starts/ends from boundary edges
361-
start_counts: Dict[Any, int] = {}
362-
end_counts: Dict[Any, int] = {}
363-
364-
# Entries into the group (from outside) -> starts
365-
# Exits from the group (to outside) -> ends
366-
for (a, b), w in edges.items():
367-
if b in g and a not in g:
368-
start_counts[b] = start_counts.get(b, 0) + w
369-
if a in g and b not in g:
370-
end_counts[a] = end_counts.get(a, 0) + w
371-
372-
# Fallback to keep the sub-DFG well-formed (very rare, but safe)
373-
if not start_counts:
374-
for a in g:
375-
start_counts[a] = 1
376-
if not end_counts:
377-
for a in g:
378-
end_counts[a] = 1
379-
380-
sub.start_activities.update(start_counts)
381-
sub.end_activities.update(end_counts)
382-
383-
dfgs.append(sub)
384-
385-
# Wrap each projected DFG as an InductiveDFG with correct skippability
335+
dfn.end_activities[a] = dfg.end_activities[a]
336+
else:
337+
skippable[0] = True
338+
elif gind == 1:
339+
for a in g:
340+
dfn.start_activities[a] = 1
341+
dfn.end_activities[a] = 1
342+
dfgs.append(dfn)
386343
return [
387344
IMDataStructureDFG(InductiveDFG(dfg=dfgs[i], skip=skippable[i]))
388345
for i in range(len(dfgs))

0 commit comments

Comments
 (0)