1use crate::algorithms::astar::CfgGraphNode;
20use std::collections::{HashMap, HashSet, VecDeque};
21
22#[derive(Debug, Clone)]
24pub struct SliceResult {
25 pub nodes: HashSet<u64>,
27 pub edges: Vec<(u64, u64)>,
29 pub direction: SliceDirection,
31 pub criterion: u64,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum SliceDirection {
38 Backward,
40 Forward,
42}
43
44pub fn backward_slice(nodes: &[CfgGraphNode], criterion: u64) -> SliceResult {
56 let mut predecessors: HashMap<u64, Vec<u64>> = HashMap::new();
58 let mut all_nodes: HashSet<u64> = HashSet::new();
59
60 for node in nodes {
61 all_nodes.insert(node.id);
62 for &succ in &node.successors {
63 predecessors.entry(succ).or_default().push(node.id);
64 }
65 }
66
67 let mut slice_nodes: HashSet<u64> = HashSet::new();
69 let mut worklist: VecDeque<u64> = VecDeque::new();
70
71 if all_nodes.contains(&criterion) {
72 slice_nodes.insert(criterion);
73 worklist.push_back(criterion);
74 }
75
76 while let Some(node_id) = worklist.pop_front() {
77 if let Some(preds) = predecessors.get(&node_id) {
78 for &pred in preds {
79 if !slice_nodes.contains(&pred) {
80 slice_nodes.insert(pred);
81 worklist.push_back(pred);
82 }
83 }
84 }
85 }
86
87 let mut edges = Vec::new();
89 for node in nodes {
90 if slice_nodes.contains(&node.id) {
91 for &succ in &node.successors {
92 if slice_nodes.contains(&succ) {
93 edges.push((node.id, succ));
94 }
95 }
96 }
97 }
98
99 SliceResult {
100 nodes: slice_nodes,
101 edges,
102 direction: SliceDirection::Backward,
103 criterion,
104 }
105}
106
107pub fn forward_slice(nodes: &[CfgGraphNode], criterion: u64) -> SliceResult {
119 let node_map: HashMap<u64, &CfgGraphNode> = nodes.iter().map(|n| (n.id, n)).collect();
120
121 let mut slice_nodes: HashSet<u64> = HashSet::new();
123 let mut worklist: VecDeque<u64> = VecDeque::new();
124
125 if node_map.contains_key(&criterion) {
126 slice_nodes.insert(criterion);
127 worklist.push_back(criterion);
128 }
129
130 while let Some(node_id) = worklist.pop_front() {
131 if let Some(node) = node_map.get(&node_id) {
132 for &succ in &node.successors {
133 if !slice_nodes.contains(&succ) {
134 slice_nodes.insert(succ);
135 worklist.push_back(succ);
136 }
137 }
138 }
139 }
140
141 let mut edges = Vec::new();
143 for node in nodes {
144 if slice_nodes.contains(&node.id) {
145 for &succ in &node.successors {
146 if slice_nodes.contains(&succ) {
147 edges.push((node.id, succ));
148 }
149 }
150 }
151 }
152
153 SliceResult {
154 nodes: slice_nodes,
155 edges,
156 direction: SliceDirection::Forward,
157 criterion,
158 }
159}
160
161pub fn full_slice(nodes: &[CfgGraphNode], criterion: u64) -> SliceResult {
163 let backward = backward_slice(nodes, criterion);
164 let forward = forward_slice(nodes, criterion);
165
166 let mut nodes = backward.nodes;
167 nodes.extend(forward.nodes);
168
169 let mut edges = backward.edges;
170 edges.extend(forward.edges);
171
172 SliceResult {
173 nodes,
174 edges,
175 direction: SliceDirection::Backward, criterion,
177 }
178}
179
180pub fn slice_size(slice: &SliceResult) -> usize {
182 slice.nodes.len()
183}
184
185pub fn node_in_slice(node_id: u64, slice: &SliceResult) -> bool {
187 slice.nodes.contains(&node_id)
188}
189
190pub fn slice_coverage(slice: &SliceResult, total_nodes: usize) -> f32 {
192 if total_nodes == 0 {
193 return 0.0;
194 }
195 (slice.nodes.len() as f32) / (total_nodes as f32) * 100.0
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn test_backward_slice_linear() {
204 let nodes = vec![
206 CfgGraphNode {
207 id: 0,
208 x: 0.0,
209 y: 0.0,
210 z: 0.0,
211 successors: vec![1],
212 },
213 CfgGraphNode {
214 id: 1,
215 x: 1.0,
216 y: 0.0,
217 z: 0.0,
218 successors: vec![2],
219 },
220 CfgGraphNode {
221 id: 2,
222 x: 2.0,
223 y: 0.0,
224 z: 0.0,
225 successors: vec![3],
226 },
227 CfgGraphNode {
228 id: 3,
229 x: 3.0,
230 y: 0.0,
231 z: 0.0,
232 successors: vec![],
233 },
234 ];
235
236 let slice = backward_slice(&nodes, 3);
238 assert_eq!(slice.nodes.len(), 4);
239 assert!(slice.nodes.contains(&0));
240 assert!(slice.nodes.contains(&3));
241 assert_eq!(slice.direction, SliceDirection::Backward);
242 }
243
244 #[test]
245 fn test_backward_slice_partial() {
246 let nodes = vec![
248 CfgGraphNode {
249 id: 0,
250 x: 0.0,
251 y: 0.0,
252 z: 0.0,
253 successors: vec![1],
254 },
255 CfgGraphNode {
256 id: 1,
257 x: 1.0,
258 y: 0.0,
259 z: 0.0,
260 successors: vec![2],
261 },
262 CfgGraphNode {
263 id: 2,
264 x: 2.0,
265 y: 0.0,
266 z: 0.0,
267 successors: vec![3],
268 },
269 CfgGraphNode {
270 id: 3,
271 x: 3.0,
272 y: 0.0,
273 z: 0.0,
274 successors: vec![],
275 },
276 ];
277
278 let slice = backward_slice(&nodes, 1);
280 assert_eq!(slice.nodes.len(), 2);
281 assert!(slice.nodes.contains(&0));
282 assert!(slice.nodes.contains(&1));
283 }
284
285 #[test]
286 fn test_forward_slice_linear() {
287 let nodes = vec![
289 CfgGraphNode {
290 id: 0,
291 x: 0.0,
292 y: 0.0,
293 z: 0.0,
294 successors: vec![1],
295 },
296 CfgGraphNode {
297 id: 1,
298 x: 1.0,
299 y: 0.0,
300 z: 0.0,
301 successors: vec![2],
302 },
303 CfgGraphNode {
304 id: 2,
305 x: 2.0,
306 y: 0.0,
307 z: 0.0,
308 successors: vec![3],
309 },
310 CfgGraphNode {
311 id: 3,
312 x: 3.0,
313 y: 0.0,
314 z: 0.0,
315 successors: vec![],
316 },
317 ];
318
319 let slice = forward_slice(&nodes, 0);
321 assert_eq!(slice.nodes.len(), 4);
322 assert!(slice.nodes.contains(&0));
323 assert!(slice.nodes.contains(&3));
324 assert_eq!(slice.direction, SliceDirection::Forward);
325 }
326
327 #[test]
328 fn test_forward_slice_partial() {
329 let nodes = vec![
331 CfgGraphNode {
332 id: 0,
333 x: 0.0,
334 y: 0.0,
335 z: 0.0,
336 successors: vec![1],
337 },
338 CfgGraphNode {
339 id: 1,
340 x: 1.0,
341 y: 0.0,
342 z: 0.0,
343 successors: vec![2],
344 },
345 CfgGraphNode {
346 id: 2,
347 x: 2.0,
348 y: 0.0,
349 z: 0.0,
350 successors: vec![3],
351 },
352 CfgGraphNode {
353 id: 3,
354 x: 3.0,
355 y: 0.0,
356 z: 0.0,
357 successors: vec![],
358 },
359 ];
360
361 let slice = forward_slice(&nodes, 2);
363 assert_eq!(slice.nodes.len(), 2);
364 assert!(slice.nodes.contains(&2));
365 assert!(slice.nodes.contains(&3));
366 }
367
368 #[test]
369 fn test_slice_coverage() {
370 let nodes = vec![
371 CfgGraphNode {
372 id: 0,
373 x: 0.0,
374 y: 0.0,
375 z: 0.0,
376 successors: vec![1],
377 },
378 CfgGraphNode {
379 id: 1,
380 x: 1.0,
381 y: 0.0,
382 z: 0.0,
383 successors: vec![],
384 },
385 ];
386
387 let slice = backward_slice(&nodes, 1);
388 let coverage = slice_coverage(&slice, 2);
389 assert!((coverage - 100.0).abs() < 0.001);
390 }
391
392 #[test]
393 fn test_node_in_slice() {
394 let nodes = vec![
395 CfgGraphNode {
396 id: 0,
397 x: 0.0,
398 y: 0.0,
399 z: 0.0,
400 successors: vec![1],
401 },
402 CfgGraphNode {
403 id: 1,
404 x: 1.0,
405 y: 0.0,
406 z: 0.0,
407 successors: vec![],
408 },
409 ];
410
411 let slice = backward_slice(&nodes, 1);
412 assert!(node_in_slice(0, &slice));
413 assert!(node_in_slice(1, &slice));
414 }
415
416 #[test]
417 fn test_backward_slice_branching() {
418 let nodes = vec![
420 CfgGraphNode {
421 id: 0,
422 x: 0.0,
423 y: 0.0,
424 z: 0.0,
425 successors: vec![1, 2],
426 },
427 CfgGraphNode {
428 id: 1,
429 x: 1.0,
430 y: 0.0,
431 z: 0.0,
432 successors: vec![3],
433 },
434 CfgGraphNode {
435 id: 2,
436 x: 2.0,
437 y: 0.0,
438 z: 0.0,
439 successors: vec![3],
440 },
441 CfgGraphNode {
442 id: 3,
443 x: 3.0,
444 y: 0.0,
445 z: 0.0,
446 successors: vec![],
447 },
448 ];
449
450 let slice = backward_slice(&nodes, 3);
452 assert_eq!(slice.nodes.len(), 4);
453 }
454
455 #[test]
456 fn test_slice_edges() {
457 let nodes = vec![
458 CfgGraphNode {
459 id: 0,
460 x: 0.0,
461 y: 0.0,
462 z: 0.0,
463 successors: vec![1],
464 },
465 CfgGraphNode {
466 id: 1,
467 x: 1.0,
468 y: 0.0,
469 z: 0.0,
470 successors: vec![2],
471 },
472 CfgGraphNode {
473 id: 2,
474 x: 2.0,
475 y: 0.0,
476 z: 0.0,
477 successors: vec![],
478 },
479 ];
480
481 let slice = backward_slice(&nodes, 2);
482 assert_eq!(slice.edges.len(), 2);
483 assert!(slice.edges.contains(&(0, 1)));
484 assert!(slice.edges.contains(&(1, 2)));
485 }
486}