1
//! Authors: Maurice Laveaux and Sjef van Loo
2

            
3
use std::fmt;
4

            
5
use delegate::delegate;
6
use oxidd::BooleanFunction;
7
use oxidd::ManagerRef;
8
use oxidd::bdd::BDDFunction;
9
use oxidd::bdd::BDDManagerRef;
10

            
11
use merc_symbolic::FormatConfigSet;
12
use merc_symbolic::minus;
13
use merc_utilities::MercError;
14

            
15
use crate::Edge;
16
use crate::PG;
17
use crate::ParityGame;
18
use crate::Player;
19
use crate::Priority;
20
use crate::VertexIndex;
21

            
22
/// A variability parity game is an extension of a parity game where each edge is
23
/// associated with a BDD function representing the configurations in which the
24
/// edge is enabled.
25
///
26
/// # Details
27
///
28
/// This is also a max-priority parity game. There is also a configuration set associated
29
/// with the variability parity game, representing the overall configurations.
30
pub struct VariabilityParityGame {
31
    /// The underlying normal parity game.
32
    game: ParityGame,
33

            
34
    /// The overall configurations for the variability parity game.
35
    configuration: BDDFunction,
36

            
37
    /// The variables used in the configuration BDD.
38
    variables: Vec<BDDFunction>,
39

            
40
    /// Every edge has an associated BDD function representing the configurations
41
    /// in which the edge is enabled.
42
    edges_configuration: Vec<BDDFunction>,
43
}
44

            
45
impl VariabilityParityGame {
46
    /// Constructs a new variability parity game from an iterator over edges.
47
    ///
48
    /// The vertices are given by their owner and priority.
49
    /// The `edges` iterator should yield tuples of the form (from, configuration, to).
50
303
    pub fn from_edges<F, I>(
51
303
        manager_ref: &BDDManagerRef,
52
303
        initial_vertex: VertexIndex,
53
303
        owner: Vec<Player>,
54
303
        priority: Vec<Priority>,
55
303
        configuration: BDDFunction,
56
303
        variables: Vec<BDDFunction>,
57
303
        mut edges: F,
58
303
    ) -> Self
59
303
    where
60
303
        F: FnMut() -> I,
61
303
        I: Iterator<Item = (VertexIndex, BDDFunction, VertexIndex)>,
62
    {
63
303
        let num_of_vertices = owner.len();
64

            
65
303
        let mut vertices = Vec::new();
66
303
        vertices.resize_with(num_of_vertices, Default::default);
67

            
68
        // Count the number of transitions for every state
69
303
        let mut num_of_edges = 0;
70
16533
        for (from, _, to) in edges() {
71
            // Ensure that the states vector is large enough.
72
16533
            if vertices.len() <= *from.max(to) {
73
                vertices.resize_with(*from.max(to) + 1, || 0);
74
16533
            }
75

            
76
16533
            vertices[*from] += 1;
77
16533
            num_of_edges += 1;
78

            
79
16533
            debug_assert!(
80
16533
                *from < num_of_vertices && *to < num_of_vertices,
81
                "Vertex index out of bounds: from {:?}, to {:?}, num_of_vertices {}",
82
                from,
83
                to,
84
                num_of_vertices
85
            );
86
        }
87

            
88
303
        if initial_vertex.value() >= vertices.len() {
89
            // Ensure that the initial state is a valid state (and all states before it exist).
90
            vertices.resize_with(initial_vertex.value() + 1, Default::default);
91
303
        }
92

            
93
        // Sets the offset for every state into the edge arrays.
94
8649
        vertices.iter_mut().fold(0, |count, start| {
95
8649
            let result = count + *start;
96
8649
            *start = count;
97
8649
            result
98
8649
        });
99

            
100
        // Place the transitions, and increment the end for every state.
101
303
        let mut edges_to = vec![VertexIndex::new(0); num_of_edges];
102
303
        let mut edges_configuration =
103
303
            manager_ref.with_manager_shared(|manager| vec![BDDFunction::f(manager); num_of_edges]);
104
16533
        for (from, config, to) in edges() {
105
16533
            let start = &mut vertices[*from];
106
16533
            edges_to[*start] = to;
107
16533
            edges_configuration[*start] = config;
108
16533
            *start += 1;
109
16533
        }
110

            
111
        // Reset the offset to the start.
112
8649
        vertices.iter_mut().fold(0, |previous, start| {
113
8649
            let result = *start;
114
8649
            *start = previous;
115
8649
            result
116
8649
        });
117

            
118
303
        vertices.push(num_of_edges); // Sentinel vertex
119

            
120
303
        Self::new(
121
303
            ParityGame::new(initial_vertex, owner, priority, vertices, edges_to),
122
303
            configuration,
123
303
            variables,
124
303
            edges_configuration,
125
        )
126
303
    }
127

            
128
    /// Construct a new variability parity game from the given components.
129
703
    pub(crate) fn new(
130
703
        parity_game: ParityGame,
131
703
        configuration: BDDFunction,
132
703
        variables: Vec<BDDFunction>,
133
703
        edges_configuration: Vec<BDDFunction>,
134
703
    ) -> Self {
135
703
        let result = Self {
136
703
            game: parity_game,
137
703
            configuration,
138
703
            variables,
139
703
            edges_configuration,
140
703
        };
141
703
        result.assert_consistent();
142
703
        result
143
703
    }
144

            
145
    /// Returns true iff the variability parity game is total.
146
    ///
147
    /// # Details
148
    ///
149
    /// Unlike the [`PG::is_total`] check (which only verifies that every vertex
150
    /// has at least one outgoing edge), this also verifies that the outgoing
151
    /// edge configurations of every vertex cover the overall configuration.
152
402
    pub fn is_vpg_total(&self, manager_ref: &BDDManagerRef) -> Result<bool, MercError> {
153
        // Check that every vertex has at least one outgoing edge.
154
7831
        for v in self.iter_vertices() {
155
7831
            if self.outgoing_edges(v).next().is_none() {
156
1
                return Ok(false);
157
7830
            }
158
        }
159

            
160
        // Check that the configurations of the outgoing edges cover the overall configuration.
161
7824
        for v in self.iter_vertices() {
162
            // Compute the disjunction of all outgoing edge configurations.
163
7824
            let covered = self.outgoing_edges(v).try_fold(
164
7824
                manager_ref.with_manager_shared(|manager| BooleanFunction::f(manager)),
165
16875
                |acc: BDDFunction, edge| acc.or(edge.label()),
166
            )?;
167

            
168
            // If there are configurations not covered by the outgoing edges, the game is not total.
169
7824
            if minus(&self.configuration, &covered)?.satisfiable() {
170
                return Ok(false);
171
7824
            }
172
        }
173

            
174
401
        Ok(true)
175
402
    }
176

            
177
    /// Returns the overall configuration BDD of the variability parity game.
178
45335
    pub fn configuration(&self) -> &BDDFunction {
179
45335
        &self.configuration
180
45335
    }
181

            
182
    /// Returns the variables used in the configuration BDD.
183
633
    pub fn variables(&self) -> &Vec<BDDFunction> {
184
633
        &self.variables
185
633
    }
186

            
187
    /// Returns the owners of the vertices in the variability parity game.
188
332
    pub(crate) fn owners(&self) -> &Vec<Player> {
189
332
        self.game.owners()
190
332
    }
191

            
192
    /// Returns the priorities of the vertices in the variability parity game.
193
1035
    pub(crate) fn priorities(&self) -> &Vec<Priority> {
194
1035
        self.game.priorities()
195
1035
    }
196

            
197
    /// Asserts that the internal state of the variability parity game is consistent.
198
703
    fn assert_consistent(&self) {
199
703
        debug_assert!(
200
703
            self.initial_vertex().value() < self.num_of_vertices(),
201
            "Initial vertex index {} out of bounds {}",
202
            self.initial_vertex().value(),
203
            self.num_of_vertices()
204
        );
205

            
206
703
        debug_assert_eq!(
207
703
            self.priorities().len(),
208
703
            self.num_of_vertices(),
209
            "Owner and priority vectors should have the same length"
210
        );
211

            
212
703
        debug_assert_eq!(
213
703
            self.game.num_of_edges(),
214
703
            self.edges_configuration.len(),
215
            "There should be a configuration BDD for every edge"
216
        );
217

            
218
        // Edge duplicates are already checked in the underlying parity game.
219
703
    }
220
}
221

            
222
impl PG for VariabilityParityGame {
223
    type Label = BDDFunction;
224

            
225
65056
    fn outgoing_edges<'a>(&'a self, state_index: VertexIndex) -> impl Iterator<Item = Edge<'a, Self::Label>> + 'a {
226
65056
        let start = self.game.vertices()[*state_index];
227
65056
        let end = self.game.vertices()[*state_index + 1];
228
65056
        self.edges_configuration[start..end]
229
65056
            .iter()
230
65056
            .zip(self.game.edges_to()[start..end].iter())
231
128864
            .map(|(configuration, &to)| Edge::new(configuration, to))
232
65056
    }
233

            
234
    delegate! {
235
        to self.game {
236
1338
            fn initial_vertex(&self) -> VertexIndex;
237
5498
            fn num_of_vertices(&self) -> usize;
238
902
            fn num_of_edges(&self) -> usize;
239
2969
            fn iter_vertices(&self) -> impl Iterator<Item = VertexIndex> + '_;
240
39895
            fn owner(&self, vertex: VertexIndex) -> Player;
241
35821
            fn priority(&self, vertex: VertexIndex) -> Priority;
242
            fn is_total(&self) -> bool;
243
            fn highest_priority(&self) -> Priority;
244
        }
245
    }
246
}
247

            
248
impl fmt::Display for VariabilityParityGame {
249
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250
        writeln!(f, "Variability Parity Game:")?;
251
        writeln!(f, "Configuration BDD: {}", FormatConfigSet(self.configuration()))?;
252

            
253
        for v in self.iter_vertices() {
254
            write!(
255
                f,
256
                "v{}: {:?}, priority={}, edges=[",
257
                v,
258
                self.owner(v).to_index(),
259
                self.priority(v)
260
            )?;
261

            
262
            let mut first = true;
263
            for edge in self.outgoing_edges(v) {
264
                if !first {
265
                    write!(f, ", ")?;
266
                }
267
                write!(f, "(v{}, {})", edge.to(), FormatConfigSet(edge.label()))?;
268
                first = false;
269
            }
270

            
271
            writeln!(f, "]")?;
272
        }
273

            
274
        Ok(())
275
    }
276
}