1
use std::fmt;
2

            
3
use merc_data::DataExpression;
4
use merc_data::DataSpecification;
5
use merc_data::DataVariable;
6
use merc_ldd::Ldd;
7
use merc_ldd::Storage;
8
use merc_ldd::Value;
9
use merc_ldd::compute_meta;
10
use merc_lts::LtsMultiAction;
11
use merc_utilities::MercError;
12

            
13
use crate::SymbolicLTS;
14
use crate::TransitionGroup;
15

            
16
/// Represents a symbolic LTS encoded by a disjunctive transition relation and a set of states.
17
pub struct SymbolicLts {
18
    data_specification: DataSpecification,
19
    states: Ldd,
20

            
21
    /// A singleton LDD representing the initial state.
22
    initial_state: Ldd,
23
    summand_groups: Vec<SummandGroup>,
24

            
25
    /// The action labels of the LTS, stored as their string representation,
26
    /// their position corresponds to the LDD values.
27
    action_labels: Vec<String>,
28

            
29
    /// The possible values for each process parameter, their position
30
    /// corresponds to the LDD values.
31
    parameter_values: Vec<Vec<DataExpression>>,
32
}
33

            
34
impl SymbolicLts {
35
    /// Creates a new symbolic LTS.
36
    ///
37
    /// `parameter_values` contains, for each process parameter, the list of
38
    /// possible values it can take. Their indices correspond to the values stored
39
    /// in the LDDs.
40
303
    pub fn new(
41
303
        data_specification: DataSpecification,
42
303
        states: Ldd,
43
303
        initial_state: Ldd,
44
303
        summand_groups: Vec<SummandGroup>,
45
303
        action_labels: Vec<LtsMultiAction>,
46
303
        parameter_values: Vec<Vec<DataExpression>>,
47
303
    ) -> Self {
48
303
        let action_labels = action_labels
49
303
            .into_iter()
50
1741
            .map(|aterm| format!("{}", aterm))
51
303
            .collect::<Vec<String>>();
52

            
53
303
        Self {
54
303
            data_specification,
55
303
            states,
56
303
            initial_state,
57
303
            summand_groups,
58
303
            action_labels,
59
303
            parameter_values,
60
303
        }
61
303
    }
62

            
63
    /// Returns the data specification of the LTS.
64
    pub fn data_specification(&self) -> &DataSpecification {
65
        &self.data_specification
66
    }
67

            
68
    /// Returns the parameter values of the LTS.
69
    pub fn parameter_values(&self) -> &Vec<Vec<DataExpression>> {
70
        &self.parameter_values
71
    }
72
}
73

            
74
impl SymbolicLTS for SymbolicLts {
75
806
    fn states(&self) -> &Ldd {
76
806
        &self.states
77
806
    }
78

            
79
602
    fn initial_state(&self) -> &Ldd {
80
602
        &self.initial_state
81
602
    }
82

            
83
1260
    fn transition_groups(&self) -> &[impl TransitionGroup] {
84
1260
        &self.summand_groups
85
1260
    }
86

            
87
493
    fn action_labels(&self) -> &[String] {
88
493
        &self.action_labels
89
493
    }
90

            
91
401
    fn parameter_values(&self) -> &[Vec<DataExpression>] {
92
401
        &self.parameter_values
93
401
    }
94
}
95

            
96
/// Represents a short vector transition relation for a group of summands.
97
///
98
/// # Details
99
///
100
/// A short transition vector is part of a transition relation T -> U, where we
101
/// store T' -> U' with T' being the projection of T on the read parameters and
102
/// U' the projection of U on the write parameters, as a LDD. Formally,
103
///
104
/// (t, u) in (T -> U)  iff  (t', u') in (T' -> U') where t' and u' are the projections
105
///     of t and u on the read and write parameters respectively.
106
pub struct SummandGroup {
107
    /// The read parameters for this summand group.
108
    read_parameters: Vec<DataVariable>,
109
    read_parameter_indices: Vec<Value>,
110

            
111
    /// The write parameters for this summand group.
112
    write_parameters: Vec<DataVariable>,
113
    write_parameter_indices: Vec<Value>,
114

            
115
    /// The transition relation T' -> U' for this summand group.
116
    relation: Ldd,
117

            
118
    /// The meta information for this summand group.
119
    meta: Ldd,
120

            
121
    /// The action label index for this summand group.
122
    action_label_index: usize,
123
}
124

            
125
impl TransitionGroup for SummandGroup {
126
6665
    fn relation(&self) -> &Ldd {
127
6665
        &self.relation
128
6665
    }
129

            
130
1905
    fn meta(&self) -> &Ldd {
131
1905
        &self.meta
132
1905
    }
133

            
134
23359
    fn read_indices(&self) -> &[u32] {
135
23359
        &self.read_parameter_indices
136
23359
    }
137

            
138
20347
    fn write_indices(&self) -> &[u32] {
139
20347
        &self.write_parameter_indices
140
20347
    }
141

            
142
4122
    fn action_label_index(&self) -> Option<usize> {
143
4122
        Some(self.action_label_index)
144
4122
    }
145
}
146

            
147
impl SummandGroup {
148
    /// Creates a new summand group.
149
    ///
150
    /// This can fail if one of the read or write parameters is not in the list of all parameters.
151
1621
    pub fn new(
152
1621
        storage: &mut Storage,
153
1621
        parameters: &[DataVariable],
154
1621
        read_parameters: Vec<DataVariable>,
155
1621
        write_parameters: Vec<DataVariable>,
156
1621
        relation: Ldd,
157
1621
    ) -> Result<Self, MercError> {
158
        // Find the position of every variable in the parameter list.
159
1621
        let read_parameter_indices: Vec<Value> = read_parameters
160
1621
            .iter()
161
6927
            .map(|var| {
162
6927
                parameters
163
6927
                    .iter()
164
40568
                    .position(|p| p == var)
165
6927
                    .ok_or(format!("Cannot find read parameter {var:?}"))
166
6927
                    .map(|pos| pos as Value)
167
6927
            })
168
1621
            .collect::<Result<Vec<Value>, _>>()?;
169

            
170
1621
        let write_parameter_indices: Vec<Value> = write_parameters
171
1621
            .iter()
172
7083
            .map(|var| {
173
7083
                parameters
174
7083
                    .iter()
175
42268
                    .position(|p| p == var)
176
7083
                    .ok_or(format!("Cannot find write parameter {var:?}"))
177
7083
                    .map(|pos| pos as Value)
178
7083
            })
179
1621
            .collect::<Result<Vec<Value>, _>>()?;
180

            
181
1621
        let meta = compute_meta(storage, &read_parameter_indices, &write_parameter_indices);
182
1621
        let action_label_index = read_parameters.len() + write_parameters.len(); // The action label is the last index
183

            
184
1621
        Ok(Self {
185
1621
            read_parameters,
186
1621
            read_parameter_indices,
187
1621
            write_parameters,
188
1621
            write_parameter_indices,
189
1621
            relation,
190
1621
            meta,
191
1621
            action_label_index,
192
1621
        })
193
1621
    }
194

            
195
    /// Returns the transition relation LDD for this summand group.
196
    pub fn relation(&self) -> &Ldd {
197
        &self.relation
198
    }
199

            
200
    /// Returns the read parameters for this summand group.
201
    pub fn read_parameters(&self) -> &[DataVariable] {
202
        &self.read_parameters
203
    }
204

            
205
    /// Returns the write parameters for this summand group.
206
    pub fn write_parameters(&self) -> &[DataVariable] {
207
        &self.write_parameters
208
    }
209
}
210

            
211
impl fmt::Debug for SummandGroup {
212
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213
        write!(
214
            f,
215
            "{:?} -> {:?}",
216
            self.read_parameter_indices, self.write_parameter_indices
217
        )
218
    }
219
}