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

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

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

            
15
/// Projects a variability parity game into a standard parity game by removing
16
/// edges that are not enabled by the given feature selection.
17
745
pub fn project_variability_parity_game(
18
745
    vpg: &VariabilityParityGame,
19
745
    feature_selection: &BDDFunction,
20
745
) -> Result<ParityGame, MercError> {
21
745
    let mut edges = Vec::new();
22

            
23
16390
    for v in vpg.iter_vertices() {
24
23730
        for edge in vpg.outgoing_conf_edges(v) {
25
            // Check if the edge is enabled by the feature selection, if so, include it.
26
23730
            if feature_selection.and(edge.configuration())?.satisfiable() {
27
22131
                edges.push((v, edge.to()));
28
22131
            }
29
        }
30
    }
31

            
32
745
    Ok(ParityGame::from_edges(
33
745
        vpg.initial_vertex(),
34
745
        vpg.owners().clone(),
35
745
        vpg.priorities().clone(),
36
        true, // It can be that after removing edges the result is not a total parity game.
37
1490
        || edges.iter().cloned(),
38
    ))
39
745
}
40

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

            
48
/// Projects all configurations of a variability parity game into standard parity games.
49
100
pub fn project_variability_parity_games_iter<'a>(
50
100
    vpg: &'a VariabilityParityGame,
51
100
    timing: &'a Timing,
52
100
) -> impl Iterator<Item = Result<(Projected, &'a Timing), MercError>> {
53
745
    CubeIterAll::new(vpg.configuration()).map(move |cube| {
54
745
        let cube = cube?;
55
745
        let bdd = match bits_to_bdd(&vpg.configuration().manager_ref(), vpg.variables(), &cube) {
56
745
            Ok(bdd) => bdd,
57
            Err(e) => return Err(MercError::from(e)),
58
        };
59

            
60
745
        let pg = timing.measure("project", || -> Result<_, MercError> {
61
745
            project_variability_parity_game(vpg, &bdd)
62
745
        })?;
63

            
64
745
        Ok((
65
745
            Projected {
66
745
                bits: cube,
67
745
                bdd,
68
745
                game: pg,
69
745
            },
70
745
            timing,
71
745
        ))
72
745
    })
73
100
}