Skip to content
Snippets Groups Projects
Commit 03e2baa9 authored by Andrea Burattin's avatar Andrea Burattin
Browse files

First non-snapshot version of the framework

parent 81ced921
Branches gh-pages
No related tags found
No related merge requests found
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>beamline</groupId> <groupId>beamline</groupId>
<artifactId>framework</artifactId> <artifactId>framework</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1</version>
<properties> <properties>
<maven.compiler.source>11</maven.compiler.source> <maven.compiler.source>11</maven.compiler.source>
...@@ -49,29 +49,15 @@ ...@@ -49,29 +49,15 @@
<artifactId>org.eclipse.paho.client.mqttv3</artifactId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.0</version> <version>1.2.0</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.beamline</groupId>
<artifactId>graphviz</artifactId>
<version>0.0.2</version>
</dependency>
<dependency> <dependency>
<groupId>io.reactivex.rxjava3</groupId> <groupId>io.reactivex.rxjava3</groupId>
<artifactId>rxjava</artifactId> <artifactId>rxjava</artifactId>
<version>3.1.3</version> <version>3.1.3</version>
</dependency> </dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.5</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>com.github.beamline</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>graphviz</artifactId>
<version>3.10</version> <version>0.0.2</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
package beamline.miners;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.deckfour.xes.extension.std.XConceptExtension;
import org.deckfour.xes.model.XTrace;
import beamline.models.algorithms.StreamMiningAlgorithm;
public class DiscoveryMiner extends StreamMiningAlgorithm<XTrace, ProcessMap> {
private Map<String, String> latestActivityInCase = new HashMap<String, String>();
private Map<Pair<String, String>, Double> relations = new HashMap<Pair<String, String>, Double>();
private Map<String, Double> activities = new HashMap<String, Double>();
private Double maxActivityFreq = Double.MIN_VALUE;
private Double maxRelationsFreq = Double.MIN_VALUE;
private double minDependency = 1d;
private int modelRefreshRate = 0;
public DiscoveryMiner() {
}
public void setMinDependency(double minDependency) {
this.minDependency = minDependency;
}
public void setModelRefreshRate(int modelRefreshRate) {
this.modelRefreshRate = modelRefreshRate;
}
@Override
public ProcessMap ingest(XTrace event) {
String caseID = XConceptExtension.instance().extractName(event);
String activityName = XConceptExtension.instance().extractName(event.get(0));
Double activityFreq = 1d;
if (activities.containsKey(activityName)) {
activityFreq += activities.get(activityName);
maxActivityFreq = Math.max(maxActivityFreq, activityFreq);
}
activities.put(activityName, activityFreq);
if (latestActivityInCase.containsKey(caseID)) {
Pair<String, String> relation = new ImmutablePair<String, String>(latestActivityInCase.get(caseID), activityName);
Double relationFreq = 1d;
if (relations.containsKey(relation)) {
relationFreq += relations.get(relation);
maxRelationsFreq = Math.max(maxRelationsFreq, relationFreq);
}
relations.put(relation, relationFreq);
}
latestActivityInCase.put(caseID, activityName);
if (getProcessedEvents() % modelRefreshRate == 0) {
setLatestResponse(mine(minDependency));
}
return getLatestResponse();
}
public ProcessMap mine(double threshold) {
ProcessMap process = new ProcessMap();
for (String activity : activities.keySet()) {
process.addActivity(activity, activities.get(activity) / maxActivityFreq);
}
for (Pair<String, String> relation : relations.keySet()) {
double dependency = relations.get(relation) / maxRelationsFreq;
if (dependency >= threshold) {
process.addRelation(relation.getLeft(), relation.getRight(), dependency);
}
}
Set<String> toRemove = new HashSet<String>();
Set<String> selfLoopsToRemove = new HashSet<String>();
for (String activity : activities.keySet()) {
if (process.isStartActivity(activity) && process.isEndActivity(activity)) {
toRemove.add(activity);
}
if (process.isIsolatedNode(activity)) {
selfLoopsToRemove.add(activity);
}
}
for (String activity : toRemove) {
process.removeActivity(activity);
}
return process;
}
}
package beamline.miners;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import beamline.graphviz.Dot;
import beamline.models.responses.GraphvizResponse;
import beamline.view.graph.PMDotModel;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ProcessMap implements GraphvizResponse {
private Map<String, Double> activities;
private Map<Pair<String, String>, Double> relations;
@Override
public Dot generateDot() {
return new PMDotModel(this, beamline.view.graph.ColorPalette.Colors.BLUE);
}
public ProcessMap() {
this.activities = new HashMap<String, Double>();
this.relations = new HashMap<Pair<String, String>, Double>();
}
public void addActivity(String activityName, Double value) {
this.activities.put(activityName, value);
}
public void removeActivity(String activityName) {
this.activities.remove(activityName);
}
public void addRelation(String activitySource, String activityTarget, Double value) {
relations.put(new ImmutablePair<String, String>(activitySource, activityTarget), value);
}
public void removeRelation(String activitySource, String activityTarget) {
relations.remove(new ImmutablePair<String, String>(activitySource, activityTarget));
}
public Set<String> getActivities() {
return activities.keySet();
}
public Set<Pair<String, String>> getRelations() {
return relations.keySet();
}
public Double getActivityValue(String activity) {
return this.activities.get(activity);
}
public Double getRelationValue(Pair<String, String> relation) {
return this.relations.get(relation);
}
public Set<String> getIncomingActivities(String candidate) {
Set<String> result = new HashSet<String>();
for (Pair<String, String> relation : getRelations()) {
if (relation.getRight().equals(candidate)) {
result.add(relation.getLeft());
}
}
return result;
}
public Set<String> getOutgoingActivities(String candidate) {
Set<String> result = new HashSet<String>();
for (Pair<String, String> relation : getRelations()) {
if (relation.getLeft().equals(candidate)) {
result.add(relation.getRight());
}
}
return result;
}
public boolean isStartActivity(String candidate) {
return getIncomingActivities(candidate).size() == 0;
}
public boolean isEndActivity(String candidate) {
return getOutgoingActivities(candidate).size() == 0;
}
public boolean isIsolatedNode(String candidate) {
return getOutgoingActivities(candidate).equals(getIncomingActivities(candidate));
}
}
\ No newline at end of file
package beamline.tester;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.deckfour.xes.extension.std.XConceptExtension;
import org.deckfour.xes.extension.std.XTimeExtension;
import org.deckfour.xes.in.XParser;
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 beamline.filters.ExcludeActivitiesFilter;
import beamline.filters.RetainActivitiesFilter;
import beamline.miners.DiscoveryMiner;
import beamline.miners.ProcessMap;
import beamline.models.algorithms.HookEventProcessing;
import beamline.models.algorithms.StreamMiningAlgorithm;
import beamline.sources.XesLogSource;
import beamline.sources.XesSource;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.functions.Predicate;
import jdk.jshell.execution.StreamingExecutionControl;
public class Tester {
public static void main(String[] args) throws Exception {
System.out.println("start");
XParser p = new XesXmlParser();
XLog l = p.parse(new File("C:\\Users\\andbur\\Desktop\\input.xes")).get(0);
XesSource source = new XesLogSource(l);
// XesSource source = new MQTTXESSource(broker, topic, process);
source.prepare();
DiscoveryMiner miner = new DiscoveryMiner();
miner.setMinDependency(0.3);
miner.setModelRefreshRate(1);
Observable<XTrace> obs = source.getObservable();
obs
// .filter(new RetainActivitiesFilter("A", "B", "C", "dummy-retain"))
// .filter(new ExcludeActivitiesFilter("A", "dummy-exclude"))
// .map(new DirectSuccessionMapper())
// .combine(new SlidingWindow(1000))
// .map(new Miner(1, 0.5))
.subscribe(miner);
// .subscribe(new Consumer<XTrace>() {
// @Override
// public void accept(@NonNull XTrace t) throws Throwable {
// System.out.println(
// XConceptExtension.instance().extractName(t) + " - " +
// XConceptExtension.instance().extractName(t.get(0)) + " - " +
// XTimeExtension.instance().extractTimestamp(t.get(0))
// );
// }
// });
miner.getLatestResponse().generateDot().exportToSvg(new File("C:\\Users\\andbur\\Desktop\\output.svg"));
System.out.println("done");
}
}
package beamline.view.graph;
import java.awt.Color;
// see https://content.linkedin.com/content/dam/brand/site/img/color/color-palette-order.png
public class ColorPalette {
public enum Colors {
BLUE ("#CFEDFB", "#0B4971"),
VIOLET("#F0E3EF", "#593482"),
RED ("#FFE2D2", "#98041B"),
ORANGE("#FFEBB6", "#933304"),
AQUA ("#D2ECEB", "#0E5C68"),
YELLOW("#FAF0B5", "#856A1D"),
PINK ("#FBE2ED", "#951343"),
GREEN ("#E5EFC7", "#3F652D"),
GRAY ("#E0E2E4", "#3A3C3E"),
DARK_GRAY("#86888A", "#252526");
public Color min;
public Color max;
Colors(String min, String max) {
this.min = Color.decode(min);
this.max = Color.decode(max);
}
}
public static Color getValue(Colors base, double value) {
float rMin = base.min.getRed() / 255f;
float gMin = base.min.getGreen() / 255f;
float bMin = base.min.getBlue() / 255f;
float rMax = base.max.getRed() / 255f;
float gMax = base.max.getGreen() / 255f;
float bMax = base.max.getBlue() / 255f;
float rOwn = (float) (rMin + (rMax - rMin) * value);
float gOwn = (float) (gMin + (gMax - gMin) * value);
float bOwn = (float) (bMin + (bMax - bMin) * value);
rOwn = (rOwn > 1f)? 1 : (rOwn < 0? 0 : rOwn);
gOwn = (gOwn > 1f)? 1 : (gOwn < 0? 0 : gOwn);
bOwn = (bOwn > 1f)? 1 : (bOwn < 0? 0 : bOwn);
return new Color(rOwn, gOwn, bOwn);
}
public static Color getFontColor(Color background) {
double a = 1
- (0.299 * background.getRed() + 0.587 * background.getGreen() + 0.114 * background.getBlue()) / 255;
return a < 0.5 ? Color.BLACK : Color.WHITE;
}
public static String colorToString(Color color) {
return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());
}
}
\ No newline at end of file
package beamline.view.graph;
import beamline.graphviz.DotEdge;
import beamline.graphviz.DotNode;
public class PMDotEdge extends DotEdge {
public PMDotEdge(DotNode source, DotNode target, String edgeText, Double weight) {
super(source, target);
setOption("decorate", "false");
setOption("fontsize", "8");
setOption("arrowsize", "0.5");
setOption("fontname", "Arial");
setOption("tailclip", "false");
if (edgeText != null) {
setLabel(" " + edgeText);
}
if (weight != null) {
setOption("color",
ColorPalette.colorToString(ColorPalette.getValue(ColorPalette.Colors.DARK_GRAY, weight)));
if ((source instanceof PMDotStartNode) || (target instanceof PMDotEndNode)) {
setOption("penwidth", "" + (1 + (5 * weight)));
} else {
setOption("penwidth", "" + (1 + (8 * weight)));
}
} else {
if ((source instanceof PMDotStartNode) || (target instanceof PMDotEndNode)) {
setOption("penwidth", "2");
} else {
setOption("penwidth", "3");
}
}
if (source instanceof PMDotStartNode) {
setOption("style", "dashed");
setOption("color", "#ACB89C");
}
if (target instanceof PMDotEndNode) {
setOption("style", "dashed");
setOption("color", "#C2B0AB");
}
}
}
\ No newline at end of file
package beamline.view.graph;
import beamline.graphviz.DotNode;
public class PMDotEndNode extends DotNode {
public PMDotEndNode() {
super("", null);
setOption("shape", "circle");
setOption("style", "filled");
setOption("fillcolor", "#D8BBB9"); // #D8BBB9:#BC9F9D
setOption("gradientangle", "270");
setOption("color", "#614847");
setOption("height", "0.13");
setOption("width", "0.13");
}
@Override
public String toString() {
return "{ rank = \"sink\"; " + super.toString() + "}";
}
}
\ No newline at end of file
package beamline.view.graph;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import beamline.graphviz.Dot;
import beamline.graphviz.DotNode;
import beamline.miners.ProcessMap;
/**
*
* @author Andrea Burattin
*/
public class PMDotModel extends Dot {
private ProcessMap model;
private ColorPalette.Colors activityColor;
public PMDotModel(ProcessMap model, ColorPalette.Colors activityColor) {
this.model = model;
this.activityColor = activityColor;
realize();
}
private void realize() {
// setOption("rankdir", "LR");
setOption("ranksep", ".1");
setOption("fontsize", "9");
setOption("remincross", "true");
setOption("margin", "0.0,0.0");
setOption("outputorder", "edgesfirst");
Map<String, DotNode> activityToNode = new HashMap<String, DotNode>();
Map<String, String> nodeToActivity = new HashMap<String, String>();
Set<DotNode> startNodes = new HashSet<DotNode>();
Set<DotNode> endNodes = new HashSet<DotNode>();
// add all activities
for(String activity : model.getActivities()) {
DotNode node = addNodeIfNeeded(activity, activityToNode, nodeToActivity);
if (node instanceof PMDotNode) {
((PMDotNode) node).setColorWeight(model.getActivityValue(activity), activityColor);
}
if (model.isStartActivity(activity)) {
startNodes.add(node);
}
if (model.isEndActivity(activity)) {
endNodes.add(node);
}
}
// add all relations
for (Pair<String, String> relation : model.getRelations()) {
String sourceActivity = relation.getLeft();
String targetActivity = relation.getRight();
// adding source nodes
DotNode sourceNode = addNodeIfNeeded(sourceActivity, activityToNode, nodeToActivity);
// adding target nodes
DotNode targetNode = addNodeIfNeeded(targetActivity, activityToNode, nodeToActivity);
// adding relations
addRelation(sourceNode, targetNode, model.getRelationValue(relation));
}
// add relations from start and end
if (startNodes.size() > 0) {
PMDotStartNode start = new PMDotStartNode();
addNode(start);
for (DotNode n : startNodes) {
addRelation(start, n, null);
}
}
if (endNodes.size() > 0) {
PMDotEndNode end = new PMDotEndNode();
addNode(end);
for (DotNode n : endNodes) {
addRelation(n, end, null);
}
}
}
private void addRelation(DotNode sourceNode, DotNode targetNode, Double value) {
addEdge(new PMDotEdge(sourceNode, targetNode, (value == null? null : String.format("%.2g%n", value)), value));
}
private DotNode addNodeIfNeeded(String activity, Map<String, DotNode> activityToNode, Map<String, String> nodeToActivity) {
DotNode existingNode = activityToNode.get(activity);
if (existingNode == null) {
// if (model.isStartActivity(activity)) {
// PMCEPDotStartNode startNode = new PMCEPDotStartNode();
// addNode(startNode);
// activityToNode.put(activity, startNode);
// nodeToActivity.put(startNode.getId(), activity);
// return startNode;
// } else if (model.isEndActivity(activity)) {
// PMCEPDotEndNode endNode = new PMCEPDotEndNode();
// addNode(endNode);
// activityToNode.put(activity, endNode);
// nodeToActivity.put(endNode.getId(), activity);
// return endNode;
// } else {
PMDotNode newNode = new PMDotNode(activity.toString());
newNode.setColorWeight(model.getActivityValue(activity), activityColor);
newNode.setSecondLine(String.format("%.2g%n", model.getActivityValue(activity)));
addNode(newNode);
activityToNode.put(activity, newNode);
nodeToActivity.put(newNode.getId(), activity);
return newNode;
// }
} else {
return existingNode;
}
}
}
\ No newline at end of file
package beamline.view.graph;
import java.awt.Color;
import beamline.graphviz.DotNode;
public class PMDotNode extends DotNode {
private String label;
public PMDotNode(String label) {
this(label, null, null, null);
}
public PMDotNode(String label, String secondLine, Double weight, ColorPalette.Colors activityColor) {
super(label, null);
this.label = label;
setOption("shape", "box");
setOption("fixedsize", "true");
setOption("height", "0.23");
setOption("width", "1.2");
setOption("style", "rounded,filled");
setOption("fontname", "Arial");
setSecondLine(secondLine);
setColorWeight(weight, activityColor);
}
public void setSecondLine(String secondLine) {
if (secondLine != null) {
setLabel("<<font point-size='22'>" + label + "</font> <br/><font point-size='16'>" + secondLine
+ "</font>>");
}
}
public void setColorWeight(Double weight, ColorPalette.Colors activityColor) {
if (weight == null) {
setOption("fillcolor", "#FDEFD8"); // #FDEFD8:#E1D3BC
} else {
Color backgroundColor = ColorPalette.getValue(activityColor, weight);
Color fontColor = ColorPalette.getFontColor(backgroundColor);
setOption("fillcolor", ColorPalette
.colorToString(backgroundColor)/* + ":" + ColorPalette.colorToString(backgroundColor.darker()) */);
setOption("fontcolor", ColorPalette.colorToString(fontColor));
setOption("fixedsize", "false");
}
}
public void setMovedIn() {
setOption("fillcolor", "white");
}
public void setMovedOut() {
setOption("fillcolor", "black");
}
@Override
public int hashCode() {
return getLabel().hashCode();
}
@Override
public boolean equals(Object object) {
return getLabel().equals(object);
}
}
\ No newline at end of file
package beamline.view.graph;
import beamline.graphviz.DotNode;
public class PMDotStartNode extends DotNode {
public PMDotStartNode() {
super("", null);
setOption("shape", "circle");
setOption("style", "filled");
setOption("fillcolor", "#CED6BD"); // #CED6BD:#B3BBA2
setOption("gradientangle", "270");
setOption("color", "#595F45");
setOption("height", "0.13");
setOption("width", "0.13");
}
@Override
public String toString() {
return "{ rank = \"source\"; " + super.toString() + " }";
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment