1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
use std::collections::VecDeque;
use std::marker::PhantomData;

use crate::modifications::Modification;
use crate::reducers::reduce::{ConservativeReduce, PlaceReduce, TransitionReduce};
use crate::reducers::Reduce;

/// Execute a reduction, then on each transition and place modified we execute the actions
/// `PostPlace` and `PostTransition` on each of the modifications
pub struct SmartReducer<Net, Red, PostPlace, PostTransition>(
    PhantomData<(Net, Red, PostPlace, PostTransition)>,
)
where
    Red: Reduce<Net>,
    PostPlace: PlaceReduce<Net>,
    PostTransition: TransitionReduce<Net>;

impl<Net, Red, PostPlace, PostTransition> ConservativeReduce<Net>
    for SmartReducer<Net, Red, PostPlace, PostTransition>
where
    Red: ConservativeReduce<Net>,
    PostPlace: PlaceReduce<Net> + ConservativeReduce<Net>,
    PostTransition: TransitionReduce<Net> + ConservativeReduce<Net>,
{
}

impl<Net, Red, PostPlace, PostTransition> Reduce<Net>
    for SmartReducer<Net, Red, PostPlace, PostTransition>
where
    Red: Reduce<Net>,
    PostPlace: PlaceReduce<Net>,
    PostTransition: TransitionReduce<Net>,
{
    fn reduce(net: &mut Net, modifications: &mut Vec<Modification>) {
        let mut original_modifications = vec![];
        // Run original reduction
        Red::reduce(net, &mut original_modifications);
        // Fill a queue with all modification
        let mut modifications_queue = VecDeque::from(original_modifications);
        // While this queue is not empty, try to execute PostPlace and PostTransition
        while let Some(modification) = modifications_queue.pop_front() {
            match modification {
                Modification::Agglomeration(agg) => {
                    let mut modifications = vec![];
                    PostPlace::place_reduce(net, agg.new_place, &mut modifications);
                    modifications.push(Modification::Agglomeration(agg));
                    modifications_queue.extend(modifications);
                }
                other => modifications.push(other),
            }
        }
    }
}