petri-net-simulation 0.4.0

A library for simulating petri nets
Documentation
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
}

/// Calculate how often a transaction could theoretically be fired.
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(),
        },
    )
}

/// Calculate how often a transaction could theoretically be unfired.
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(),
        },
    )
}