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
330
    CubeIterAll::new(vpg.configuration()).map(move |cube| {
21
330
        let cube = cube?;
22
330
        let bdd = match bits_to_bdd(&vpg.configuration().manager_ref(), vpg.variables(), &cube) {
23
330
            Ok(bdd) => bdd,
24
            Err(e) => return Err(MercError::from(e)),
25
        };
26

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

            
31
330
        Ok((
32
330
            Projected {
33
330
                bits: cube,
34
330
                bdd,
35
330
                game: pg,
36
330
            },
37
330
            timing,
38
330
        ))
39
330
    })
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
330
pub fn project_variability_parity_game(
52
330
    vpg: &VariabilityParityGame,
53
330
    feature_selection: &BDDFunction,
54
330
) -> Result<ParityGame, MercError> {
55
330
    let mut edges = Vec::new();
56

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

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