Skip to content

Commit 2b34ef8

Browse files
committed
Added option to change the target number of routing transitions to
reduce down to. The lower this number,the less precise the model will be.
1 parent 2469c1d commit 2b34ef8

File tree

3 files changed

+165
-107
lines changed

3 files changed

+165
-107
lines changed

src/org/processmining/discover/algorithms/DiscoverPetriNetAlgorithm.java

Lines changed: 126 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -251,41 +251,46 @@ public AcceptingPetriNet apply(PluginContext context, XLog eventLog, ProcessTree
251251
+ (System.currentTimeMillis() - time) + " milliseconds.");
252252
}
253253

254-
int nofA = 0;
255-
int nofI = 0;
256-
for (Transition t : apn.getNet().getTransitions()) {
257-
if (!t.isInvisible() || t.getLabel().equals(ActivityAlphabet.START)
258-
|| t.getLabel().equals(ActivityAlphabet.END)) {
259-
nofA++;
260-
} else {
261-
nofI++;
262-
}
263-
}
264-
// Let's try to aim for less silent transitions then other transitions.
265-
while (nofI > nofA) {
266-
ReduceUsingMurataRulesAlgorithm redAlgorithm = new ReduceUsingMurataRulesAlgorithm();
267-
ReduceUsingMurataRulesParameters redParameters = new ReduceUsingMurataRulesParameters();
268-
System.out.println("[DiscoverPetriNetAlgorithm] Reducing clusters");
269-
reduceSilentClusters(apn);
270-
System.out.println("[DiscoverPetriNetAlgorithm] Reducing using rules...");
271-
apn = redAlgorithm.apply(context, apn, redParameters);
272-
int nofA2 = 0;
273-
int nofI2 = 0;
254+
if (parameters.getMaxNofRoutingTransitions() > 0) {
255+
int nofNonRoutingTransitions = 0;
256+
int nofRoutingTransitions = 0;
274257
for (Transition t : apn.getNet().getTransitions()) {
275258
if (!t.isInvisible() || t.getLabel().equals(ActivityAlphabet.START)
276259
|| t.getLabel().equals(ActivityAlphabet.END)) {
277-
nofA2++;
260+
nofNonRoutingTransitions++;
278261
} else {
279-
nofI2++;
262+
nofRoutingTransitions++;
280263
}
281264
}
282-
if (nofA2 == nofA && nofI2 == nofI) {
283-
// No reductions possible anymore.
284-
nofI = -1;
285-
} else {
286-
// Some reductions were done, try next iteration.
287-
nofA = nofA2;
288-
nofI = nofI2;
265+
// Let's try to aim for less silent transitions then other transitions.
266+
while (nofRoutingTransitions > parameters.getMaxNofRoutingTransitions()) {
267+
ReduceUsingMurataRulesAlgorithm redAlgorithm = new ReduceUsingMurataRulesAlgorithm();
268+
ReduceUsingMurataRulesParameters redParameters = new ReduceUsingMurataRulesParameters();
269+
System.out.println("[DiscoverPetriNetAlgorithm] Reducing clusters");
270+
reduceSilentClusters(apn, parameters);
271+
System.out.println("[DiscoverPetriNetAlgorithm] Reducing using rules...");
272+
apn = redAlgorithm.apply(context, apn, redParameters);
273+
int nofNonRoutingTransitions2 = 0;
274+
int nofRoutingTransitions2 = 0;
275+
for (Transition t : apn.getNet().getTransitions()) {
276+
if (!t.isInvisible() || t.getLabel().equals(ActivityAlphabet.START)
277+
|| t.getLabel().equals(ActivityAlphabet.END)) {
278+
nofNonRoutingTransitions2++;
279+
} else {
280+
nofRoutingTransitions2++;
281+
}
282+
}
283+
if (nofNonRoutingTransitions2 == nofNonRoutingTransitions
284+
&& nofRoutingTransitions2 == nofRoutingTransitions) {
285+
// No reductions possible anymore.
286+
System.out.println("[DiscoverPetriNetAlgorithm] No more reductions possible");
287+
nofRoutingTransitions = -1;
288+
} else {
289+
// Some reductions were done, try next iteration.
290+
nofNonRoutingTransitions = nofNonRoutingTransitions2;
291+
nofRoutingTransitions = nofRoutingTransitions2;
292+
}
293+
System.out.println("[DiscoverPetriNetAlgorithm] Continuing with " + nofRoutingTransitions + " routing transitions");
289294
}
290295
}
291296
// fixEnhancements(context, apn, parameters);
@@ -1069,7 +1074,15 @@ private boolean areEquivalent(List<List<String>> playOut, String source, String
10691074
return true;
10701075
}
10711076

1072-
private void reduceSilentClusters(AcceptingPetriNet apn) {
1077+
private void reduceSilentClusters(AcceptingPetriNet apn, DiscoverPetriNetParameters parameters) {
1078+
int nofRoutingTransitions = 0;
1079+
for (Transition t : apn.getNet().getTransitions()) {
1080+
if (!t.isInvisible() || t.getLabel().equals(ActivityAlphabet.START)
1081+
|| t.getLabel().equals(ActivityAlphabet.END)) {
1082+
} else {
1083+
nofRoutingTransitions++;
1084+
}
1085+
}
10731086
Map<PetrinetNode, Set<PetrinetNode>> preset = new HashMap<PetrinetNode, Set<PetrinetNode>>();
10741087
Map<PetrinetNode, Set<PetrinetNode>> postset = new HashMap<PetrinetNode, Set<PetrinetNode>>();
10751088
for (PetrinetNode node : apn.getNet().getNodes()) {
@@ -1082,108 +1095,115 @@ private void reduceSilentClusters(AcceptingPetriNet apn) {
10821095
}
10831096
Set<Place> places = new HashSet<Place>();
10841097
Set<List<Transition>> clusters = new HashSet<List<Transition>>();
1085-
for (Transition t1 : apn.getNet().getTransitions()) {
1086-
if (!t1.isInvisible() || t1.getLabel().equals(ActivityAlphabet.START)
1087-
|| t1.getLabel().equals(ActivityAlphabet.END)) {
1088-
continue;
1089-
}
1090-
Place pre_t1 = (Place) preset.get(t1).iterator().next();
1091-
Place post_t1 = (Place) postset.get(t1).iterator().next();
1092-
if (pre_t1 == post_t1) {
1093-
continue;
1094-
}
1095-
if (places.contains(pre_t1) || places.contains(post_t1)) {
1096-
continue;
1097-
}
1098-
for (PetrinetNode n2 : postset.get(pre_t1)) {
1099-
Transition t2 = (Transition) n2;
1100-
if (t2 == t1) {
1098+
if (nofRoutingTransitions > parameters.getMaxNofRoutingTransitions()) {
1099+
for (Transition t1 : apn.getNet().getTransitions()) {
1100+
if (!t1.isInvisible() || t1.getLabel().equals(ActivityAlphabet.START)
1101+
|| t1.getLabel().equals(ActivityAlphabet.END)) {
11011102
continue;
11021103
}
1103-
if (!t2.isInvisible() || t2.getLabel().equals(ActivityAlphabet.START)
1104-
|| t2.getLabel().equals(ActivityAlphabet.END)) {
1104+
Place pre_t1 = (Place) preset.get(t1).iterator().next();
1105+
Place post_t1 = (Place) postset.get(t1).iterator().next();
1106+
if (pre_t1 == post_t1) {
11051107
continue;
11061108
}
1107-
Place post_t2 = (Place) postset.get(t2).iterator().next();
1108-
if (post_t2 == pre_t1 || post_t2 == post_t1) {
1109+
if (places.contains(pre_t1) || places.contains(post_t1)) {
11091110
continue;
11101111
}
1111-
if (places.contains(post_t2)) {
1112-
continue;
1113-
}
1114-
for (PetrinetNode n3 : preset.get(post_t1)) {
1115-
Transition t3 = (Transition) n3;
1116-
if (t3 == t2 || t3 == t1) {
1112+
for (PetrinetNode n2 : postset.get(pre_t1)) {
1113+
Transition t2 = (Transition) n2;
1114+
if (t2 == t1) {
11171115
continue;
11181116
}
1119-
if (!t3.isInvisible() || t3.getLabel().equals(ActivityAlphabet.START)
1120-
|| t3.getLabel().equals(ActivityAlphabet.END)) {
1117+
if (!t2.isInvisible() || t2.getLabel().equals(ActivityAlphabet.START)
1118+
|| t2.getLabel().equals(ActivityAlphabet.END)) {
11211119
continue;
11221120
}
1123-
Place pre_t3 = (Place) preset.get(t3).iterator().next();
1124-
if (pre_t3 == pre_t1 || pre_t3 == post_t1 || pre_t3 == post_t2) {
1121+
Place post_t2 = (Place) postset.get(t2).iterator().next();
1122+
if (post_t2 == pre_t1 || post_t2 == post_t1) {
11251123
continue;
11261124
}
1127-
if (places.contains(pre_t3)) {
1125+
if (places.contains(post_t2)) {
11281126
continue;
11291127
}
1130-
for (PetrinetNode n4 : postset.get(pre_t3)) {
1131-
Transition t4 = (Transition) n4;
1132-
if (t4 == t3 || t4 == t2 || t4 == t1) {
1128+
for (PetrinetNode n3 : preset.get(post_t1)) {
1129+
Transition t3 = (Transition) n3;
1130+
if (t3 == t2 || t3 == t1) {
11331131
continue;
11341132
}
1135-
if (!t4.isInvisible() || t4.getLabel().equals(ActivityAlphabet.START)
1136-
|| t4.getLabel().equals(ActivityAlphabet.END)) {
1133+
if (!t3.isInvisible() || t3.getLabel().equals(ActivityAlphabet.START)
1134+
|| t3.getLabel().equals(ActivityAlphabet.END)) {
11371135
continue;
11381136
}
1139-
if (postset.get(t4).iterator().next() != post_t2) {
1137+
Place pre_t3 = (Place) preset.get(t3).iterator().next();
1138+
if (pre_t3 == pre_t1 || pre_t3 == post_t1 || pre_t3 == post_t2) {
11401139
continue;
11411140
}
1142-
List<Transition> cluster = new ArrayList<Transition>();
1143-
cluster.add(t1);
1144-
cluster.add(t2);
1145-
cluster.add(t3);
1146-
cluster.add(t4);
1147-
clusters.add(cluster);
1148-
places.add(pre_t1);
1149-
places.add(post_t1);
1150-
places.add(post_t2);
1151-
places.add(pre_t3);
1141+
if (places.contains(pre_t3)) {
1142+
continue;
1143+
}
1144+
for (PetrinetNode n4 : postset.get(pre_t3)) {
1145+
Transition t4 = (Transition) n4;
1146+
if (t4 == t3 || t4 == t2 || t4 == t1) {
1147+
continue;
1148+
}
1149+
if (!t4.isInvisible() || t4.getLabel().equals(ActivityAlphabet.START)
1150+
|| t4.getLabel().equals(ActivityAlphabet.END)) {
1151+
continue;
1152+
}
1153+
if (postset.get(t4).iterator().next() != post_t2) {
1154+
continue;
1155+
}
1156+
List<Transition> cluster = new ArrayList<Transition>();
1157+
cluster.add(t1);
1158+
cluster.add(t2);
1159+
cluster.add(t3);
1160+
cluster.add(t4);
1161+
clusters.add(cluster);
1162+
places.add(pre_t1);
1163+
places.add(post_t1);
1164+
places.add(post_t2);
1165+
places.add(pre_t3);
1166+
}
11521167
}
11531168
}
11541169
}
1155-
}
1156-
for (List<Transition> cluster : clusters) {
1157-
System.out.println("[DiscoverPetriNetAlgorithm] Reducing " + cluster);
1158-
Transition t1 = cluster.get(0);
1159-
Place p1 = (Place) preset.get(t1).iterator().next();
1160-
Place p2 = (Place) postset.get(t1).iterator().next();
1161-
Transition t2 = cluster.get(3);
1162-
Place p3 = (Place) preset.get(t2).iterator().next();
1163-
Place p4 = (Place) postset.get(t2).iterator().next();
1164-
// Remove transitions (and edges connected to them)
1165-
apn.getNet().removeTransition(cluster.get(1));
1166-
apn.getNet().removeTransition(cluster.get(2));
1167-
apn.getNet().removeTransition(cluster.get(3));
1168-
// Reroute arcs from p3/p4 to p1/p2
1169-
for (PetrinetEdge<? extends PetrinetNode, ? extends PetrinetNode> edge : apn.getNet().getEdges()) {
1170-
if (edge.getSource() == t1 || edge.getTarget() == t1) {
1171-
continue;
1172-
}
1173-
if (edge.getSource() == p3) {
1174-
apn.getNet().addArc(p1, (Transition) edge.getTarget());
1175-
} else if (edge.getSource() == p4) {
1176-
apn.getNet().addArc(p2, (Transition) edge.getTarget());
1170+
for (List<Transition> cluster : clusters) {
1171+
System.out.println("[DiscoverPetriNetAlgorithm] Reducing " + cluster);
1172+
Transition t1 = cluster.get(0);
1173+
Place p1 = (Place) preset.get(t1).iterator().next();
1174+
Place p2 = (Place) postset.get(t1).iterator().next();
1175+
Transition t2 = cluster.get(3);
1176+
Place p3 = (Place) preset.get(t2).iterator().next();
1177+
Place p4 = (Place) postset.get(t2).iterator().next();
1178+
// Remove transitions (and edges connected to them)
1179+
apn.getNet().removeTransition(cluster.get(1));
1180+
apn.getNet().removeTransition(cluster.get(2));
1181+
apn.getNet().removeTransition(cluster.get(3));
1182+
// Reroute arcs from p3/p4 to p1/p2
1183+
for (PetrinetEdge<? extends PetrinetNode, ? extends PetrinetNode> edge : apn.getNet().getEdges()) {
1184+
if (edge.getSource() == t1 || edge.getTarget() == t1) {
1185+
continue;
1186+
}
1187+
if (edge.getSource() == p3) {
1188+
apn.getNet().addArc(p1, (Transition) edge.getTarget());
1189+
} else if (edge.getSource() == p4) {
1190+
apn.getNet().addArc(p2, (Transition) edge.getTarget());
1191+
}
1192+
if (edge.getTarget() == p3) {
1193+
apn.getNet().addArc((Transition) edge.getSource(), p1);
1194+
} else if (edge.getTarget() == p4) {
1195+
apn.getNet().addArc((Transition) edge.getSource(), p2);
1196+
}
11771197
}
1178-
if (edge.getTarget() == p3) {
1179-
apn.getNet().addArc((Transition) edge.getSource(), p1);
1180-
} else if (edge.getTarget() == p4) {
1181-
apn.getNet().addArc((Transition) edge.getSource(), p2);
1198+
// Remove places (and edges connected to them)
1199+
apn.getNet().removePlace(p3);
1200+
apn.getNet().removePlace(p4);
1201+
nofRoutingTransitions -= 3;
1202+
if (nofRoutingTransitions <= parameters.getMaxNofRoutingTransitions()) {
1203+
System.out.println("[DiscoverPetriNetAlgorithm] Reduced to " + nofRoutingTransitions + " routing transitions");
1204+
return;
11821205
}
11831206
}
1184-
// Remove places (and edges connected to them)
1185-
apn.getNet().removePlace(p3);
1186-
apn.getNet().removePlace(p4);
11871207
}
11881208
}
11891209
}

src/org/processmining/discover/parameters/DiscoverPetriNetParameters.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public class DiscoverPetriNetParameters implements ClassifierParameter {
9999
*/
100100
private int safetyThreshold2;
101101

102+
private int maxNofRoutingTransitions;
102103
/**
103104
* The percentage threshold for concurrent pairs
104105
* A concurrent pair is ignored it its score does not exceed this percentage of the maximal score.
@@ -149,6 +150,7 @@ public class DiscoverPetriNetParameters implements ClassifierParameter {
149150
private static int lastNofTraces = 250;
150151
private static int lastMaxTraceLength = 100;
151152
private static int lastNofThreads = 4;
153+
private static int lastMaxNofRoutingTransitions = -100;
152154

153155
/**
154156
* Creates default parameter settings.
@@ -185,6 +187,7 @@ public DiscoverPetriNetParameters() {
185187
setNofTraces(lastNofTraces);
186188
setMaxTraceLength(lastMaxTraceLength);
187189
setNofThreads(lastNofThreads);
190+
setMaxNofRoutingTransitions(lastMaxNofRoutingTransitions);
188191
}
189192

190193
/*
@@ -522,6 +525,15 @@ public void setNofThreads(int nofThreads) {
522525
this.nofThreads = nofThreads;
523526
}
524527

528+
public int getMaxNofRoutingTransitions() {
529+
return maxNofRoutingTransitions;
530+
}
531+
532+
public void setMaxNofRoutingTransitions(int maxNofRoutingTransitions) {
533+
lastMaxNofRoutingTransitions = maxNofRoutingTransitions;
534+
this.maxNofRoutingTransitions = maxNofRoutingTransitions;
535+
}
536+
525537
// public int getPercentage() {
526538
// return percentage;
527539
// }

src/org/processmining/discover/widgets/DiscoverPetriNetWidget.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class DiscoverPetriNetWidget extends JPanel {
3434
* @param parameters The given parameter settings
3535
*/
3636
public DiscoverPetriNetWidget(final DiscoverPetriNetParameters parameters) {
37-
double size[][] = { { 30, TableLayoutConstants.FILL }, { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, TableLayoutConstants.FILL } };
37+
double size[][] = { { 30, TableLayoutConstants.FILL }, { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, TableLayoutConstants.FILL } };
3838
setLayout(new TableLayout(size));
3939

4040

@@ -197,6 +197,32 @@ public void actionPerformed(ActionEvent e) {
197197
add(addBinaryPlacesBox, "0, 6, 1, 6");
198198

199199

200+
final NiceSlider nofRoutingTransitionsSlider = SlickerFactory.instance().createNiceIntegerSlider(
201+
"Target number of routing transitions", 1, 1000, Math.abs(parameters.getMaxNofRoutingTransitions()), Orientation.HORIZONTAL);
202+
nofRoutingTransitionsSlider.addChangeListener(new ChangeListener() {
203+
204+
public void stateChanged(ChangeEvent e) {
205+
int value = nofRoutingTransitionsSlider.getSlider().getValue();
206+
parameters.setMaxNofRoutingTransitions(value);
207+
}
208+
});
209+
nofRoutingTransitionsSlider.setPreferredSize(new Dimension(100, 30));
210+
nofRoutingTransitionsSlider.setVisible(parameters.getMaxNofRoutingTransitions() > 0);
211+
add(nofRoutingTransitionsSlider, "1, 11");
212+
213+
final JCheckBox nofRoutingTransitionsBox = SlickerFactory.instance().createCheckBox("Reduce routing transitions",
214+
parameters.getMaxNofRoutingTransitions() > 0);
215+
nofRoutingTransitionsBox.addActionListener(new ActionListener() {
216+
217+
public void actionPerformed(ActionEvent e) {
218+
nofRoutingTransitionsSlider.setVisible(nofRoutingTransitionsBox.isSelected());
219+
parameters.setMaxNofRoutingTransitions(-parameters.getMaxNofRoutingTransitions());
220+
}
221+
222+
});
223+
nofRoutingTransitionsBox.setOpaque(false);
224+
add(nofRoutingTransitionsBox, "0, 10, 1, 10");
225+
200226
// Check box for majority
201227
// final JCheckBox majorityBox = SlickerFactory.instance().createCheckBox("Use veto for noise",
202228
// parameters.isVetoNoise());

0 commit comments

Comments
 (0)