pm4js
Version:
Process Mining for Javascript
265 lines (238 loc) • 6.06 kB
JavaScript
class PetriNet {
constructor(name="EMPTY") {
this.name = name;
this.places = {};
this.transitions = {};
this.arcs = {};
this.associatedTime = 0;
}
addPlace(name) {
let place = new PetriNetPlace(name);
this.places[place] = place;
return place;
}
addTransition(name, label) {
let trans = new PetriNetTransition(name, label);
this.transitions[trans] = trans;
return trans;
}
addArcFromTo(source, target, weight=1) {
if (source.constructor.name == target.constructor.name) {
throw 'Petri nets are bipartite graphs';
}
let arc = new PetriNetArc(source, target, weight);
source.outArcs[arc] = arc;
target.inArcs[arc] = arc;
this.arcs[arc] = arc;
return arc;
}
removePlace(place) {
for (let arcId in place.inArcs) {
let arc = place.inArcs[arcId];
delete this.arcs[arcId];
delete arc.source.outArcs[arcId];
}
for (let arcId in place.outArcs) {
let arc = place.outArcs[arcId];
delete this.arcs[arcId];
delete arc.target.inArcs[arcId];
}
delete this.places[place];
}
removeTransition(transition) {
for (let arcId in transition.inArcs) {
let arc = transition.inArcs[arcId];
delete this.arcs[arcId];
delete arc.target.outArcs[arcId];
}
for (let arcId in transition.outArcs) {
let arc = transition.outArcs[arcId];
delete this.arcs[arcId];
delete arc.target.inArcs[arcId];
}
delete this.transitions[transition];
}
toString() {
return "petriNet@@"+this.name;
}
}
class PetriNetPlace {
constructor(name) {
this.name = name;
this.inArcs = {};
this.outArcs = {};
this.properties = {};
}
toString() {
return "place@@"+this.name;
}
}
class PetriNetTransition {
constructor(name, label) {
this.name = name;
this.label = label;
this.inArcs = {};
this.outArcs = {};
this.properties = {};
this.associatedTime = 0;
}
toString() {
return "transition@@"+this.name;
}
getPreMarking() {
let preMarking = {}
for (let arcKey in this.inArcs) {
let arc = this.inArcs[arcKey];
let sourcePlace = arc.source;
preMarking[sourcePlace] = arc.weight;
}
return preMarking;
}
getPostMarking() {
let postMarking = {};
for (let arcKey in this.outArcs) {
let arc = this.outArcs[arcKey];
let targetPlace = arc.target;
postMarking[targetPlace] = arc.weight;
}
return postMarking;
}
checkPreset(marking) {
let preMarking = this.getPreMarking();
for (let place in preMarking) {
if (!(place in marking.tokens) || (marking.tokens[place] < preMarking[place])) {
return false;
}
}
return true;
}
}
class PetriNetArc {
constructor(source, target, weight=1) {
this.source = source;
this.target = target;
this.weight = weight;
this.properties = {};
}
toString() {
return "arc@@"+this.source+"@@"+this.target;
}
}
class Marking {
constructor(net) {
this.net = net;
this.tokens = {};
}
toString() {
let ret = "marking@@";
let orderedKeys = Object.keys(this.tokens).sort();
for (let place of orderedKeys) {
ret += place + "=" + this.tokens[place] + ";"
}
return ret;
}
setTokens(place, tokens) {
this.tokens[place] = tokens;
}
getEnabledTransitions() {
let ret = [];
for (let transKey in this.net.transitions) {
let trans = this.net.transitions[transKey];
if (trans.checkPreset(this)) {
ret.push(trans);
}
}
return ret;
}
execute(transition, associatedTime=null) {
let newMarking = new Marking(this.net);
for (let place in this.tokens) {
newMarking.setTokens(place, this.tokens[place]);
}
let preMarking = transition.getPreMarking();
let postMarking = transition.getPostMarking();
let transObj = this.net.transitions[transition];
if (associatedTime != null) {
transObj.associatedTime = associatedTime;
}
for (let place in preMarking) {
newMarking.tokens[place] -= preMarking[place];
}
for (let place in postMarking) {
if (!(place in newMarking)) {
newMarking.tokens[place] = postMarking[place];
}
else {
newMarking.tokens[place] += postMarking[place];
}
if (associatedTime != null) {
let placeObj = this.net.places[place];
placeObj.associatedTime = associatedTime;
}
}
for (let place in newMarking.tokens) {
if (newMarking.tokens[place] == 0) {
delete newMarking.tokens[place];
}
}
return newMarking;
}
copy() {
let newMarking = new Marking(this.net);
for (let place in this.tokens) {
newMarking.setTokens(place, this.tokens[place]);
}
return newMarking;
}
equals(other) {
let thisTokens = this.tokens;
let otherTokens = other.tokens;
for (let place in thisTokens) {
if (!(place in otherTokens)) {
return false;
}
else if (otherTokens[place] != thisTokens[place]) {
return false;
}
}
for (let place in otherTokens) {
if (!(place in thisTokens)) {
return false;
}
}
return true;
}
setAssociatedTimest(timest) {
for (let placeId in this.tokens) {
let place = this.net.places[placeId];
place.associatedTime = timest;
}
}
getAssociatedTimest() {
let maxTime = 0;
for (let placeId in this.tokens) {
let place = this.net.places[placeId];
maxTime = Math.max(place.associatedTime, maxTime);
}
return maxTime;
}
}
class AcceptingPetriNet {
constructor(net, im, fm) {
this.net = net;
this.im = im;
this.fm = fm;
}
}
try {
module.exports = {PetriNet: PetriNet, PetriNetPlace: PetriNetPlace, PetriNetTransition: PetriNetTransition, PetriNetArc: PetriNetArc, Marking: Marking, AcceptingPetriNet: AcceptingPetriNet};
global.PetriNet = PetriNet;
global.PetriNetPlace = PetriNetPlace;
global.PetriNetTransition = PetriNetTransition;
global.PetriNetArc = PetriNetArc;
global.Marking = Marking;
global.AcceptingPetriNet = AcceptingPetriNet;
}
catch (err) {
// not in node
}