1
use oxidd::BooleanFunction;
2
use oxidd::Function;
3
use oxidd::bdd::BDDFunction;
4
use oxidd::util::OptBool;
5

            
6
use merc_symbolic::CubeIterAll;
7
use merc_symbolic::bits_to_bdd;
8
use merc_utilities::MercError;
9
use merc_utilities::Timing;
10

            
11
use crate::PG;
12
use crate::ParityGame;
13
use crate::VariabilityParityGame;
14

            
15
/// Projects all configurations of a variability parity game into standard parity games.
16
100
pub fn project_variability_parity_games_iter<'a>(
17
100
    vpg: &'a VariabilityParityGame,
18
100
    timing: &'a Timing,
19
100
) -> impl Iterator<Item = Result<(Projected, &'a Timing), MercError>> {
20
318
    CubeIterAll::new(vpg.configuration()).map(move |cube| {
21
318
        let cube = cube?;
22
318
        let bdd = match bits_to_bdd(&vpg.configuration().manager_ref(), vpg.variables(), &cube) {
23
318
            Ok(bdd) => bdd,
24
            Err(e) => return Err(MercError::from(e)),
25
        };
26

            
27
318
        let pg = timing.measure("project", || -> Result<_, MercError> {
28
318
            project_variability_parity_game(vpg, &bdd)
29
318
        })?;
30

            
31
318
        Ok((
32
318
            Projected {
33
318
                bits: cube,
34
318
                bdd,
35
318
                game: pg,
36
318
            },
37
318
            timing,
38
318
        ))
39
318
    })
40
100
}
41

            
42
/// A projected configuration of a variability parity game.
43
pub struct Projected {
44
    pub bits: Vec<OptBool>,
45
    pub bdd: BDDFunction,
46
    pub game: ParityGame,
47
}
48

            
49
/// Projects a variability parity game into a standard parity game by removing
50
/// edges that are not enabled by the given feature selection.
51
318
pub fn project_variability_parity_game(
52
318
    vpg: &VariabilityParityGame,
53
318
    feature_selection: &BDDFunction,
54
318
) -> Result<ParityGame, MercError> {
55
318
    let mut edges = Vec::new();
56

            
57
6996
    for v in vpg.iter_vertices() {
58
15279
        for edge in vpg.outgoing_edges(v) {
59
            // Check if the edge is enabled by the feature selection, if so, include it.
60
15279
            if feature_selection.and(edge.label())?.satisfiable() {
61
10243
                edges.push((v, edge.to()));
62
10243
            }
63
        }
64
    }
65

            
66
318
    Ok(ParityGame::from_edges(
67
318
        vpg.initial_vertex(),
68
318
        vpg.owners().clone(),
69
318
        vpg.priorities().clone(),
70
        true, // It can be that after removing edges the result is not a total parity game.
71
636
        || edges.iter().cloned(),
72
    ))
73
318
}