f8882f247685d2347a25020d72147370a7895520
[petrinet.git] / src / main / java / de / yasc / example / petrinet / Petrinet.java
1 package de.yasc.example.petrinet;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collections;
6 import java.util.List;
7 import java.util.Random;
8 import java.util.stream.Collectors;
9
10 public final class Petrinet {
11
12     private static final class Place {
13
14         int tokens;
15
16         boolean empty() {
17             return tokens <= 0;
18         }
19
20         void dec() {
21             assert tokens > 0;
22             tokens--;
23         }
24
25         void inc() {
26             tokens++;
27         }
28     }
29
30     private static final class Transition {
31
32         final List<Place> preset;
33         final List<Place> postset;
34
35         public Transition(List<Place> preset, List<Place> postset) {
36             this.preset = preset;
37             this.postset = postset;
38         }
39
40         boolean enabled() {
41             return preset.stream().noneMatch(Place::empty);
42         }
43
44         void fire() {
45             preset.forEach(Place::dec);
46             postset.forEach(Place::inc);
47         }
48     }
49
50     final private Random prng = new Random();
51     final private Place[] places;
52     final private List<Transition> transitions;
53
54     public Petrinet(int places) {
55         this.places = new Place[places];
56         for (int i = 0 ; i < places ; i++)
57             this.places[i] = new Place();
58         transitions = new ArrayList<>();
59     }
60
61     public void addTransistion(Integer[] preset, Integer[] postset) {
62         transitions.add(new Transition(
63                 Arrays.stream(preset).map((i) -> places[i]).collect(Collectors.toList()),
64                 Arrays.stream(postset).map((i) -> places[i]).collect(Collectors.toList())
65         ));
66     }
67     
68     public void addMarking(Integer ... marking) {
69         Arrays.stream(marking).forEach((i) -> places[i].inc());
70     }
71     
72     public boolean step() {
73         var enabledTransitions = transitions.stream().filter(Transition::enabled).collect(Collectors.toList());
74         if (enabledTransitions.isEmpty()) {
75             return false;
76         } else {
77             transitions.get(prng.nextInt(enabledTransitions.size())).fire();
78             return true;
79         }
80     }
81     
82     public int step(int k) {
83         int i = 0;
84         while (i < k) {
85             if (!step())
86                 return i;
87             ++i;
88         }
89         return i;
90     }
91     
92     public Integer[] getMarking() {
93         final var marking = new ArrayList<Integer>();
94         for (int p = 0 ; p < places.length ; p++) {
95             Collections.nCopies(places[p].tokens, p).forEach(marking::add);
96         }
97         return marking.toArray(new Integer[0]);
98     }
99 }