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
203
    pub fn new(
41
203
        data_specification: DataSpecification,
42
203
        states: Ldd,
43
203
        initial_state: Ldd,
44
203
        summand_groups: Vec<SummandGroup>,
45
203
        action_labels: Vec<LtsMultiAction>,
46
203
        parameter_values: Vec<Vec<DataExpression>>,
47
203
    ) -> Self {
48
203
        let action_labels = action_labels
49
203
            .into_iter()
50
1241
            .map(|aterm| format!("{}", aterm))
51
203
            .collect::<Vec<String>>();
52

            
53
203
        Self {
54
203
            data_specification,
55
203
            states,
56
203
            initial_state,
57
203
            summand_groups,
58
203
            action_labels,
59
203
            parameter_values,
60
203
        }
61
203
    }
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
406
    fn states(&self) -> &Ldd {
76
406
        &self.states
77
406
    }
78

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

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

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

            
91
201
    fn parameter_values(&self) -> &[Vec<DataExpression>] {
92
201
        &self.parameter_values
93
201
    }
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
4415
    fn relation(&self) -> &Ldd {
127
4415
        &self.relation
128
4415
    }
129

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

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

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

            
142
2122
    fn action_label_index(&self) -> Option<usize> {
143
2122
        Some(self.action_label_index)
144
2122
    }
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
1121
    pub fn new(
152
1121
        storage: &mut Storage,
153
1121
        parameters: &[DataVariable],
154
1121
        read_parameters: Vec<DataVariable>,
155
1121
        write_parameters: Vec<DataVariable>,
156
1121
        relation: Ldd,
157
1121
    ) -> Result<Self, MercError> {
158
        // Find the position of every variable in the parameter list.
159
1121
        let read_parameter_indices: Vec<Value> = read_parameters
160
1121
            .iter()
161
4847
            .map(|var| {
162
4847
                parameters
163
4847
                    .iter()
164
29008
                    .position(|p| p == var)
165
4847
                    .ok_or(format!("Cannot find read parameter {var:?}"))
166
4847
                    .map(|pos| pos as Value)
167
4847
            })
168
1121
            .collect::<Result<Vec<Value>, _>>()?;
169

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

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

            
184
1121
        Ok(Self {
185
1121
            read_parameters,
186
1121
            read_parameter_indices,
187
1121
            write_parameters,
188
1121
            write_parameter_indices,
189
1121
            relation,
190
1121
            meta,
191
1121
            action_label_index,
192
1121
        })
193
1121
    }
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
}