hu.bme.mit.theta.frontend.petrinet.analysis.PtNetSystem Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of theta-petrinet-analysis Show documentation
Show all versions of theta-petrinet-analysis Show documentation
Petrinet Analysis subproject in the Theta model checking framework
The newest version!
/*
* Copyright 2024 Budapest University of Technology and Economics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package hu.bme.mit.theta.frontend.petrinet.analysis;
import com.google.common.collect.ImmutableBiMap;
import com.koloboke.collect.map.ObjIntMap;
import com.koloboke.collect.map.hash.HashObjIntMaps;
import com.koloboke.collect.map.hash.HashObjObjMap;
import com.koloboke.collect.map.hash.HashObjObjMaps;
import hu.bme.mit.delta.collections.UniqueTable;
import hu.bme.mit.delta.collections.impl.MapUniqueTable;
import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor;
import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl.OrNextStateDescriptor;
import hu.bme.mit.theta.frontend.petrinet.model.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public final class PtNetSystem {
public static class TransitionEffect {
public static final TransitionEffect INDEPENDENT = new TransitionEffect(0, Integer.MAX_VALUE, 0);
public final int takes;
public final int inhibits;
public final int puts;
public TransitionEffect(final int takes, final int inhibits, final int puts) {
this.takes = takes;
this.inhibits = inhibits;
this.puts = puts;
}
public boolean isDependent() {
return takes != 0 || puts != 0 || inhibits != Integer.MAX_VALUE;
}
public boolean reads() {
return inhibits != Integer.MAX_VALUE || (takes == puts && takes > 0);
}
public boolean writes() {
return takes != puts;
}
public String toString() {
if (writes()) {
return "rw";
} else if (reads()) {
return "r";
} else {
return "";
}
}
}
private PetriNet petriNet;
private final List placeOrdering;
private Map> dependencyMatrix = HashObjObjMaps.newUpdatableMap();
private ObjIntMap transitionTop = HashObjIntMaps.newUpdatableMap();
boolean hasReadOnlyEffect = false;
boolean hasReadOnlyEffectOnTop = false;
private AbstractNextStateDescriptor.Postcondition initializer;
private AbstractNextStateDescriptor transitions;
public PtNetSystem(final PetriNet petriNet, List placeOrdering) {
if (petriNet.getPlaces().size() != placeOrdering.size()) {
throw new IllegalArgumentException();
}
if (placeOrdering.isEmpty()) {
throw new IllegalArgumentException();
}
this.petriNet = petriNet;
this.placeOrdering = placeOrdering;
initializer = createInitializer();
transitions = createTransitions();
for (Place p : petriNet.getPlaces()) {
if (!placeOrdering.contains(p)) {
throw new IllegalArgumentException("Ordering does not contain place " + p.getId());
}
}
}
private AbstractNextStateDescriptor.Postcondition createInitializer() {
PtNetInitializer current = new PtNetInitializer(placeOrdering.get(0),
Math.toIntExact(placeOrdering.get(0).getInitialMarking()),
AbstractNextStateDescriptor.terminalIdentity()
);
for (int i = 1; i < placeOrdering.size(); ++i) {
current = new PtNetInitializer(placeOrdering.get(i),
Math.toIntExact(placeOrdering.get(i).getInitialMarking()),
current
);
}
return current;
}
private AbstractNextStateDescriptor createTransitions() {
List descriptors = new ArrayList<>();
UniqueTable uniqueTable = new MapUniqueTable<>();
for (Transition t : petriNet.getTransitions()) {
descriptors.add(createTransition(t, uniqueTable));
}
return OrNextStateDescriptor.create(descriptors);
}
private AbstractNextStateDescriptor createTransition(
final Transition t, final UniqueTable uniqueTable
) {
ObjIntMap takes = HashObjIntMaps.newUpdatableMap(t.getIncomingArcs().size());
ObjIntMap puts = HashObjIntMaps.newUpdatableMap(t.getOutgoingArcs().size());
ObjIntMap inhibits = HashObjIntMaps.newUpdatableMap();
for (PTArc arc : t.getIncomingArcs()) {
if (arc.isInhibitor()) {
inhibits.put(arc.getSource(), Math.toIntExact(arc.getWeight()));
} else {
takes.put(arc.getSource(), Math.toIntExact(arc.getWeight()));
}
}
for (TPArc arc : t.getOutgoingArcs()) {
puts.put(arc.getTarget(), Math.toIntExact(arc.getWeight()));
}
final HashObjObjMap transitionDependecies = HashObjObjMaps.newUpdatableMap();
boolean readOnlyOnTop = false;
AbstractNextStateDescriptor current = AbstractNextStateDescriptor.terminalIdentity();
for (int i = 0; i < placeOrdering.size(); ++i) {
final int nTakes = takes.getOrDefault(placeOrdering.get(i), 0);
final int nInhibits = inhibits.getOrDefault(placeOrdering.get(i), Integer.MAX_VALUE);
final int nPuts = puts.getOrDefault(placeOrdering.get(i), 0);
if (nTakes != 0 || nPuts != 0 || nInhibits != Integer.MAX_VALUE) {
final TransitionEffect effect = new TransitionEffect(nTakes, nInhibits, nPuts);
transitionDependecies.put(placeOrdering.get(i), effect);
transitionTop.put(t, i);
if (effect.reads() && !effect.writes()) {
hasReadOnlyEffect = true;
readOnlyOnTop = true;
} else {
readOnlyOnTop = false;
}
current = uniqueTable.checkIn(new PtNetTransitionNextStateDescriptor(t,
placeOrdering.get(i),
nTakes,
nInhibits,
nPuts,
current
));
}
}
hasReadOnlyEffectOnTop = hasReadOnlyEffectOnTop || readOnlyOnTop;
dependencyMatrix.put(t, transitionDependecies);
return current;
}
public AbstractNextStateDescriptor.Postcondition getInitializer() {
return initializer;
}
public AbstractNextStateDescriptor getTransitions() {
return transitions;
}
public String printDependencyMatrixCsv() {
StringBuilder sb = new StringBuilder();
for (Place p : placeOrdering) {
sb.append(';');
sb.append('"');
sb.append(p.getId());
sb.append('"');
}
sb.append('\n');
List transitionLines = new ArrayList<>(getTransitionCount());
for (Transition t : petriNet.getTransitions()) {
StringBuilder sb2 = new StringBuilder();
sb2.append('"');
sb2.append(t.getId());
sb2.append('"');
for (Place p : placeOrdering) {
sb2.append(';');
sb2.append(dependencyMatrix.getOrDefault(t, Map.of())
.getOrDefault(p, TransitionEffect.INDEPENDENT)
.toString());
}
sb2.append('\n');
transitionLines.add(sb2.toString());
}
transitionLines.sort((a, b) -> String.CASE_INSENSITIVE_ORDER.compare(reverseString(a), reverseString(b)));
for (String line : transitionLines) {
sb.append(line);
}
return sb.toString();
}
public static String reverseString(String str) {
StringBuilder sb = new StringBuilder(str);
sb.reverse();
return sb.toString();
}
public BufferedImage dependencyMatrixImage(final int blockWidth) {
int width = placeOrdering.size() * blockWidth, height = petriNet.getTransitions().size() * blockWidth;
// TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
// into integer pixels
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bi.createGraphics();
final List transitions = new ArrayList<>(petriNet.getTransitions());
transitions.sort(Comparator.comparingInt(t -> transitionTop.getOrDefault(t, -1)));
for (int y = 0; y < transitions.size(); y++) {
final Transition t = transitions.get(y);
for (int x = 0; x < placeOrdering.size(); x++) {
final Place p = placeOrdering.get(x);
final TransitionEffect effect = dependencyMatrix.getOrDefault(t, Map.of()).getOrDefault(p,
TransitionEffect.INDEPENDENT
);
if (effect.writes()) {
graphics.setPaint(Color.RED);
} else if (effect.reads()) {
graphics.setPaint(Color.GREEN);
} else {
graphics.setPaint(Color.WHITE);
}
graphics.fillRect(x * blockWidth, y * blockWidth, blockWidth, blockWidth);
// graphics.setPaint(Color.LIGHT_GRAY);
// graphics.drawRect(x*blockWidth, y*blockWidth, blockWidth + 1, blockWidth + 1);
}
}
return bi;
}
public String getName() {
return petriNet.getName() == null ? petriNet.getId() : petriNet.getName();
}
public boolean hasReadOnlyEffect() {
return hasReadOnlyEffect;
}
public boolean hasReadOnlyEffectOnTop() {
return hasReadOnlyEffectOnTop;
}
public int getPlaceCount() {
return petriNet.getPlaces().size();
}
public int getTransitionCount() {
return petriNet.getTransitions().size();
}
public int getArcCount() {
return petriNet.getPtArcs().size() + petriNet.getTpArcs().size();
}
public Map> getDependencyMatrix() {
return ImmutableBiMap.copyOf(dependencyMatrix);
}
public PetriNet getPetriNet() {
return petriNet;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy