petri_net_simulation/
helpers.rs1use std::collections::HashSet;
2
3use pns::{Net, Node, Pid, Tid};
4
5struct CountSearchInfo {
6 pids: fn(&Node<Pid>) -> &[Pid],
7 tids: fn(&Node<Tid>) -> &[Tid],
8 used: HashSet<Tid>,
9}
10
11#[inline(always)]
12fn minimal_count(
13 net: &Net,
14 tid: Tid,
15 info: &mut CountSearchInfo,
16 alt: &mut CountSearchInfo,
17) -> Option<usize> {
18 info.used.insert(tid);
19 let mut current_minimal_count = None;
20 'outer: for &pid in (info.pids)(net.transition(tid)) {
21 let mut count = net.initial_token_count(pid);
22 for &tid in (info.tids)(net.place(pid)) {
23 if alt.used.contains(&tid) {
24 continue;
25 }
26 if info.used.contains(&tid) {
27 continue 'outer;
28 }
29 let Some(add) = minimal_count(net, tid, info, alt) else {
30 continue 'outer;
31 };
32 count += add;
33 }
34 for &tid in (alt.tids)(net.place(pid)) {
35 if info.used.contains(&tid) {
36 continue;
37 }
38 if alt.used.contains(&tid) {
39 continue 'outer;
40 }
41 let Some(add) = minimal_count(net, tid, alt, info) else {
42 continue 'outer;
43 };
44 count += add;
45 }
46 if let Some(minimal_count) = &mut current_minimal_count {
47 if count <= *minimal_count {
48 *minimal_count = count;
49 }
50 } else {
51 current_minimal_count = Some(count);
52 }
53 }
54
55 current_minimal_count
56}
57
58pub fn maximum_fire_count(net: &Net, tid: Tid) -> Option<usize> {
60 minimal_count(
61 net,
62 tid,
63 &mut CountSearchInfo {
64 pids: Node::prev,
65 tids: Node::prev,
66 used: HashSet::new(),
67 },
68 &mut CountSearchInfo {
69 pids: Node::next,
70 tids: Node::next,
71 used: HashSet::new(),
72 },
73 )
74}
75
76pub fn maximum_unfire_count(net: &Net, tid: Tid) -> Option<usize> {
78 minimal_count(
79 net,
80 tid,
81 &mut CountSearchInfo {
82 pids: Node::next,
83 tids: Node::next,
84 used: HashSet::new(),
85 },
86 &mut CountSearchInfo {
87 pids: Node::prev,
88 tids: Node::prev,
89 used: HashSet::new(),
90 },
91 )
92}