diff --git a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/BPMNDiscovery.java b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/BPMNDiscovery.java index 5920743c..58ba65d6 100644 --- a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/BPMNDiscovery.java +++ b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/BPMNDiscovery.java @@ -11,9 +11,9 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Queue; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -27,7 +27,6 @@ import org.openbpmn.bpmn.elements.Gateway; import org.openbpmn.bpmn.elements.SequenceFlow; import org.openbpmn.bpmn.elements.core.BPMNElement; -import org.openbpmn.bpmn.elements.core.BPMNElementEdge; import org.openbpmn.bpmn.elements.core.BPMNElementNode; import org.openbpmn.bpmn.exceptions.BPMNInvalidReferenceException; import org.openbpmn.bpmn.exceptions.BPMNInvalidTypeException; @@ -85,16 +84,13 @@ public BPMNDiscovery(DependencyGraph dependenciesGraph) { this.dependencies = (LinkedList) dependenciesGraph.getDependenciesDFA(); - - - LoopMerger loopMerger = new LoopMerger(this.dependenciesGraph.loops, dependenciesGraph.dependencyGraphWithLoop); this.loops = loopMerger.getMergedLoop(); System.out.println("loops"); System.out.println(this.loops); - System.out.println( this.dependenciesGraph.elementInformations); - System.out.println( this.dependenciesGraph.elementsName); + System.out.println(this.dependenciesGraph.elementInformations); + System.out.println(this.dependenciesGraph.elementsName); //get missing exclusive for the loops DecisionForLoop decisionForLoop = new DecisionForLoop(dependenciesGraph.exlusive, dependenciesGraph.parallelism, dependenciesGraph.inclusive, this.loops); @@ -109,7 +105,7 @@ public BPMNDiscovery(DependencyGraph dependenciesGraph) { System.out.println(decisionRelations); //get parallelism ParallelismMerger parallelismMerger = new ParallelismMerger(dependenciesGraph.parallelism, - dependenciesGraph.dependencyGraphWithLoop); + dependenciesGraph.dependencyGraph); LinkedList> parallelRelations = parallelismMerger.getParallelims(); System.out.println("parallelRelations1"); System.out.println(parallelRelations); @@ -455,7 +451,7 @@ public void DependencyGraphToBPMN() throws BPMNModelException, CloneNotSupported targetElements.add(targetElement); } try { - loopBlockConstruction(sourceElements, targetElements); +// loopBlockConstruction(sourceElements, targetElements); } catch (Exception e) { System.out.println("########### LOOP CONSTRACTION ERROR ##################"); System.out.println(e.getMessage()); @@ -477,7 +473,7 @@ public void DependencyGraphToBPMN() throws BPMNModelException, CloneNotSupported targetElements.add(targetElement); } try { - addLoopGateway(sourceElements, targetElements); +// addLoopGateway(sourceElements, targetElements); } catch (Exception e) { System.out.println("########### LOOP ERROR ##################"); System.out.println(e.getMessage()); @@ -1158,14 +1154,49 @@ private void loopBlockConstruction(List sourceElements, List 1) { - int countSqOfsSource = 0; - for (BPMNElementNode element : sourceElements) { - if (!element.getOutgoingSequenceFlows().isEmpty()) { - countSqOfsSource++; +// int countSqOfsSource = 0; +// for (BPMNElementNode element : sourceElements) { +// if (!element.getOutgoingSequenceFlows().isEmpty()) { +// countSqOfsSource++; +// } +// } + +// if (countSqOfsSource != sourceElements.size()) { + + Set gatewaysofSource = sourceElements.stream() + .flatMap(element -> process.getAllForwardNestedGateways(element).stream()) + .collect(Collectors.toSet()); + + List acceptedGateway = new ArrayList<>(); + for (BPMNElementNode bpmnElementNode : gatewaysofSource) { + List predeccessors = process.getAllPredeccessors(bpmnElementNode); + if (predeccessors.containsAll(sourceElements)) { + acceptedGateway.add(bpmnElementNode); } } + AtomicReference sourceElement = new AtomicReference<>(acceptedGateway.stream().filter(gateway -> + gateway.getIngoingSequenceFlows().stream(). + allMatch(sequenceFlow -> !acceptedGateway.contains(sequenceFlow.getSourceElement()))) + .findAny().orElse(null)); +// System.out.println("LOOP BLOCK CONSTRUCTION: " +// + sourceElements.stream().map(BPMNElement::getId).collect(Collectors.toList())); +// System.out.println(sourceElement.getId()); + if (sourceElement.get() != null) { + sourceElements.stream().flatMap(element -> element.getOutgoingSequenceFlows().stream()) + .forEach(sq -> { + if (sq.getTargetElement() instanceof Gateway) { + if(sq.getTargetElement().getOutgoingSequenceFlows().size()>1){ + sourceElement.set(null); + return; + } + }else{ + sourceElement.set(null); + return; + } + }); + } + if (sourceElement.get() == null) { - if (countSqOfsSource != sourceElements.size()) { System.out.println("LOOP BLOCK CONSTRUCTION: " + sourceElements.stream().map(BPMNElement::getId).collect(Collectors.toList())); List> sourcesAsPair = new ArrayList<>(); @@ -1287,24 +1318,72 @@ private void loopBlockConstruction(List sourceElements, List 1) { - // check if there exists a relation between the targets (relation = gateway) +// // check if there exists a relation between the targets (relation = gateway) +// List targetIds = targetElements.stream().map(BPMNElement::getId).collect(Collectors.toList()); +// +// boolean shouldConstruct = true; +// Set gatewaysofSource = targetElements.stream() +// .flatMap(element -> process.getAllBackwardNestedGateways(element).stream()) +// .collect(Collectors.toSet()); +// +// +// for (BPMNElementNode bpmnElementNode : gatewaysofSource) { +// List sucessors = process.getAllSuccesssors(bpmnElementNode); +// if (sucessors.containsAll(targetElements)) { +// shouldConstruct = false; +// break; +// } +// } + + AtomicReference targetElementTemp = new AtomicReference<>(); + // get root gateway based on the relation List targetIds = targetElements.stream().map(BPMNElement::getId).collect(Collectors.toList()); + int num = getGatewayNum(targetIds); + StringBuffer gatewayNum = new StringBuffer(); + gatewayNum.append(num); + if (!gatewayNum.toString().contentEquals("-1")) { - boolean shouldConstruct = true; - Set gatewaysofSource = targetElements.stream() - .flatMap(element -> process.getAllBackwardNestedGateways(element).stream()) - .collect(Collectors.toSet()); + targetElementTemp.set(process.getGateways().stream() + .filter(gateway -> gateway.getAttribute(GATEWAY_NUM).contentEquals(gatewayNum) && gateway.getIngoingSequenceFlows().size() <= 1).findAny() + .orElse(null)); + } else { + Set gatewaysofSource = sourceElements.stream() + .flatMap(element -> process.getAllBackwardNestedGateways(element).stream()) + .collect(Collectors.toSet()); - for (BPMNElementNode bpmnElementNode : gatewaysofSource) { - List sucessors = process.getAllSuccesssors(bpmnElementNode); - if (sucessors.containsAll(targetElements)) { - shouldConstruct = false; - break; + List acceptedGateway = new ArrayList<>(); + for (BPMNElementNode bpmnElementNode : gatewaysofSource) { + List sucessors = process.getAllSuccesssors(bpmnElementNode); + if (sucessors.containsAll(targetElements)) { + acceptedGateway.add(bpmnElementNode); + } } + targetElementTemp.set(acceptedGateway.stream().filter(gateway -> + gateway.getOutgoingSequenceFlows().stream(). + allMatch(sequenceFlow -> !acceptedGateway.contains(sequenceFlow.getTargetElement()))) + .findAny().orElse(null)); +// targetElement = bpmnElementNode; + } + + if (targetElementTemp.get() != null) { + targetElements.stream().flatMap(element -> element.getIngoingSequenceFlows().stream()) + .forEach(sq -> { + if (sq.getSourceElement() instanceof Gateway) { + if(sq.getSourceElement().getIngoingSequenceFlows().size()>1){ + targetElementTemp.set(null); + return; + } + }else{ + targetElementTemp.set(null); + return; + } + }); + } + // if no gateway added to the source elements - if (shouldConstruct) { + if (targetElementTemp.get() ==null) { System.out.println("LOOP BLOCK TARGET CONSTRUCTION: " + targetElements.stream().map(BPMNElement::getId).collect(Collectors.toList())); diff --git a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/XESAnalyzerBonitaMiner.java b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/XESAnalyzerBonitaMiner.java new file mode 100644 index 00000000..475a304e --- /dev/null +++ b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/XESAnalyzerBonitaMiner.java @@ -0,0 +1,591 @@ +package org.openbpmn.bpmn.discovery; + +import org.apache.commons.lang3.StringUtils; +import org.deckfour.xes.in.XesXmlParser; +import org.deckfour.xes.model.XEvent; +import org.deckfour.xes.model.XLog; +import org.deckfour.xes.model.XTrace; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedPseudograph; +import org.openbpmn.bpmn.discovery.model.DecisionMerger; +import org.openbpmn.bpmn.discovery.model.DependencyGraph; +import org.openbpmn.bpmn.discovery.model.LoopMerger; +import org.openbpmn.bpmn.discovery.model.ParallelismMerger; + +import java.io.File; +import java.sql.Array; +import java.util.*; + +public class XESAnalyzerBonitaMiner { + + public static void main(String[] args) { + try { + // Start timing + String fileName = "S16"; + String pathLog = "C:\\Users\\AliNourEldin\\Desktop\\da-bpmn\\generated-BPMN\\event_logs\\" + fileName + ".xes"; + String outputpath = "C:\\Users\\AliNourEldin\\Desktop\\da-bpmn\\generated-BPMN\\our\\" + fileName + ".bpmn"; + Double epsilom = 1.0; + Double frequencyNoiseRemove = 0.0; + Double frequency = 0.0; + long startTime = System.nanoTime(); + + XLog log = new XESAnalyzerBonitaMiner().readLog(pathLog); + + Map traces = new HashMap<>(); + Map> tracesList = new HashMap<>(); + + DependencyGraph dependencyGraph = generateDependencyGraph(log, traces, tracesList); + + double maxWeight = getMaxEdgeWeight(dependencyGraph.dependencyGraph); + System.out.println("Max Weight: " + maxWeight); + System.out.println(dependencyGraph.dependencyGraph.toString()); + + + //loop detection + loopDetection(dependencyGraph, traces); + System.out.println(dependencyGraph.loops); + + //get parallelism + DependencyGraph dependencyGraphNew = generateDependencyGraph(log, traces, tracesList); + dependencyGraphNew.loops.addAll(dependencyGraph.loops); + parallelDetection(dependencyGraphNew, epsilom); + dependencyGraph.parallelism.addAll(dependencyGraphNew.parallelism); + System.out.println(dependencyGraph.parallelism); + + + // add loops to dependency graph with loop + dependencyGraph.loops.forEach(loop -> { + dependencyGraph.dependencyGraphWithLoop.addEdge(loop.get(0), loop.get(1)); + }); + + + System.out.println("Start loop merge"); + LoopMerger loopMerger = new LoopMerger(dependencyGraph.loops, dependencyGraph.dependencyGraphWithLoop); + System.out.println(loopMerger.getMergedLoop()); + System.out.println("END loop merge"); + + DependencyGraph dependencyGraphNew2 = generateDependencyGraph(log, traces, tracesList); + Set> toAddToLoop = new HashSet<>(); + //extra loop + System.out.println("Start Extract loop"); + dependencyGraph.loops.forEach(edge1 -> { + dependencyGraph.loops.forEach(edge2 -> { + if (edge1 != edge2 && !edge1.get(0).equals(edge1.get(1)) && !edge2.get(0).equals(edge2.get(1))) { + System.out.println("go to test"); + System.out.println(edge1.toString() + " " + edge2.toString()); + if (dependencyGraph.parallelism.stream().anyMatch(parallel-> parallel.contains(edge1.get(1)) && parallel.contains(edge2.get(1)))){ + + System.out.println("OK***** parallel"); + System.out.print(edge1.get(0) + " "+ edge2.get(0)); + if (dependencyGraphNew2.dependencyGraph.containsEdge(edge1.get(1), edge2.get(0)) && + dependencyGraphNew2.dependencyGraph.containsEdge(edge2.get(1), edge1.get(0))) { + List loop = new ArrayList<>(); + loop.add(edge2.get(0)); + loop.add(edge1.get(1)); + toAddToLoop.add(loop); + dependencyGraph.dependencyGraphWithLoop.addEdge(loop.get(0), loop.get(1)); +// loop.clear(); +// loop.add(edge2.get(1)); +// loop.add(edge1.get(0)); +// +// toAddToLoop.add(loop); +// dependencyGraph.dependencyGraphWithLoop.addEdge(loop.get(0), loop.get(1)); + } + } + } + }); + }); + + dependencyGraph.loops.addAll(toAddToLoop); + System.out.println(dependencyGraph.loops); + System.out.println("END extra loop: "); + System.out.println("Extra parallelism: "); + loopMerger.getMergedLoop().forEach(loop -> { + if (dependencyGraph.parallelism.contains(new HashSet<>(loop.getSource())) + && dependencyGraph.parallelism.contains(new HashSet<>(loop.getTarget())) + && loop.getSource().containsAll(loop.getTarget()) && loop.getTarget().containsAll(loop.getSource()) + ) { + System.out.println(loop.getSource()); + loop.getSource().forEach(source -> { + loop.getSource().forEach(target -> { + if (!source.equals(target)) { + if (dependencyGraph.parallelism.contains(new HashSet<>(Arrays.asList(source, target)))) { + + if (dependencyGraph.vertexWeights.get(source) != dependencyGraph.vertexWeights.get(target)) { + dependencyGraph.parallelism.remove(new HashSet<>(Arrays.asList(source, target))); + } + + } + } + }); + }); + } + }); + System.out.println(dependencyGraph.parallelism); + System.out.println("End parallelism: "); + + + long startTime_1; + //get inclusive + System.out.println("Inclusive: "); + startTime_1 = System.nanoTime(); + dependencyGraph.findInclusive(); + System.out.println(dependencyGraph.inclusive); + printOutTime(startTime_1); + System.out.println("END Inclusive"); + + //get exclusive + System.out.println("Decision: "); + startTime_1 = System.nanoTime(); + dependencyGraph.findExculisve(); + System.out.println(dependencyGraph.exlusive); + DecisionMerger decisionMerger = new DecisionMerger(dependencyGraph.exlusive, dependencyGraph.dependencyGraphWithLoop); + LinkedList> decisionRelations = decisionMerger.getDecisions(); + System.out.println("Decision Relations: "); + System.out.println(decisionRelations); + printOutTime(startTime_1); + System.out.println("End Decision"); + System.out.println(dependencyGraph.dependencyGraphWithLoop.toString()); + System.out.println(dependencyGraph.dependencyGraph.toString()); + +// get sequence + BPMNDiscovery bpmnDiscovery = new BPMNDiscovery(dependencyGraph); + bpmnDiscovery.DependencyGraphToBPMN(); + bpmnDiscovery.saveMode(outputpath); + printOutTime(startTime); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void printOutTime(long startTime) { + + // Stop timing + long endTime = System.nanoTime(); + // Calculate execution time in milliseconds + long duration = (endTime - startTime) / 1_000_000; // Convert nanoseconds to milliseconds + System.out.println("Execution time: " + duration + " ms"); + } + + public XLog readLog(String filePath) throws Exception { + XesXmlParser parser = new XesXmlParser(); + if (parser.canParse(new File(filePath))) { + List logs = parser.parse(new File(filePath)); + if (!logs.isEmpty()) { + return logs.get(0); // Return the first log + } + } + throw new Exception("Unable to parse log"); + } + + public static DependencyGraph generateDependencyGraph(XLog log, Map traces, Map> tracesList) { + DependencyGraph graph = new DependencyGraph(); + for (XTrace trace : log) { + List lst = new ArrayList<>(); + String traceName = "::"; + String lastEvent = null; + for (XEvent event : trace) { + String eventName = event.getAttributes().get("concept:name").toString(); + graph.addVertex(eventName); + + + if (lastEvent != null) { + graph.addEdge(lastEvent, eventName); + } + lastEvent = eventName; + traceName += DependencyGraph.regex(eventName) + "::"; + lst.add(DependencyGraph.regex(eventName)); + } + if (traces.containsKey(traceName)) { + traces.put(traceName, traces.get(traceName) + 1); + } else { + traces.put(traceName, 1); + tracesList.put(traceName, lst); + } + graph.startActivities.add(trace.get(0).getAttributes().get("concept:name").toString()); + graph.endActivities.add(trace.get(trace.size() - 1).getAttributes().get("concept:name").toString()); + } + + //get names + graph.dependencyGraph.vertexSet().forEach(vertex -> { + graph.elementsName.put(vertex.trim(), vertex); + }); + + List startActivities = new ArrayList<>(graph.startActivities); + List endActivities = new ArrayList<>(graph.endActivities); + graph.startActivities.clear(); + graph.endActivities.clear(); + String startEvent = "start"; + graph.addVertex(startEvent); + graph.elementInformations.put(startEvent, new HashMap() {{ + put("type", "start"); + }}); + graph.elementsName.put(startEvent.trim(), startEvent); + + for (String str : startActivities) { + graph.addEdge(startEvent, str); + } + + startActivities.clear(); + startActivities.add(startEvent); + graph.startActivities.add(startEvent); + + + String endEvent = "end"; + graph.addVertex(endEvent); + graph.elementInformations.put(endEvent, new HashMap() {{ + put("type", "end"); + }}); + graph.elementsName.put(endEvent.trim(), endEvent); + + for (String str : endActivities) { + graph.addEdge(str, endEvent); +// dependencyGraph.endActivities.remove(str); + } + endActivities.clear(); + endActivities.add(endEvent); + graph.endActivities.add(endEvent); + return graph; + } + + + public static Set> extractTracePairs(XLog log) { + Set> tracePairs = new HashSet<>(); + for (XTrace trace : log) { + List events = new ArrayList<>(); + for (XEvent event : trace) { + String eventName = event.getAttributes().get("concept:name").toString(); + events.add(eventName); + } + tracePairs.add(new ArrayList<>(events)); // Add a copy for immutability concerns + } + return tracePairs; + } + + public static Set findStartActivities(Set> traces) { + Set startEvents = new HashSet<>(); + // Add the first event of each trace to the set + for (List trace : traces) { + startEvents.add(trace.get(0)); + } + + // Check if each event in the set really starts all traces it appears in + Set verifiedStartEvents = new HashSet<>(startEvents); + for (String event : startEvents) { + for (List trace : traces) { + if (!trace.get(0).equals(event)) { + verifiedStartEvents.remove(event); + break; + } + } + } + + return verifiedStartEvents; + } + + public static Set findEndActivities(Set> traces) { + Set endEvents = new HashSet<>(); + // Add the last event of each trace to the set + for (List trace : traces) { + endEvents.add(trace.get(trace.size() - 1)); + } + + + return endEvents; + } + + public static boolean areTasksConcurrent(DirectedWeightedPseudograph graph, String a, String b, double epsilon) { + + DefaultWeightedEdge edgeAtoB = graph.getEdge(a, b); + DefaultWeightedEdge edgeBtoA = graph.getEdge(b, a); + + // Condition 3: Basic requirement for concurrency + if (edgeAtoB == null || edgeBtoA == null) + return false; + double weightAtoB = graph.getEdgeWeight(edgeAtoB); + double weightBtoA = graph.getEdgeWeight(edgeBtoA); + if (weightAtoB <= 0 || weightBtoA <= 0) + return false; + + + // Adjusting for frequency-based epsilon check + double max = Math.max(weightAtoB, weightBtoA); + double sum = weightAtoB + weightBtoA; + double diff = Math.abs(weightAtoB - weightBtoA) / max; // Normalize the difference by the maximum weight + if (diff >= epsilon) + return false; + + + return true; + } + + public static Set> findAllConcurrentPairs(DirectedWeightedPseudograph graph, double epsilon) { + Set> concurrentPairs = new HashSet<>(); + List allVertices = new ArrayList<>(graph.vertexSet()); + + for (int i = 0; i < allVertices.size(); i++) { + for (int j = i + 1; j < allVertices.size(); j++) { + String taskA = allVertices.get(i); + String taskB = allVertices.get(j); + if (areTasksConcurrent(graph, taskA, taskB, epsilon)) { + Set pair = new HashSet<>(); + pair.add(taskA); + pair.add(taskB); + concurrentPairs.add(pair); + } + } + } + + return concurrentPairs; + } + + public static double getMaxEdgeWeight(DirectedWeightedPseudograph graph) { + double maxWeight = Double.NEGATIVE_INFINITY; + for (DefaultWeightedEdge edge : graph.edgeSet()) { + double weight = graph.getEdgeWeight(edge); + if (weight > maxWeight) { + maxWeight = weight; + } + } + return maxWeight; + } + + public static Map removeEdgesBasedOnFrequency(DependencyGraph dependencyGraph, double frequency, Double maxWeight) { + + Map removableList = new HashMap<>(); + Set edgesToRemove = new HashSet<>(); + + for (DefaultWeightedEdge edge : dependencyGraph.dependencyGraph.edgeSet()) { + double weight = dependencyGraph.dependencyGraph.getEdgeWeight(edge); + if (weight / maxWeight < frequency) { + edgesToRemove.add(edge); + } + } + + for (DefaultWeightedEdge edge : edgesToRemove) { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + removableList.put(source + "::" + target, dependencyGraph.dependencyGraph.getEdgeWeight(edge)); + dependencyGraph.dependencyGraph.removeEdge(source, target); + dependencyGraph.dependencyGraphWithLoop.removeEdge(source, target); + } + return removableList; + } + + + public static void parallelDetection(DependencyGraph dependencyGraph, Double epsilom) { + long startTime_1; + //remove looping edge (we dont remove a->, b->a) + Set> edgesToRemove = new HashSet<>(); + dependencyGraph.loops.forEach(loop -> { + String source = loop.get(0); + String target = loop.get(1); + + if (!(dependencyGraph.loops.stream().anyMatch(list -> list.contains(target) && list.contains(source)) + && dependencyGraph.loops.stream().anyMatch(list -> list.contains(source) && list.contains(target))) || source.contentEquals(target)) { + edgesToRemove.add(new ArrayList<>() {{ + add(source); + add(target); + }}); + } + }); + + edgesToRemove.forEach(edge -> { + Iterator parallel = edge.iterator(); + String source = parallel.next(); + String target = parallel.next(); + dependencyGraph.dependencyGraph.removeEdge(source, target); + dependencyGraph.dependencyGraph.removeEdge(target, source); + dependencyGraph.dependencyGraphWithLoop.removeEdge(source, target); + dependencyGraph.dependencyGraphWithLoop.removeEdge(target, source); + }); + + dependencyGraph.loops.clear(); + dependencyGraph.loopsL1.clear(); + System.out.println("Parallelism: "); + startTime_1 = System.nanoTime(); + dependencyGraph.dependencyGraph.edgeSet().forEach(edge -> { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + + Set parallel = new HashSet<>(); + parallel.add(source); + parallel.add(target); + + if (!source.equals(target)) { + if (!dependencyGraph.parallelism.contains(parallel) && dependencyGraph.dependencyGraph.containsEdge(target, source)) { + Set p = new HashSet<>(); + p.add(target); + p.add(source); + dependencyGraph.parallelism.add(p); + } + } + }); + + Set> tempParallelism = new HashSet<>(dependencyGraph.parallelism); + dependencyGraph.parallelism.clear(); + tempParallelism.stream().forEach(parallel -> { + Iterator it = parallel.iterator(); + String source = it.next(); + String target = it.next(); + DefaultWeightedEdge edge = dependencyGraph.dependencyGraph.getEdge(source, target); + + if (dependencyGraph.dependencyGraph.containsEdge(target, source)) { + DefaultWeightedEdge edge2 = dependencyGraph.dependencyGraph.getEdge(target, source); + double src2tgt_frequency = dependencyGraph.dependencyGraph.getEdgeWeight(edge); + double tgt2src_frequency = dependencyGraph.dependencyGraph.getEdgeWeight(edge2); +// double parallelismScore = (double) (src2tgt_frequency - tgt2src_frequency) / (src2tgt_frequency + tgt2src_frequency); + double parallelismScore = (double) (src2tgt_frequency - tgt2src_frequency) / Math.max(src2tgt_frequency, tgt2src_frequency); + if (Math.abs(parallelismScore) < epsilom) { + dependencyGraph.parallelism.add(new HashSet() {{ + add(source); + add(target); + }}); + } + } + }); + dependencyGraph.removeParallelism(); + System.out.println(dependencyGraph.parallelism); + dependencyGraph.filerParallelism(); + System.out.println(dependencyGraph.parallelism); + + printOutTime(startTime_1); + System.out.println("END Parallelism"); + } + + + public static void loopDetection(DependencyGraph dependencyGraph, Map traces) { + long startTime_1; + // loop detection + //get loop + System.out.println("Start selfLoop: "); + startTime_1 = System.nanoTime(); + + //self loop detection + Set> selfLoops = new HashSet<>(); + dependencyGraph.dependencyGraph.edgeSet().forEach(edge -> { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + List loop = new ArrayList<>(); + loop.add(source); + loop.add(target); + if (source.equals(target)) { + selfLoops.add(loop); + } + }); + System.out.println(selfLoops); + printOutTime(startTime_1); + System.out.println("END selfLoop"); + + //remove self loop + selfLoops.forEach(loop -> { + dependencyGraph.dependencyGraphWithLoop.removeEdge(loop.get(0), loop.get(1)); + dependencyGraph.dependencyGraph.addEdge(loop.get(0), loop.get(1)); + }); + + //detect short loop + Set> shortLoops = new HashSet<>(); + System.out.println("Start shortLoops: "); + startTime_1 = System.nanoTime(); + System.out.println(dependencyGraph.loops); + dependencyGraph.dependencyGraph.edgeSet().forEach(edge -> { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + + List loop = new ArrayList<>(); + loop.add(source); + loop.add(target); + + if (!shortLoops.contains(loop) && dependencyGraph.dependencyGraph.containsEdge(target, source) && + selfLoops.stream().noneMatch(list -> list.contains(source) || list.contains(target))) { + String src2tgt_loop2Pattern = "::" + source + "::" + target + "::" + source + "::"; + String tgt2src_loop2Pattern = "::" + target + "::" + source + "::" + target + "::"; + double src2tgt_loop2Frequency = 0; + double tgt2src_loop2Frequency = 0; + for (String trace : traces.keySet()) { + src2tgt_loop2Frequency += (StringUtils.countMatches(trace, src2tgt_loop2Pattern) * traces.get(trace)); + tgt2src_loop2Frequency += (StringUtils.countMatches(trace, tgt2src_loop2Pattern) * traces.get(trace)); + } + double loop2score = src2tgt_loop2Frequency + tgt2src_loop2Frequency; + if (loop2score > 0) { + List loop2 = new ArrayList<>(); + loop2.add(target); + loop2.add(source); + + shortLoops.add(loop); + shortLoops.add(loop2); + } + } + + + }); + System.out.println(shortLoops); + printOutTime(startTime_1); + System.out.println("END shortLoops"); + + //check if any self loop has a loop based on the sources of all the self loop + selfLoops.forEach(loop -> { + selfLoops.forEach(loop2 -> { + if (loop != loop2) { + String source = loop.get(0); + String target = loop2.get(0); + if (dependencyGraph.dependencyGraph.containsEdge(source, target) + && dependencyGraph.dependencyGraph.containsEdge(target, source) + && !shortLoops.contains(new ArrayList<>(Arrays.asList(source, target))) + ) { + List loop3 = new ArrayList<>(); + loop3.add(source); + loop3.add(target); + shortLoops.add(loop3); + + loop3.clear(); + loop3.add(target); + loop3.add(source); + shortLoops.add(loop3); + } + } + }); + }); + System.out.println("ShortLoops: "); + System.out.println(shortLoops); + //remove all a->b, b->a from the graph, and add all the loops to it + Set edgesToRemove = new HashSet<>(); + dependencyGraph.dependencyGraph.edgeSet().forEach(edge -> { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + if (dependencyGraph.dependencyGraph.containsEdge(target, source) && + !(shortLoops.contains(new ArrayList<>(Arrays.asList(source, target))) + || shortLoops.contains(new ArrayList<>(Arrays.asList(target, source))))) { + edgesToRemove.add(edge); + } + }); + edgesToRemove.forEach(edge -> { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + dependencyGraph.dependencyGraph.removeEdge(source, target); + dependencyGraph.dependencyGraphWithLoop.removeEdge(source, target); + }); + + //detect looping edge + Set> loopingEdges = new HashSet<>(); + System.out.println("Start looping edge: "); + startTime_1 = System.nanoTime(); + System.out.println(dependencyGraph.dependencyGraphWithLoop.toString()); + dependencyGraph.findAndRemoveLoops2(traces); + dependencyGraph.loops.addAll(selfLoops); + System.out.println(dependencyGraph.loops); + printOutTime(startTime_1); + System.out.println("END looping edge"); + } + + public static List getAllIndexes(String str, String subStr) { + List indexes = new ArrayList<>(); + int index = str.indexOf(subStr); + while (index >= 0) { + indexes.add(index); + index = str.indexOf(subStr, index + 1); + } + return indexes; + } +} diff --git a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/XESAnalyzerSplitMiner.java b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/XESAnalyzerSplitMiner.java index 11a5645c..afd254c6 100644 --- a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/XESAnalyzerSplitMiner.java +++ b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/XESAnalyzerSplitMiner.java @@ -20,10 +20,11 @@ public class XESAnalyzerSplitMiner { public static void main(String[] args) { try { // Start timing - String fileName = "M7"; + String fileName = "S0"; String pathLog = "C:\\Users\\AliNourEldin\\Desktop\\da-bpmn\\generated-BPMN\\event_logs\\" + fileName + ".xes"; String outputpath = "C:\\Users\\AliNourEldin\\Desktop\\da-bpmn\\generated-BPMN\\our\\" + fileName + ".bpmn"; Double epsilom = 1.0; + Double frequencyNoiseRemove = 0.05; Double frequency = 0.0; @@ -35,6 +36,9 @@ public static void main(String[] args) { Map> tracesList = new HashMap<>(); DependencyGraph dependencyGraph = generateDependencyGraph(log, traces, tracesList); + double maxWeight = getMaxEdgeWeight(dependencyGraph.dependencyGraph); + System.out.println("Max Weight: " + maxWeight); + //get names dependencyGraph.dependencyGraph.vertexSet().forEach(vertex -> { @@ -45,7 +49,7 @@ public static void main(String[] args) { List endActivities = new ArrayList<>(dependencyGraph.endActivities); dependencyGraph.startActivities.clear(); dependencyGraph.endActivities.clear(); - String startEvent = "start" ; + String startEvent = "start"; dependencyGraph.addVertex(startEvent); dependencyGraph.elementInformations.put(startEvent, new HashMap() {{ put("type", "start"); @@ -116,9 +120,8 @@ public static void main(String[] args) { tgt2src_loop2Frequency += (StringUtils.countMatches(trace, tgt2src_loop2Pattern) * traces.get(trace)); } double loop2score = src2tgt_loop2Frequency + tgt2src_loop2Frequency; - System.out.println(loop2score); - - if (loop2score != 0) { + if (loop2score > 0) { +// if(src2tgt_loop2Frequency>0 && tgt2src_loop2Frequency>0){ List loop2 = new ArrayList<>(); loop2.add(target); loop2.add(source); @@ -130,51 +133,150 @@ public static void main(String[] args) { } }); - - System.out.println(dependencyGraph.loops); printOutTime(startTime_1); System.out.println("END Loop"); + //remove self loop + dependencyGraph.loops.forEach(loop -> { + if (loop.get(0).equals(loop.get(1))) { + dependencyGraph.loopsL1.add(loop); + dependencyGraph.dependencyGraphWithLoop.removeEdge(loop.get(0), loop.get(0)); + dependencyGraph.dependencyGraph.addEdge(loop.get(0), loop.get(1)); + } + }); + + //get parallelism System.out.println("Parallelism: "); startTime_1 = System.nanoTime(); - - HashSet removableEdge = new HashSet<>(); - dependencyGraph.dependencyGraph.edgeSet().forEach(edge -> { String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); - boolean priorityCheck = !dependencyGraph.loops.contains(new ArrayList() {{ - add(source); - add(target); - }}) || true; + Set loop = new HashSet<>(); + loop.add(source); + loop.add(target); - if (dependencyGraph.dependencyGraph.containsEdge(target, source) && !removableEdge.contains(edge) && priorityCheck && target != source) { + if (!source.equals(target)) { + + if (!dependencyGraph.parallelism.contains(loop) && dependencyGraph.dependencyGraph.containsEdge(target, source)) { +// String src2tgt_loop2Pattern = "::" + source + "::" + target + "::" + source + "::"; +// String tgt2src_loop2Pattern = "::" + target + "::" + source + "::" + target + "::"; +// double src2tgt_loop2Frequency = 0; +// double tgt2src_loop2Frequency = 0; +// for (String trace : traces.keySet()) { +// src2tgt_loop2Frequency += (StringUtils.countMatches(trace, src2tgt_loop2Pattern) * traces.get(trace)); +// tgt2src_loop2Frequency += (StringUtils.countMatches(trace, tgt2src_loop2Pattern) * traces.get(trace)); +// } +// double loop2score = src2tgt_loop2Frequency + tgt2src_loop2Frequency; +// if(loop2score==0){ + Set loop2 = new HashSet<>(); + loop2.add(target); + loop2.add(source); + dependencyGraph.parallelism.add(loop2); + } +// } + + } + }); + + Set> tempParallelism = new HashSet<>(dependencyGraph.parallelism); + dependencyGraph.parallelism.clear(); + tempParallelism.stream().forEach(loop -> { + Iterator it = loop.iterator(); + String source = it.next(); + String target = it.next(); + DefaultWeightedEdge edge = dependencyGraph.dependencyGraph.getEdge(source, target); + + + if (dependencyGraph.dependencyGraph.containsEdge(target, source)) { DefaultWeightedEdge edge2 = dependencyGraph.dependencyGraph.getEdge(target, source); double src2tgt_frequency = dependencyGraph.dependencyGraph.getEdgeWeight(edge); double tgt2src_frequency = dependencyGraph.dependencyGraph.getEdgeWeight(edge2); - double parallelismScore = (double) (src2tgt_frequency - tgt2src_frequency) / (src2tgt_frequency + tgt2src_frequency); +// double parallelismScore = (double) (src2tgt_frequency - tgt2src_frequency) / (src2tgt_frequency + tgt2src_frequency); + double parallelismScore = (double) (src2tgt_frequency - tgt2src_frequency) / Math.max(src2tgt_frequency, tgt2src_frequency); if (Math.abs(parallelismScore) < epsilom) { - removableEdge.add(edge); - removableEdge.add(edge2); dependencyGraph.parallelism.add(new HashSet() {{ add(source); add(target); }}); - } else { - if (parallelismScore > 0) removableEdge.add(edge2); - else removableEdge.add(edge); } + } }); - dependencyGraph.dependencyGraph.removeAllEdges(removableEdge); - dependencyGraph.dependencyGraphWithLoop.removeAllEdges(removableEdge); + System.out.println(dependencyGraph.parallelism); - dependencyGraph.removeParallelismDiscovery(); + + + // Remove edges with frequency less than the threshold + Map removableEdge = removeEdgesBasedOnFrequency(dependencyGraph, frequencyNoiseRemove, maxWeight); + removableEdge.putAll(removeEdgesBasedOnFrequency(dependencyGraph, frequency, maxWeight)); + + + dependencyGraph.loops.clear(); + + //get loop + System.out.println("Loop: "); + startTime_1 = System.nanoTime(); + System.out.println(dependencyGraph.loops); + dependencyGraph.dependencyGraph.edgeSet().forEach(edge -> { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + + List loop = new ArrayList<>(); + loop.add(source); + loop.add(target); + + if (source.equals(target)) { + + dependencyGraph.loops.add(loop); + } else { + if (!dependencyGraph.loops.contains(loop) && dependencyGraph.dependencyGraph.containsEdge(target, source)) { + String src2tgt_loop2Pattern = "::" + source + "::" + target + "::" + source + "::"; + String tgt2src_loop2Pattern = "::" + target + "::" + source + "::" + target + "::"; + double src2tgt_loop2Frequency = 0; + double tgt2src_loop2Frequency = 0; + for (String trace : traces.keySet()) { + src2tgt_loop2Frequency += (StringUtils.countMatches(trace, src2tgt_loop2Pattern) * traces.get(trace)); + tgt2src_loop2Frequency += (StringUtils.countMatches(trace, tgt2src_loop2Pattern) * traces.get(trace)); + } + double loop2score = src2tgt_loop2Frequency + tgt2src_loop2Frequency; + if (loop2score > 0) { +// if(src2tgt_loop2Frequency>0 && tgt2src_loop2Frequency>0){ + List loop2 = new ArrayList<>(); + loop2.add(target); + loop2.add(source); + + dependencyGraph.loops.add(loop); + dependencyGraph.loops.add(loop2); + } + } + + } + }); + System.out.println(dependencyGraph.loops); + printOutTime(startTime_1); + System.out.println("END Loop"); + + removableEdge.keySet().forEach(edge -> { + String[] edgeVertices = edge.split("::"); + dependencyGraph.dependencyGraph.addEdge(edgeVertices[0], edgeVertices[1]); + dependencyGraph.dependencyGraph.setEdgeWeight(edgeVertices[0], edgeVertices[1], removableEdge.get(edge)); + dependencyGraph.dependencyGraphWithLoop.addEdge(edgeVertices[0], edgeVertices[1]); + dependencyGraph.dependencyGraphWithLoop.setEdgeWeight(edgeVertices[0], edgeVertices[1], removableEdge.get(edge)); + }); + + dependencyGraph.removeAllParallelismDiscovery(tempParallelism); + + removableEdge.clear(); + + // Remove edges with frequency less than the threshold + removableEdge.putAll(removeEdgesBasedOnFrequency(dependencyGraph, frequencyNoiseRemove, maxWeight)); + removableEdge.putAll(removeEdgesBasedOnFrequency(dependencyGraph, frequency, maxWeight)); + System.out.println(dependencyGraph.parallelism); dependencyGraph.filerParallelism(); System.out.println(dependencyGraph.parallelism); @@ -187,12 +289,62 @@ public static void main(String[] args) { System.out.println("END Parallelism"); + //check if there is not connected vertices in the outgoing or incomming, should add the edge from the removable edge based on teh high frequency of this edge + dependencyGraph.dependencyGraph.vertexSet().forEach(vertex -> { + if (dependencyGraph.loops.stream().noneMatch(list -> list.contains(vertex))) { + Set incomingEdges = dependencyGraph.dependencyGraph.incomingEdgesOf(vertex); + Set outgoingEdges = dependencyGraph.dependencyGraph.outgoingEdgesOf(vertex); + if (incomingEdges.isEmpty()) { + System.out.println("Incoming: " + vertex); + String maxEdge = ""; + double maxFrequency = 0; + for (String edge : removableEdge.keySet()) { + String[] edgeVertices = edge.split("::"); + if (edgeVertices[1].equals(vertex)) { + if (removableEdge.get(edge) > maxFrequency) { + maxFrequency = removableEdge.get(edge); + maxEdge = edge; + } + } + } + if (!maxEdge.isEmpty()) { + String[] edgeVertices = maxEdge.split("::"); + dependencyGraph.dependencyGraph.addEdge(edgeVertices[0], edgeVertices[1]); + dependencyGraph.dependencyGraphWithLoop.addEdge(edgeVertices[0], edgeVertices[1]); + } + } + + if (outgoingEdges.isEmpty()) { + System.out.println("Outgoing: " + vertex); + String maxEdge = ""; + double maxFrequency = 0; + for (String edge : removableEdge.keySet()) { + String[] edgeVertices = edge.split("::"); + if (edgeVertices[0].equals(vertex)) { + if (removableEdge.get(edge) > maxFrequency) { + maxFrequency = removableEdge.get(edge); + maxEdge = edge; + } + } + } + if (!maxEdge.isEmpty()) { + String[] edgeVertices = maxEdge.split("::"); + dependencyGraph.dependencyGraph.addEdge(edgeVertices[0], edgeVertices[1]); + dependencyGraph.dependencyGraphWithLoop.addEdge(edgeVertices[0], edgeVertices[1]); + } + } + } + }); + + //continue loop detection System.out.println("Loop2: "); startTime_1 = System.nanoTime(); System.out.println(dependencyGraph.loops); // dependencyGraph.getLongLoopDiscovery(); - dependencyGraph.findAndRemoveLoops(); +// dependencyGraph.findAndRemoveLoops(); + + dependencyGraph.findAndRemoveLoops2(traces); System.out.println(dependencyGraph.loops); LoopMerger loopMerger = new LoopMerger(dependencyGraph.loops, dependencyGraph.dependencyGraphWithLoop); System.out.println(loopMerger.getMergedLoop()); @@ -373,4 +525,38 @@ public static Set> findAllConcurrentPairs(DirectedWeightedPseudograp return concurrentPairs; } + + public static double getMaxEdgeWeight(DirectedWeightedPseudograph graph) { + double maxWeight = Double.NEGATIVE_INFINITY; + for (DefaultWeightedEdge edge : graph.edgeSet()) { + double weight = graph.getEdgeWeight(edge); + if (weight > maxWeight) { + maxWeight = weight; + } + } + return maxWeight; + } + + public static Map removeEdgesBasedOnFrequency(DependencyGraph dependencyGraph, double frequency, Double maxWeight) { + + Map removableList = new HashMap<>(); + Set edgesToRemove = new HashSet<>(); + + for (DefaultWeightedEdge edge : dependencyGraph.dependencyGraph.edgeSet()) { + double weight = dependencyGraph.dependencyGraph.getEdgeWeight(edge); + if (weight / maxWeight < frequency) { + edgesToRemove.add(edge); + } + } + + for (DefaultWeightedEdge edge : edgesToRemove) { + String source = dependencyGraph.dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.dependencyGraph.getEdgeTarget(edge); + removableList.put(source + "::" + target, dependencyGraph.dependencyGraph.getEdgeWeight(edge)); + dependencyGraph.dependencyGraph.removeEdge(source, target); + dependencyGraph.dependencyGraphWithLoop.removeEdge(source, target); + } + return removableList; + } + } diff --git a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/model/DependencyGraph.java b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/model/DependencyGraph.java index ef1d22df..ad4a6fda 100644 --- a/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/model/DependencyGraph.java +++ b/open-bpmn.metamodel/src/main/java/org/openbpmn/bpmn/discovery/model/DependencyGraph.java @@ -1,18 +1,10 @@ package org.openbpmn.bpmn.discovery.model; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.jgrapht.Graph; import org.jgrapht.GraphPath; import org.jgrapht.Graphs; @@ -23,19 +15,23 @@ import org.jgrapht.graph.DirectedWeightedPseudograph; import org.openbpmn.bpmn.discovery.XESAnalyzer; +import static org.openbpmn.bpmn.discovery.XESAnalyzerBonitaMiner.getAllIndexes; + public class DependencyGraph { + // Map to store vertex weights + public Map vertexWeights = new HashMap<>(); public DirectedWeightedPseudograph dependencyGraph; public DirectedWeightedPseudograph dependencyGraphWithLoop; public List startActivities; public List endActivities; public Map> elementInformations; public Map elementsName; + public Set> loopsL1; public Set> loops; public Set> parallelism; public Set> exlusive; public Set> inclusive; - public Map vertexWeights; public DependencyGraph() { dependencyGraph = new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class); @@ -49,6 +45,7 @@ public DependencyGraph() { vertexWeights = new HashMap<>(); elementInformations = new HashMap<>(); elementsName = new HashMap<>(); + loopsL1 = new HashSet<>(); } /** @@ -60,7 +57,7 @@ public void addVertex(String v1) { if (!dependencyGraph.vertexSet().contains(v1)) { dependencyGraph.addVertex(v1); dependencyGraphWithLoop.addVertex(v1); - vertexWeights.put(v1, 1); + vertexWeights.put(v1, 1.0); } else { vertexWeights.put(v1, vertexWeights.get(v1) + 1); } @@ -88,6 +85,7 @@ public void addEdge(String v1, String v2) { } } + //TODO: to remove noise from the graph public void filterGraph() { @@ -99,7 +97,7 @@ public void filerParallelism() { Iterator setIter = set.iterator(); String element1 = setIter.next(); String element2 = setIter.next(); - if (!(DependencyGraph.haveIntersectPredecessors(dependencyGraphWithLoop, element1, element2))) { + if (!(DependencyGraph.haveSamePredecessors(dependencyGraphWithLoop, element1, element2))) { iterator.remove(); } } @@ -110,14 +108,24 @@ public void removeParallelism() { Iterator setIter = set.iterator(); String element1 = setIter.next(); String element2 = setIter.next(); - if (!(loops.contains(new ArrayList<>(Arrays.asList(element1, element2))) || loops.contains(new ArrayList<>(Arrays.asList(element2, element1))))) { - dependencyGraphWithLoop.removeEdge(element1, element2); - dependencyGraphWithLoop.removeEdge(element2, element1); - } + dependencyGraphWithLoop.removeEdge(element1, element2); + dependencyGraphWithLoop.removeEdge(element2, element1); dependencyGraph.removeEdge(element1, element2); dependencyGraph.removeEdge(element2, element1); + }); + } + public void removeAllParallelismDiscovery(Set> parallelism) { + parallelism.stream().forEach(set -> { + Iterator setIter = set.iterator(); + String element1 = setIter.next(); + String element2 = setIter.next(); + + dependencyGraphWithLoop.removeEdge(element1, element2); + dependencyGraphWithLoop.removeEdge(element2, element1); + dependencyGraph.removeEdge(element1, element2); + dependencyGraph.removeEdge(element2, element1); }); } @@ -295,8 +303,337 @@ public void findAndRemoveLoops() { } }); } + } + + public void findAndRemoveLoops2(Map traces) { + loops.stream().forEach(edge -> { + dependencyGraph.addEdge(edge.get(0), edge.get(1)); + dependencyGraphWithLoop.addEdge(edge.get(0), edge.get(1)); + }); +// loops = new HashSet<>(); +// loops.addAll(loopsL1); + if (dependencyGraph != null) { + //self loop +// dependencyGraphWithLoop.vertexSet().forEach(vertex -> { +// if (dependencyGraphWithLoop.containsEdge(vertex, vertex)) { +// loops.add(new ArrayList<>(Arrays.asList(vertex, vertex))); +// } +// }); + + // remove loops from dependency graph + dependencyGraph = (DirectedWeightedPseudograph) dependencyGraphWithLoop.clone(); +// System.out.println("loops"); +// System.out.println(loops); + loops.stream().forEach(edge -> { + dependencyGraph.removeEdge(edge.get(0), edge.get(1)); + }); + + AllDirectedPaths allPaths = new AllDirectedPaths<>(dependencyGraph); + Set acceptedVertices = new HashSet<>(); + // looping edge + for (String startNode : startActivities) { + for (String endNode : endActivities) { + List> paths = allPaths.getAllPaths(startNode, endNode, true, null); + acceptedVertices.addAll(new HashSet<>(paths.stream().map(GraphPath::getVertexList).flatMap(List::stream).collect(Collectors.toSet()))); + } + } + + Set verticesInGraph = new HashSet<>(dependencyGraph.vertexSet()); + System.out.println("accepted vertices"); + System.out.println(acceptedVertices); + System.out.println(verticesInGraph); + verticesInGraph.removeAll(acceptedVertices); + + //check all outgoing edges of the not accepted vertices if it can be connected to the accepted vertices in the graph + // if yes then add the edge to the loop + for (String vertex : verticesInGraph) { + Set outgoingEdges = dependencyGraph.outgoingEdgesOf(vertex); + for (DefaultWeightedEdge edge : outgoingEdges) { + String target = dependencyGraph.getEdgeTarget(edge); + if (acceptedVertices.contains(target)) { + loops.add(new ArrayList<>(Arrays.asList(vertex, target))); + } + } + } + + System.out.println("loops2"); + System.out.println(loops); + // remove loops from dependency graph + loops.stream().forEach(edge -> { + dependencyGraph.removeEdge(edge.get(0), edge.get(1)); + }); + + + Set> shortLoop = new HashSet<>(); + + // short loop + dependencyGraph.edgeSet().forEach(edge -> { + String source = dependencyGraph.getEdgeSource(edge); + String target = dependencyGraphWithLoop.getEdgeTarget(edge); + if (Objects.equals(source, target)) { + loops.add(new ArrayList<>(Arrays.asList(source, target))); + } else if (dependencyGraph.containsEdge(target, source)) { + shortLoop.add(new ArrayList<>(Arrays.asList(source, target))); + shortLoop.add(new ArrayList<>(Arrays.asList(target, source))); + } + }); + System.out.println("loops3"); + System.out.println(shortLoop); + Iterator> iterator = shortLoop.iterator(); + while (iterator.hasNext()) { + List edge = iterator.next(); + if (!removeSafeEdge(dependencyGraph, edge.get(0), edge.get(1),true)) { + iterator.remove(); + } + } + System.out.println(shortLoop); + loops.addAll(shortLoop); + +// System.out.println("loops4"); + Set> loopingEdge = new HashSet<>(); + allPaths = new AllDirectedPaths<>(dependencyGraph); + List> orderPath = new ArrayList<>(); + + for (String startNode : startActivities) { + for (String endNode : endActivities) { + orderPath.addAll(allPaths.getAllPaths(startNode, endNode, true, null)); + } + } + orderPath.sort(Comparator.comparingDouble(GraphPath::getLength)); + + orderPath.forEach(graph -> { + System.out.println(graph.toString()); + }); + + DirectedWeightedPseudograph tempGraph = new DirectedWeightedPseudograph( + DefaultWeightedEdge.class); + + orderPath.forEach(graph -> { + System.out.println(graph.toString()); + List edges = graph.getEdgeList(); + + + for (DefaultWeightedEdge edge : edges) { + AllDirectedPaths allPaths2 = new AllDirectedPaths<>(tempGraph); + String source = graph.getGraph().getEdgeSource(edge); + String target = graph.getGraph().getEdgeTarget(edge); + System.out.println(source + "::" + target); + if (tempGraph.containsVertex(source) && tempGraph.containsVertex(target)) { + if (tempGraph.containsEdge(source, target)) { + continue; + } + + + List> paths = new ArrayList<>(); + for (String startNode : startActivities) { + for (String endNode : endActivities) { + if (tempGraph.containsVertex(startNode) && tempGraph.containsVertex(endNode)) { + paths.addAll(allPaths2.getAllPaths(startNode, endNode, true, null)); + } + } + } + +// + if (paths.stream().anyMatch(graphPath -> graphPath.getVertexList().contains(target)) + && paths.stream().anyMatch(graphPath -> graphPath.getVertexList().contains(source))) { + loopingEdge.add(new ArrayList<>(Arrays.asList(source, target))); + break; + } else { + tempGraph.addVertex(source); + tempGraph.addVertex(target); + tempGraph.addEdge(source, target); + } + } else { + + tempGraph.addVertex(source); + tempGraph.addVertex(target); + tempGraph.addEdge(source, target); + } + } + }); + System.out.println("loops4"); + System.out.println(loopingEdge); + iterator = loopingEdge.iterator(); + while (iterator.hasNext()) { + List edge = iterator.next(); + boolean isLoopingEdge = false; + for (String trace : traces.keySet()) { + + List bIndexes = getAllIndexes(trace, ":" + edge.get(1) + ":"); + // Get all indexes of ":d:" + List dIndexes = getAllIndexes(trace, ":" + edge.get(0) + ":"); + + // Print all indexes +// System.out.println("Indexes of :b:: " + bIndexes); +// System.out.println("Indexes of :d:: " + dIndexes); + + // Check which occurrences of ":b:" are before ":d:" + for (int bIndex : bIndexes) { + for (int dIndex : dIndexes) { + if (bIndex < dIndex) { + System.out.println(edge.get(1) + " is before " + edge.get(0)); + isLoopingEdge = true; + break; + } + } + if (isLoopingEdge) { + break; + } + } + if (isLoopingEdge) { + break; + } + } + + if (!isLoopingEdge) { + iterator.remove(); + } else if (!removeSafeEdge(dependencyGraph, edge.get(0), edge.get(1),true)) { + iterator.remove(); + } + } + loops.addAll(loopingEdge); + // remove loops from dependency graph + loops.stream().forEach(edge -> { + dependencyGraph.removeEdge(edge.get(0), edge.get(1)); + }); + System.out.println(loops); + System.out.println("loops5"); + System.out.println(dependencyGraph.toString()); + + + List> tempLoops = new ArrayList<>(); + Set edges = dependencyGraph.edgeSet(); + AllDirectedPaths allPaths2 = new AllDirectedPaths<>(dependencyGraph); + + orderPath.clear(); + Set endEvent = findEndNodes(dependencyGraph); + for (String startNode : startActivities) { + for (String endNode : endEvent) { + orderPath.addAll(allPaths2.getAllPaths(startNode, endNode, true, null)); + } + } + for (DefaultWeightedEdge edge : edges) { + String source = dependencyGraph.getEdgeSource(edge); + String target = dependencyGraph.getEdgeTarget(edge); + +// System.out.println(source + "::" + target); + + + if (orderPath.stream().noneMatch(graphPath -> + graphPath.getEdgeList().stream().anyMatch(edge1 -> dependencyGraph.getEdgeSource(edge1).contentEquals(source) + && dependencyGraph.getEdgeTarget(edge1).contentEquals(target)))) { + tempLoops.add(new ArrayList<>(Arrays.asList(source, target))); + } + } + + iterator = tempLoops.iterator(); + while (iterator.hasNext()) { + List edge = iterator.next(); + boolean isLoopingEdge = false; + for (String trace : traces.keySet()) { + + List bIndexes = getAllIndexes(trace, ":" + edge.get(1) + ":"); + // Get all indexes of ":d:" + List dIndexes = getAllIndexes(trace, ":" + edge.get(0) + ":"); + + // Print all indexes +// System.out.println("Indexes of :b:: " + bIndexes); +// System.out.println("Indexes of :d:: " + dIndexes); + + // Check which occurrences of ":b:" are before ":d:" + for (int bIndex : bIndexes) { + for (int dIndex : dIndexes) { + if (bIndex < dIndex) { + System.out.println(edge.get(1) + " is before " + edge.get(0)); + isLoopingEdge = true; + break; + } + } + if (isLoopingEdge) { + break; + } + } + if (isLoopingEdge) { + break; + } + } + + if (!isLoopingEdge) { + iterator.remove(); + } else if (!removeSafeEdge(dependencyGraph, edge.get(0), edge.get(1),false)) { + iterator.remove(); + } + } + loops.addAll(tempLoops); + // remove loops from dependency graph + loops.stream().forEach(edge -> { + dependencyGraph.removeEdge(edge.get(0), edge.get(1)); + }); +// System.out.println(loops); + + // old code +// AllDirectedPaths allPaths = new AllDirectedPaths<>(dependencyGraphWithLoop); +// for (String startNode : startActivities) { +// for (String endNode : endActivities) { +// List> paths = allPaths.getAllPaths(startNode, endNode, true, null); +// for (GraphPath grapthpath : paths) { +// List node = grapthpath.getVertexList(); +// for (int i = 0; i < node.size(); i++) { +// for (int j = i; j < node.size(); j++) { +// if (dependencyGraphWithLoop.containsEdge(node.get(j), node.get(i))) { +// loops.add(new ArrayList<>(Arrays.asList(node.get(j), node.get(i)))); +// } +// } +// } +// +// } +// } +// } +// +// // remove loops from dependency graph +// dependencyGraph = (DirectedWeightedPseudograph) dependencyGraphWithLoop.clone(); +// loops.stream().forEach(edge -> { +// dependencyGraph.removeEdge(edge.get(0), edge.get(1)); +// }); +// +// //self loop +//// List> tempLoops = new ArrayList<>(); +// DirectedWeightedPseudograph tempGraph = new DirectedWeightedPseudograph( +// DefaultWeightedEdge.class); +// Set edges = dependencyGraph.edgeSet(); +// AllDirectedPaths allPaths2 = new AllDirectedPaths<>(tempGraph); +// +// for (DefaultWeightedEdge edge : edges) { +// String source = dependencyGraph.getEdgeSource(edge); +// String target = dependencyGraph.getEdgeTarget(edge); +// +// if (tempGraph.containsVertex(source) && tempGraph.containsVertex(target)) { +// +// List> paths = allPaths2.getAllPaths(target, source, true, +// null); +// +// if (!paths.isEmpty()) { +// loops.add(new ArrayList<>(Arrays.asList(source, target))); +// } else { +// tempGraph.addVertex(source); +// tempGraph.addVertex(target); +// tempGraph.addEdge(source, target); +// } +// } else { +// +// tempGraph.addVertex(source); +// tempGraph.addVertex(target); +// tempGraph.addEdge(source, target); +// } +// } +// // remove loops from dependency graph +// loops.stream().forEach(edge -> { +// dependencyGraph.removeEdge(edge.get(0), edge.get(1)); +// }); + + } } /** @@ -818,7 +1155,7 @@ public static boolean haveSamePredecessors(DirectedWeightedPseudograph graph, String source, String target, boolean safe) { + DefaultWeightedEdge edge = graph.getEdge(source, target); + if (edge != null) { + if (graph.incomingEdgesOf(target).size() == 1 + || (graph.outgoingEdgesOf(source).size() == 1 && safe) + ) { + return false; + } + graph.removeEdge(edge); + return true; + } + return false; + } }