1use std::collections::HashSet;
4
5use num_traits::cast::FromPrimitive;
6
7use indexmap::IndexSet;
8
9use serde::{Deserialize, Serialize};
10
11use clock_zones;
12use clock_zones::Zone;
13
14use crate::Explorer;
15
16use super::model;
17
18#[derive(Eq, PartialEq, Hash, Clone, Debug)]
19pub struct Constraint<T: TimeType> {
20 pub(crate) difference: T::CompiledDifference,
21 pub(crate) is_strict: bool,
22 pub(crate) bound: model::Value,
23}
24
25pub trait TimeType: Sized {
27 type Valuations: Eq + PartialEq + std::hash::Hash + Clone;
29
30 type External: Eq + PartialEq + std::hash::Hash + Clone;
32
33 type CompiledDifference: Clone;
35
36 type CompiledClocks: Clone;
38
39 fn new(network: &model::Network) -> Result<Self, String>;
41
42 fn compile_difference(
44 &self,
45 left: &model::Clock,
46 right: &model::Clock,
47 ) -> Self::CompiledDifference;
48
49 fn compile_clocks(&self, clocks: &HashSet<model::Clock>) -> Self::CompiledClocks;
51
52 fn is_empty(&self, valuations: &Self::Valuations) -> bool;
54
55 fn create_valuations(
57 &self,
58 constraints: Vec<Constraint<Self>>,
59 ) -> Result<Self::Valuations, String>;
60
61 fn constrain(
63 &self,
64 valuations: Self::Valuations,
65 difference: &Self::CompiledDifference,
66 is_strict: bool,
67 bound: model::Value,
68 ) -> Self::Valuations;
69
70 fn reset(
72 &self,
73 valuations: Self::Valuations,
74 clocks: &Self::CompiledClocks,
75 ) -> Self::Valuations;
76
77 fn future(&self, valuations: Self::Valuations) -> Self::Valuations;
79
80 fn externalize(&self, valuations: Self::Valuations) -> Self::External;
81}
82
83#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Clone, Debug)]
85pub struct NoClocks();
86
87impl TimeType for NoClocks {
88 type Valuations = ();
89
90 type External = ();
91
92 type CompiledDifference = ();
93
94 type CompiledClocks = ();
95
96 fn new(network: &model::Network) -> Result<Self, String> {
97 if network.declarations.clock_variables.len() > 0 {
98 Err("time type `NoClocks` does not allow any clocks".to_string())
99 } else {
100 Ok(NoClocks())
101 }
102 }
103
104 fn compile_difference(
105 &self,
106 _left: &model::Clock,
107 _right: &model::Clock,
108 ) -> Self::CompiledDifference {
109 panic!("time type `NoClocks` does not allow any clocks")
110 }
111
112 fn compile_clocks(&self, clocks: &HashSet<model::Clock>) -> Self::CompiledClocks {
113 if clocks.len() > 0 {
114 panic!("time type `NoClocks` does not allow any clocks")
115 }
116 }
117
118 fn is_empty(&self, _valuations: &Self::Valuations) -> bool {
119 false
120 }
121
122 fn create_valuations(
123 &self,
124 constraints: Vec<Constraint<Self>>,
125 ) -> Result<Self::Valuations, String> {
126 if constraints.len() > 0 {
127 Err("time type `NoClocks` does not allow any clocks".to_string())
128 } else {
129 Ok(())
130 }
131 }
132
133 fn constrain(
134 &self,
135 _valuations: Self::Valuations,
136 _difference: &Self::CompiledDifference,
137 _is_strict: bool,
138 _bound: model::Value,
139 ) -> Self::Valuations {
140 panic!("time type `NoClocks` does not allow any clocks")
141 }
142
143 fn reset(
144 &self,
145 _valuations: Self::Valuations,
146 _clocks: &Self::CompiledClocks,
147 ) -> Self::Valuations {
148 ()
149 }
150
151 fn future(&self, _valuations: Self::Valuations) -> Self::Valuations {
152 ()
153 }
154
155 fn externalize(&self, valuations: Self::Valuations) -> Self::External {
156 valuations
157 }
158}
159
160#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)]
162pub struct Float64Zone {
163 clock_variables: IndexSet<String>,
164}
165
166impl Float64Zone {
167 fn clock_to_index(&self, clock: &model::Clock) -> usize {
168 match clock {
169 model::Clock::Zero => 0,
170 model::Clock::Variable { identifier } => {
171 self.clock_variables.get_index_of(identifier).unwrap() + 1
172 }
173 }
174 }
175
176 fn apply_constraint(
177 &self,
178 zone: &mut <Self as TimeType>::Valuations,
179 constraint: Constraint<Self>,
180 ) {
181 let bound = match constraint.bound {
182 model::Value::Int64(value) => ordered_float::NotNan::from_i64(value).unwrap(),
183 model::Value::Float64(value) => value,
184 _ => panic!("unable to convert {:?} to clock bound", constraint.bound),
185 };
186 if constraint.is_strict {
187 zone.add_constraint(clock_zones::Constraint::new_diff_lt(
188 constraint.difference.0,
189 constraint.difference.1,
190 bound,
191 ));
192 } else {
193 zone.add_constraint(clock_zones::Constraint::new_diff_le(
194 constraint.difference.0,
195 constraint.difference.1,
196 bound,
197 ));
198 }
199 }
200}
201
202impl TimeType for Float64Zone {
203 type Valuations = clock_zones::DBM<clock_zones::ConstantBound<ordered_float::NotNan<f64>>>;
204
205 type External = Self::Valuations;
206
207 type CompiledDifference = (usize, usize);
208
209 type CompiledClocks = Vec<usize>;
210
211 fn new(network: &model::Network) -> Result<Self, String> {
212 Ok(Float64Zone {
213 clock_variables: network.declarations.clock_variables.clone(),
214 })
215 }
216
217 fn compile_difference(
218 &self,
219 left: &model::Clock,
220 right: &model::Clock,
221 ) -> Self::CompiledDifference {
222 (self.clock_to_index(left), self.clock_to_index(right))
223 }
224
225 fn compile_clocks(&self, clocks: &HashSet<model::Clock>) -> Self::CompiledClocks {
226 clocks
227 .iter()
228 .map(|clock| self.clock_to_index(clock))
229 .collect()
230 }
231
232 fn is_empty(&self, valuations: &Self::Valuations) -> bool {
233 valuations.is_empty()
234 }
235
236 fn create_valuations(
237 &self,
238 constraints: Vec<Constraint<Self>>,
239 ) -> Result<Self::Valuations, String> {
240 let mut valuations = Self::Valuations::new_unconstrained(self.clock_variables.len());
241 for constraint in constraints {
242 self.apply_constraint(&mut valuations, constraint);
243 }
244 Ok(valuations)
245 }
246
247 fn constrain(
248 &self,
249 mut valuations: Self::Valuations,
250 difference: &Self::CompiledDifference,
251 is_strict: bool,
252 bound: model::Value,
253 ) -> Self::Valuations {
254 self.apply_constraint(
255 &mut valuations,
256 Constraint {
257 difference: difference.clone(),
258 is_strict,
259 bound,
260 },
261 );
262 valuations
263 }
264
265 fn reset(
266 &self,
267 mut valuations: Self::Valuations,
268 clocks: &Self::CompiledClocks,
269 ) -> Self::Valuations {
270 for clock in clocks {
271 valuations.reset(*clock, ordered_float::NotNan::new(0.0).unwrap());
272 }
273 valuations
274 }
275
276 fn future(&self, mut valuations: Self::Valuations) -> Self::Valuations {
278 valuations.future();
279 valuations
280 }
281
282 fn externalize(&self, valuations: Self::Valuations) -> Self::External {
283 valuations
284 }
285}
286
287#[derive(Serialize, Deserialize, Eq, PartialEq, Clone, Debug)]
289pub struct GlobalTime {
290 clock_variables: IndexSet<String>,
291 global_clock: usize,
292}
293
294impl GlobalTime {
295 fn clock_to_index(&self, clock: &model::Clock) -> usize {
296 match clock {
297 model::Clock::Zero => 0,
298 model::Clock::Variable { identifier } => {
299 self.clock_variables.get_index_of(identifier).unwrap() + 1
300 }
301 }
302 }
303
304 fn apply_constraint(
305 &self,
306 valuations: &mut <Self as TimeType>::Valuations,
307 constraint: Constraint<Self>,
308 ) {
309 let bound = match constraint.bound {
310 model::Value::Int64(value) => ordered_float::NotNan::from_i64(value).unwrap(),
311 model::Value::Float64(value) => value,
312 _ => panic!("unable to convert {:?} to clock bound", constraint.bound),
313 };
314 if constraint.is_strict {
315 valuations
316 .zone
317 .add_constraint(clock_zones::Constraint::new_diff_lt(
318 constraint.difference.0,
319 constraint.difference.1,
320 bound,
321 ));
322 } else {
323 valuations
324 .zone
325 .add_constraint(clock_zones::Constraint::new_diff_le(
326 constraint.difference.0,
327 constraint.difference.1,
328 bound,
329 ));
330 }
331 }
332}
333#[derive(Eq, PartialEq, Hash, Clone, Debug)]
334pub struct GlobalValuations {
335 zone: clock_zones::DBM<clock_zones::ConstantBound<ordered_float::NotNan<f64>>>,
336 global_clock: usize,
337}
338
339impl GlobalValuations {
340 fn new_unconstrained(num_clocks: usize) -> Self {
341 GlobalValuations {
342 zone: clock_zones::DBM::new_unconstrained(num_clocks),
343 global_clock: num_clocks,
344 }
345 }
346
347 pub fn global_time_lower_bound(&self) -> Option<ordered_float::NotNan<f64>> {
348 self.zone.get_lower_bound(self.global_clock)
349 }
350
351 pub fn global_time_upper_bound(&self) -> Option<ordered_float::NotNan<f64>> {
352 self.zone.get_upper_bound(self.global_clock)
353 }
354
355 pub fn set_global_time(&mut self, value: ordered_float::NotNan<f64>) {
356 self.zone
357 .add_constraint(clock_zones::Constraint::new_le(self.global_clock, value));
358 self.zone
359 .add_constraint(clock_zones::Constraint::new_ge(self.global_clock, value));
360 }
361}
362
363impl TimeType for GlobalTime {
364 type Valuations = GlobalValuations;
365
366 type External = Self::Valuations;
367
368 type CompiledDifference = (usize, usize);
369
370 type CompiledClocks = Vec<usize>;
371
372 fn new(network: &model::Network) -> Result<Self, String> {
373 Ok(GlobalTime {
374 clock_variables: network.declarations.clock_variables.clone(),
375 global_clock: network.declarations.clock_variables.len() + 1,
376 })
377 }
378
379 fn compile_difference(
380 &self,
381 left: &model::Clock,
382 right: &model::Clock,
383 ) -> Self::CompiledDifference {
384 (self.clock_to_index(left), self.clock_to_index(right))
385 }
386
387 fn compile_clocks(&self, clocks: &HashSet<model::Clock>) -> Self::CompiledClocks {
388 clocks
389 .iter()
390 .map(|clock| self.clock_to_index(clock))
391 .collect()
392 }
393
394 fn is_empty(&self, valuations: &Self::Valuations) -> bool {
395 valuations.zone.is_empty()
396 }
397
398 fn create_valuations(
399 &self,
400 constraints: Vec<Constraint<Self>>,
401 ) -> Result<Self::Valuations, String> {
402 let mut valuations = Self::Valuations::new_unconstrained(self.clock_variables.len() + 1);
403 for constraint in constraints {
404 self.apply_constraint(&mut valuations, constraint);
405 }
406 valuations
407 .zone
408 .reset(self.global_clock, ordered_float::NotNan::new(0.0).unwrap());
409 Ok(valuations)
410 }
411
412 fn constrain(
413 &self,
414 mut valuations: Self::Valuations,
415 difference: &Self::CompiledDifference,
416 is_strict: bool,
417 bound: model::Value,
418 ) -> Self::Valuations {
419 self.apply_constraint(
420 &mut valuations,
421 Constraint {
422 difference: difference.clone(),
423 is_strict,
424 bound,
425 },
426 );
427 valuations
428 }
429
430 fn reset(
431 &self,
432 mut valuations: Self::Valuations,
433 clocks: &Self::CompiledClocks,
434 ) -> Self::Valuations {
435 for clock in clocks {
436 valuations
437 .zone
438 .reset(*clock, ordered_float::NotNan::new(0.0).unwrap());
439 }
440 valuations
441 }
442
443 fn future(&self, mut valuations: Self::Valuations) -> Self::Valuations {
445 valuations.zone.future();
446 valuations
447 }
448
449 fn externalize(&self, valuations: Self::Valuations) -> Self::External {
450 valuations
451 }
452}