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
16527
        for (from, _, to) in edges() {
71
            // Ensure that the states vector is large enough.
72
16527
            if vertices.len() <= *from.max(to) {
73
                vertices.resize_with(*from.max(to) + 1, || 0);
74
16527
            }
75

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

            
79
16527
            debug_assert!(
80
16527
                *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
16527
        for (from, config, to) in edges() {
105
16527
            let start = &mut vertices[*from];
106
16527
            edges_to[*start] = to;
107
16527
            edges_configuration[*start] = config;
108
16527
            *start += 1;
109
16527
        }
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 parity game is total, checks all vertices have at least one outgoing edge.
146
402
    pub fn is_total(&self, manager_ref: &BDDManagerRef) -> Result<bool, MercError> {
147
        // Check that every vertex has at least one outgoing edge.
148
7831
        for v in self.iter_vertices() {
149
7831
            if self.outgoing_edges(v).next().is_none() {
150
1
                return Ok(false);
151
7830
            }
152
        }
153

            
154
        // Check that the configurations of the outgoing edges cover the overall configuration.
155
7824
        for v in self.iter_vertices() {
156
            // Compute the disjunction of all outgoing edge configurations.
157
7824
            let covered = self.outgoing_edges(v).try_fold(
158
7824
                manager_ref.with_manager_shared(|manager| BooleanFunction::f(manager)),
159
16874
                |acc: BDDFunction, edge| acc.or(edge.label()),
160
            )?;
161

            
162
            // If there are configurations not covered by the outgoing edges, the game is not total.
163
7824
            if minus(&self.configuration, &covered)?.satisfiable() {
164
                return Ok(false);
165
7824
            }
166
        }
167

            
168
401
        Ok(true)
169
402
    }
170

            
171
    /// Returns the overall configuration BDD of the variability parity game.
172
42483
    pub fn configuration(&self) -> &BDDFunction {
173
42483
        &self.configuration
174
42483
    }
175

            
176
    /// Returns the variables used in the configuration BDD.
177
619
    pub fn variables(&self) -> &Vec<BDDFunction> {
178
619
        &self.variables
179
619
    }
180

            
181
    /// Returns the owners of the vertices in the variability parity game.
182
318
    pub(crate) fn owners(&self) -> &Vec<Player> {
183
318
        self.game.owners()
184
318
    }
185

            
186
    /// Returns the priorities of the vertices in the variability parity game.
187
1021
    pub(crate) fn priorities(&self) -> &Vec<Priority> {
188
1021
        self.game.priorities()
189
1021
    }
190

            
191
    /// Asserts that the internal state of the variability parity game is consistent.
192
703
    fn assert_consistent(&self) {
193
703
        debug_assert!(
194
703
            self.initial_vertex().value() < self.num_of_vertices(),
195
            "Initial vertex index {} out of bounds {}",
196
            self.initial_vertex().value(),
197
            self.num_of_vertices()
198
        );
199

            
200
703
        debug_assert_eq!(
201
703
            self.priorities().len(),
202
703
            self.num_of_vertices(),
203
            "Owner and priority vectors should have the same length"
204
        );
205

            
206
703
        debug_assert_eq!(
207
703
            self.game.num_of_edges(),
208
703
            self.edges_configuration.len(),
209
            "There should be a configuration BDD for every edge"
210
        );
211
        
212
        // Edge duplicates are already checked in the underlying parity game.
213
703
    }
214
}
215

            
216
impl PG for VariabilityParityGame {
217
    type Label = BDDFunction;
218

            
219
62954
    fn outgoing_edges<'a>(&'a self, state_index: VertexIndex) -> impl Iterator<Item = Edge<'a, Self::Label>> + 'a {
220
62954
        let start = self.game.vertices()[*state_index];
221
62954
        let end = self.game.vertices()[*state_index + 1];
222
62954
        self.edges_configuration[start..end]
223
62954
            .iter()
224
62954
            .zip(self.game.edges_to()[start..end].iter())
225
124664
            .map(|(configuration, &to)| Edge::new(configuration, to))
226
62954
    }
227

            
228
    delegate! {
229
        to self.game {
230
1324
            fn initial_vertex(&self) -> VertexIndex;
231
5280
            fn num_of_vertices(&self) -> usize;
232
902
            fn num_of_edges(&self) -> usize;
233
2941
            fn iter_vertices(&self) -> impl Iterator<Item = VertexIndex> + '_;
234
37620
            fn owner(&self, vertex: VertexIndex) -> Player;
235
33551
            fn priority(&self, vertex: VertexIndex) -> Priority;
236
            fn is_total(&self) -> bool;
237
            fn highest_priority(&self) -> Priority;
238
        }
239
    }
240
}
241

            
242
impl fmt::Display for VariabilityParityGame {
243
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244
        writeln!(f, "Variability Parity Game:")?;
245
        writeln!(f, "Configuration BDD: {}", FormatConfigSet(self.configuration()))?;
246

            
247
        for v in self.iter_vertices() {
248
            write!(
249
                f,
250
                "v{}: {:?}, priority={}, edges=[",
251
                v,
252
                self.owner(v).to_index(),
253
                self.priority(v)
254
            )?;
255

            
256
            let mut first = true;
257
            for edge in self.outgoing_edges(v) {
258
                if !first {
259
                    write!(f, ", ")?;
260
                }
261
                write!(f, "(v{}, {})", edge.to(), FormatConfigSet(edge.label()))?;
262
                first = false;
263
            }
264

            
265
            writeln!(f, "]")?;
266
        }
267

            
268
        Ok(())
269
    }
270
}