use std::collections::HashSet;
use pns::{Net, Node, Pid, Tid};
struct CountSearchInfo {
pids: fn(&Node<Pid>) -> &[Pid],
tids: fn(&Node<Tid>) -> &[Tid],
used: HashSet<Tid>,
}
#[inline(always)]
fn minimal_count(
net: &Net,
tid: Tid,
info: &mut CountSearchInfo,
alt: &mut CountSearchInfo,
) -> Option<usize> {
info.used.insert(tid);
let mut current_minimal_count = None;
'outer: for &pid in (info.pids)(net.transition(tid)) {
let mut count = net.initial_token_count(pid);
for &tid in (info.tids)(net.place(pid)) {
if alt.used.contains(&tid) {
continue;
}
if info.used.contains(&tid) {
continue 'outer;
}
let Some(add) = minimal_count(net, tid, info, alt) else {
continue 'outer;
};
count += add;
}
for &tid in (alt.tids)(net.place(pid)) {
if info.used.contains(&tid) {
continue;
}
if alt.used.contains(&tid) {
continue 'outer;
}
let Some(add) = minimal_count(net, tid, alt, info) else {
continue 'outer;
};
count += add;
}
if let Some(minimal_count) = &mut current_minimal_count {
if count <= *minimal_count {
*minimal_count = count;
}
} else {
current_minimal_count = Some(count);
}
}
current_minimal_count
}
pub fn maximum_fire_count(net: &Net, tid: Tid) -> Option<usize> {
minimal_count(
net,
tid,
&mut CountSearchInfo {
pids: Node::prev,
tids: Node::prev,
used: HashSet::new(),
},
&mut CountSearchInfo {
pids: Node::next,
tids: Node::next,
used: HashSet::new(),
},
)
}
pub fn maximum_unfire_count(net: &Net, tid: Tid) -> Option<usize> {
minimal_count(
net,
tid,
&mut CountSearchInfo {
pids: Node::next,
tids: Node::next,
used: HashSet::new(),
},
&mut CountSearchInfo {
pids: Node::prev,
tids: Node::prev,
used: HashSet::new(),
},
)
}