Skip to main content

netcrab/
net_creator.rs

1//! Module with simple functions to create nets
2//!
3//! This could be extended to a struct with a custom format
4//! for the place labels and transition labels
5
6use crate::petri_net::{PetriNet, PlaceRef, TransitionRef};
7
8macro_rules! place_label_from_index {
9    ($index:expr) => {
10        format!("P{}", $index)
11    };
12}
13
14macro_rules! transition_label_from_index {
15    ($index:expr) => {
16        format!("T{}", $index)
17    };
18}
19
20/// Creates a new Petri net with no arcs and `number_of_places` places and `number_of_transitions` transitions.
21///
22/// Returns the net, a vector with all place references and a vector with all transition references.
23#[must_use]
24pub fn create_basic_unconnected_net(
25    number_of_places: usize,
26    number_of_transitions: usize,
27) -> (PetriNet, Vec<PlaceRef>, Vec<TransitionRef>) {
28    let mut net = PetriNet::new();
29    let mut place_refs: Vec<PlaceRef> = Vec::new();
30    let mut transition_refs: Vec<TransitionRef> = Vec::new();
31
32    for i in 1..=number_of_places {
33        let place_ref = net.add_place(&place_label_from_index!(i));
34        place_refs.push(place_ref);
35    }
36    for i in 1..=number_of_transitions {
37        let transition_ref = net.add_transition(&transition_label_from_index!(i));
38        transition_refs.push(transition_ref);
39    }
40
41    (net, place_refs, transition_refs)
42}
43
44/// Creates a new Petri net where the places and the transition form a simple chain.
45///
46/// The net contains `length` places and `length - 1` transitions.
47/// Returns the net, a vector with all place references and a vector with all transition references.
48///
49/// # Panics
50///
51/// Panics if arcs cannot be added.
52#[must_use]
53pub fn create_net_chain_topology(length: usize) -> (PetriNet, Vec<PlaceRef>, Vec<TransitionRef>) {
54    if length == 0 {
55        return (PetriNet::new(), Vec::new(), Vec::new());
56    }
57    let (mut net, place_refs, transition_refs) = create_basic_unconnected_net(length, length - 1);
58
59    for i in 0..length - 1 {
60        let place_ref = &place_refs[i];
61        let transition_ref = &transition_refs[i];
62        net.add_arc_place_transition(place_ref, transition_ref)
63            .expect("Failed while creating a net with chain topology");
64    }
65
66    for i in 0..length - 1 {
67        let transition_ref = &transition_refs[i];
68        let place_ref = &place_refs[i + 1];
69        net.add_arc_transition_place(transition_ref, place_ref)
70            .expect("Failed while creating a net with chain topology");
71    }
72
73    (net, place_refs, transition_refs)
74}
75
76/// Creates a new Petri net with one place and one transition forming a loop.
77/// Returns the net, the single place reference and the single transition reference.
78///
79/// # Panics
80///
81/// Panics if arcs cannot be added.
82#[must_use]
83pub fn create_net_loop_topology() -> (PetriNet, PlaceRef, TransitionRef) {
84    let mut net = PetriNet::new();
85    let place_ref = net.add_place("P1");
86    let transition_ref = net.add_transition("T1");
87
88    net.add_arc_place_transition(&place_ref, &transition_ref)
89        .expect("Failed while trying to create a simple net with a loop topology");
90    net.add_arc_transition_place(&transition_ref, &place_ref)
91        .expect("Failed while trying to create a simple net with a loop topology");
92
93    (net, place_ref, transition_ref)
94}
95
96#[cfg(test)]
97mod net_creator_tests {
98    use super::*;
99
100    #[test]
101    fn create_basic_unconnected_net_has_correct_number_of_nodes() {
102        let (net, place_refs, transition_refs) = create_basic_unconnected_net(8, 14);
103
104        assert_eq!(net.get_cardinality_places(), 8);
105        assert_eq!(net.get_cardinality_transitions(), 14);
106        assert_eq!(place_refs.len(), 8);
107        assert_eq!(transition_refs.len(), 14)
108    }
109
110    #[test]
111    fn create_basic_unconnected_net_has_correct_number_of_nodes_from_0_to_10() {
112        for number_of_places in 0..=10 {
113            for number_of_transitions in 0..=10 {
114                let (net, place_refs, transition_refs) =
115                    create_basic_unconnected_net(number_of_places, number_of_transitions);
116
117                assert_eq!(net.get_cardinality_places(), number_of_places);
118                assert_eq!(net.get_cardinality_transitions(), number_of_transitions);
119                assert_eq!(place_refs.len(), number_of_places);
120                assert_eq!(transition_refs.len(), number_of_transitions);
121            }
122        }
123    }
124
125    #[test]
126    fn create_basic_unconnected_net_has_no_arcs() {
127        let (net, place_refs, transition_refs) = create_basic_unconnected_net(8, 14);
128        let arcs_1 = net.find_arcs_place_transition();
129        let arcs_2 = net.find_arcs_transition_place();
130
131        assert!(arcs_1.is_empty());
132        assert!(arcs_2.is_empty());
133        assert_eq!(place_refs.len(), 8);
134        assert_eq!(transition_refs.len(), 14)
135    }
136
137    #[test]
138    fn create_basic_unconnected_net_has_valid_references() {
139        let (net, place_refs, transition_refs) = create_basic_unconnected_net(8, 14);
140
141        for place_ref in place_refs.iter() {
142            assert!(net.check_place_ref(place_ref));
143        }
144        for transition_ref in transition_refs.iter() {
145            assert!(net.check_transition_ref(transition_ref));
146        }
147    }
148
149    #[test]
150    fn create_basic_unconnected_net_has_no_arcs_from_0_to_10() {
151        for number_of_places in 0..=10 {
152            for number_of_transitions in 0..=10 {
153                let (net, _, _) =
154                    create_basic_unconnected_net(number_of_places, number_of_transitions);
155                let arcs_1 = net.find_arcs_place_transition();
156                let arcs_2 = net.find_arcs_transition_place();
157
158                assert!(arcs_1.is_empty());
159                assert!(arcs_2.is_empty());
160            }
161        }
162    }
163
164    #[test]
165    fn create_net_chain_topology_has_correct_number_of_nodes() {
166        let (net, place_refs, transition_refs) = create_net_chain_topology(3);
167
168        assert_eq!(net.get_cardinality_places(), 3);
169        assert_eq!(net.get_cardinality_transitions(), 2);
170        assert_eq!(place_refs.len(), 3);
171        assert_eq!(transition_refs.len(), 2);
172    }
173
174    #[test]
175    fn create_net_chain_topology_has_valid_references() {
176        let (net, place_refs, transition_refs) = create_net_chain_topology(3);
177
178        for place_ref in place_refs.iter() {
179            assert!(net.check_place_ref(place_ref));
180        }
181        for transition_ref in transition_refs.iter() {
182            assert!(net.check_transition_ref(transition_ref));
183        }
184    }
185
186    #[test]
187    fn create_net_chain_topology_length_zero_returns_empty_net() {
188        let (net, place_refs, transition_refs) = create_net_chain_topology(0);
189
190        assert_eq!(net.get_cardinality_places(), 0);
191        assert_eq!(net.get_cardinality_transitions(), 0);
192        assert_eq!(place_refs.len(), 0);
193        assert_eq!(transition_refs.len(), 0);
194    }
195
196    #[test]
197    fn create_net_chain_topology_has_correct_number_of_nodes_from_1_to_10() {
198        for length in 1..=10 {
199            let (net, place_refs, transition_refs) = create_net_chain_topology(length);
200
201            assert_eq!(net.get_cardinality_places(), length);
202            assert_eq!(net.get_cardinality_transitions(), length - 1);
203            assert_eq!(place_refs.len(), length);
204            assert_eq!(transition_refs.len(), length - 1);
205        }
206    }
207
208    #[test]
209    fn create_net_chain_topology_has_correct_number_of_arcs() {
210        let (net, place_refs, transition_refs) = create_net_chain_topology(3);
211        let arcs_1 = net.find_arcs_place_transition();
212        let arcs_2 = net.find_arcs_transition_place();
213
214        assert_eq!(arcs_1.len(), 2);
215        assert_eq!(arcs_2.len(), 2);
216        assert_eq!(place_refs.len(), 3);
217        assert_eq!(transition_refs.len(), 2);
218    }
219
220    #[test]
221    fn create_net_chain_topology_has_correct_number_of_arcs_from_1_to_10() {
222        for length in 1..=10 {
223            let (net, _, _) = create_net_chain_topology(length);
224            let arcs_1 = net.find_arcs_place_transition();
225            let arcs_2 = net.find_arcs_transition_place();
226
227            assert_eq!(arcs_1.len(), length - 1);
228            assert_eq!(arcs_2.len(), length - 1);
229        }
230    }
231
232    #[test]
233    fn create_net_loop_topology_has_correct_number_of_places() {
234        let (net, place_ref, transition_ref) = create_net_loop_topology();
235
236        assert_eq!(net.get_cardinality_places(), 1);
237        assert_eq!(net.get_cardinality_transitions(), 1);
238        assert!(net.check_place_ref(&place_ref));
239        assert!(net.check_transition_ref(&transition_ref));
240    }
241
242    #[test]
243    fn create_net_loop_topology_has_valid_references() {
244        let (net, place_ref, transition_ref) = create_net_loop_topology();
245
246        assert!(net.check_place_ref(&place_ref));
247        assert!(net.check_transition_ref(&transition_ref));
248    }
249
250    #[test]
251    fn create_net_loop_topology_has_correct_number_of_arcs() {
252        let (net, _, _) = create_net_loop_topology();
253        let arcs_1 = net.find_arcs_place_transition();
254        let arcs_2 = net.find_arcs_transition_place();
255
256        assert_eq!(arcs_1.len(), 1);
257        assert_eq!(arcs_2.len(), 1);
258    }
259}