pnets_shrunk/reducers/standard/
simple_loop_agglomeration.rs1use indexed_vec::IndexVec;
2
3use pnets::standard::Net;
4use pnets::{arc, PlaceId, TransitionId};
5
6use crate::modifications::{Agglomeration, Modification};
7use crate::reducers::reduce::ConservativeReduce;
8use crate::reducers::Reduce;
9
10#[derive(Clone)]
11struct SimpleLoopAgglomerationGraphNode {
12 connected: Vec<(TransitionId, PlaceId)>,
13 num: Option<usize>,
14 accessible_num: Option<usize>,
15 in_stack: bool,
16}
17
18#[derive(Default)]
19struct Partition {
20 transitions: Vec<TransitionId>,
21 places: Vec<PlaceId>,
22}
23
24impl Partition {
25 pub fn add(&mut self, tr: TransitionId, pl: PlaceId) {
26 match self.transitions.binary_search(&tr) {
27 Ok(_) => {} Err(pos) => self.transitions.insert(pos, tr),
29 }
30 match self.places.binary_search(&pl) {
31 Ok(_) => {} Err(pos) => self.places.insert(pos, pl),
33 }
34 }
35}
36
37struct SimpleLoopAgglomerationGraph {
42 pub nodes: IndexVec<TransitionId, SimpleLoopAgglomerationGraphNode>,
43 partitions: Vec<Partition>,
44 current_num: usize,
45 stack: Vec<(TransitionId, PlaceId)>,
46}
47
48impl SimpleLoopAgglomerationGraph {
49 pub fn new(node_count: usize) -> Self {
50 let nodes: IndexVec<TransitionId, SimpleLoopAgglomerationGraphNode> = IndexVec::from_elem_n(
51 SimpleLoopAgglomerationGraphNode {
52 connected: vec![],
53 num: None,
54 accessible_num: None,
55 in_stack: false,
56 },
57 node_count,
58 );
59 Self {
60 nodes,
61 partitions: vec![],
62 current_num: 0,
63 stack: vec![],
64 }
65 }
66
67 fn walk(&mut self, net: &Net, source_tr: TransitionId) {
68 let source_transition = &net[source_tr];
69
70 if (source_transition.consume.len() != 1)
72 || source_transition.produce.len() != 1
73 || (source_transition.consume.iter().next().unwrap().1 != 1)
74 || (source_transition.produce.iter().next().unwrap().1 != 1)
75 {
76 return;
77 }
78 self.nodes[source_tr].num = Some(self.current_num);
79 self.nodes[source_tr].accessible_num = Some(self.current_num);
80 self.nodes[source_tr].in_stack = true;
81 self.current_num += 1;
82
83 let pl = match source_transition.produce.iter().next() {
84 Some(&(pl, _)) => pl,
85 _ => return,
86 };
87 let place = &net[pl];
88 self.stack.push((source_tr, pl));
89 for &tr in place.consumed_by.iter().filter_map(|(tr, _)| {
90 if net[*tr].consume.len() == 1
91 && net[*tr].produce.len() == 1
92 && (source_transition.consume.iter().next().unwrap().1 == 1)
93 && (source_transition.produce.iter().next().unwrap().1 == 1)
94 {
95 Some(tr)
96 } else {
97 None
98 }
99 }) {
100 if self.nodes[tr].num.is_none() {
101 self.walk(net, tr);
102 self.nodes[source_tr].accessible_num = Some(
103 self.nodes[source_tr]
104 .accessible_num
105 .unwrap()
106 .min(self.nodes[tr].accessible_num.unwrap()),
107 );
108 } else if self.nodes[tr].in_stack {
109 self.nodes[source_tr].accessible_num = Some(
110 self.nodes[source_tr]
111 .accessible_num
112 .unwrap()
113 .min(self.nodes[tr].num.unwrap()),
114 );
115 }
116 }
117
118 if self.nodes[source_tr].accessible_num == self.nodes[source_tr].num {
119 let mut component = Partition::default();
120 while let Some((tr, pl)) = self.stack.pop() {
121 component.add(tr, pl);
122 if tr == source_tr {
123 break;
124 }
125 }
126 if component.transitions.len() > 1 && component.places.len() > 1 {
127 self.partitions.push(component);
128 }
129 }
130 }
131
132 pub fn compute_partitions(&mut self, net: &Net) {
133 for n in (0..self.nodes.len()).map(|n| TransitionId::from(n)) {
134 if self.nodes[n].num.is_none() {
135 self.walk(net, n);
136 }
137 }
138 }
139}
140
141pub struct SimpleLoopAgglomeration;
145
146impl ConservativeReduce<Net> for SimpleLoopAgglomeration {}
147
148impl Reduce<Net> for SimpleLoopAgglomeration {
149 fn reduce(net: &mut Net, modifications: &mut Vec<Modification>) {
150 let mut graph = SimpleLoopAgglomerationGraph::new(net.transitions.len());
152 graph.compute_partitions(net);
153
154 for partition in &graph.partitions {
156 let new_place = net.create_place();
157 let mut arcs = vec![];
159 let mut initial = 0;
160 for &pl in &partition.places {
161 arcs.extend(net[pl].get_arcs());
162 initial += net[pl].initial;
163 net.delete_place(pl);
164 }
165 net[new_place].initial = initial;
166 for original_arc in &arcs {
167 match *original_arc {
168 arc::Kind::Consume(_, tr, w) => {
169 net.add_arc(arc::Kind::Consume(new_place, tr, w)).unwrap();
170 }
171 arc::Kind::Produce(_, tr, w) => {
172 net.add_arc(arc::Kind::Produce(new_place, tr, w)).unwrap();
173 }
174 _ => {}
175 }
176 }
177 modifications.push(Modification::Agglomeration(Agglomeration {
178 deleted_places: partition.places.iter().map(|pl| (*pl, 1)).collect(),
179 new_place,
180 constant: 0,
181 factor: 1,
182 }));
183 }
184 }
185}