1use serde::{Deserialize, Serialize};
4
5use itertools::Itertools;
6
7use super::model;
8use super::time;
9
10mod actions;
11mod compiled;
12mod evaluate;
13
14pub mod external;
15
16use compiled::*;
17
18pub use actions::*;
19
20#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
26pub struct State<V> {
27 locations: Box<[LocationIndex]>,
28 global_store: Box<[model::Value]>,
29 transient_store: Box<[model::Value]>,
30 valuations: V,
31}
32
33impl<V> State<V> {
34 pub fn get_location_of<'e, T: time::TimeType>(
39 &self,
40 explorer: &'e Explorer<T>,
41 automaton_name: &str,
42 ) -> &'e String {
43 explorer
44 .network
45 .automata
46 .get_index_of(automaton_name)
47 .and_then(|automaton_index| {
48 self.locations
49 .get(automaton_index)
50 .and_then(|location_index| {
51 let (_, automaton) = explorer
52 .network
53 .automata
54 .get_index(automaton_index)
55 .unwrap();
56 automaton
57 .locations
58 .get_index(*location_index)
59 .map(|(location_name, _)| location_name)
60 })
61 })
62 .expect("Invalid automaton name or explorer passed to `State::get_location_of`.")
63 }
64
65 pub fn get_global_value<T: time::TimeType>(
70 &self,
71 explorer: &Explorer<T>,
72 identifier: &str,
73 ) -> &model::Value {
74 explorer
75 .network
76 .declarations
77 .global_variables
78 .get_index_of(identifier)
79 .and_then(|index| self.global_store.get(index))
80 .expect("Invalid variable name or explorer passed to `State::get_global_value`.")
81 }
82
83 pub fn get_transient_value(&self, network: &model::Network, identifier: &str) -> &model::Value {
88 network
89 .declarations
90 .transient_variables
91 .get_index_of(identifier)
92 .and_then(|index| self.transient_store.get(index))
93 .expect("Invalid variable name or explorer passed to `State::get_transient_value`.")
94 }
95
96 pub fn valuations(&self) -> &V {
98 &self.valuations
99 }
100
101 fn global_env(&self) -> GlobalEnvironment {
103 evaluate::Environment::new([&self.global_store, &self.transient_store])
104 }
105
106 fn edge_env<'e, 's: 'e>(&'s self, edge_store: &'e [model::Value]) -> EdgeEnvironment<'e> {
108 evaluate::Environment::new([&self.global_store, &self.transient_store, edge_store])
109 }
110
111 fn future<T: time::TimeType>(
112 state: State<T::Valuations>,
113 compiled_network: &CompiledNetwork<T>,
114 ) -> State<T::Valuations> {
115 let env = evaluate::Environment::new([&state.global_store, &state.transient_store]);
116
117 let mut valuations = compiled_network.zone_compiler.future(state.valuations);
118
119 for (automaton_index, location_index) in state.locations.iter().enumerate() {
120 let location = &compiled_network.automata[automaton_index].locations[*location_index];
121 valuations = location
122 .invariant
123 .iter()
124 .fold(valuations, |valuations, constraint| {
125 compiled_network.zone_compiler.constrain(
126 valuations,
127 &constraint.difference,
128 constraint.is_strict,
129 constraint.bound.evaluate(&env),
130 )
131 })
132 }
133
134 State {
135 locations: state.locations,
136 global_store: state.global_store,
137 transient_store: state.transient_store,
138 valuations: valuations,
139 }
140 }
141}
142
143pub struct Transition<'e, T: time::TimeType> {
145 pub(crate) edges: Box<[&'e CompiledEdge<T>]>,
146 pub(crate) actions: Box<[Action]>,
147 pub(crate) valuations: T::Valuations,
148 pub(crate) action: Action,
149}
150
151impl<'e, T: time::TimeType> Transition<'e, T> {
152 pub fn local_actions(&self) -> &[Action] {
154 &self.actions
155 }
156
157 pub fn edges(&self) -> Vec<model::EdgeReference> {
159 self.edges
160 .iter()
161 .map(|edge| edge.reference.clone())
162 .collect()
163 }
164
165 pub fn valuations(&self) -> &T::Valuations {
167 &self.valuations
168 }
169
170 pub fn result_action(&self) -> &Action {
172 &self.action
173 }
174
175 pub fn replace_valuations(self, valuations: T::Valuations) -> Self {
177 Transition {
178 edges: self.edges,
179 actions: self.actions,
180 valuations,
181 action: self.action,
182 }
183 }
184
185 pub fn edge_references(&self) -> Vec<model::EdgeReference> {
186 self.edges
187 .iter()
188 .map(|edge| edge.reference.clone())
189 .collect()
190 }
191}
192
193pub struct Destination<'c, T: time::TimeType> {
195 pub(crate) probability: f64,
196 pub(crate) destinations: Box<[&'c CompiledDestination<T>]>,
197}
198
199impl<'c, T: time::TimeType> Destination<'c, T> {
200 pub fn probability(&self) -> f64 {
202 self.probability
203 }
204}
205
206pub struct Explorer<T: time::TimeType> {
208 pub network: model::Network,
209 pub(crate) compiled_network: CompiledNetwork<T>,
210}
211
212impl<T: time::TimeType> Explorer<T> {
213 pub fn new(network: model::Network) -> Self {
215 let compiled = CompiledNetwork::new(&network);
216 Explorer {
217 network,
218 compiled_network: compiled,
219 }
220 }
221
222 pub fn initial_states(&self) -> Vec<State<T::Valuations>> {
224 let global_scope = self.network.global_scope();
225 self.network
226 .initial_states
227 .iter()
228 .map(|state| {
229 let locations = self
230 .network
231 .automata
232 .iter()
233 .map(|(automaton_name, automaton)| {
234 automaton
235 .locations
236 .get_index_of(&state.locations[automaton_name])
237 .unwrap()
238 })
239 .collect();
240 let global_store: Box<[model::Value]> = self
241 .network
242 .declarations
243 .global_variables
244 .keys()
245 .map(|identifier| state.values[identifier].clone())
246 .collect();
247 let transient_store = self
248 .compiled_network
249 .compute_transient_values(&global_store);
250 let global_env = evaluate::Environment::new([&global_store, &transient_store]);
251 let valuations = self
253 .compiled_network
254 .zone_compiler
255 .create_valuations(
256 state
257 .zone
258 .iter()
259 .map(|constraint| {
260 CompiledClockConstraint::compile(
261 &self.compiled_network.zone_compiler,
262 constraint,
263 &global_scope,
264 )
265 .evaluate(&global_env)
266 })
267 .collect(),
268 )
269 .unwrap();
270 State::<T::Valuations>::future(
271 State {
272 locations,
273 global_store,
274 transient_store,
275 valuations,
276 },
277 &self.compiled_network,
278 )
279 })
280 .collect()
281 }
282
283 pub fn transitions<'c>(&'c self, state: &State<T::Valuations>) -> Vec<Transition<'c, T>> {
285 let global_env = state.global_env();
286 let enabled_edges = self
287 .compiled_network
288 .automata
289 .iter()
290 .zip(state.locations.iter())
291 .map(|(automaton, location_index)| {
292 automaton.locations[*location_index]
293 .visible_edges
294 .iter()
295 .map(|link_edges| {
296 link_edges
297 .iter()
298 .filter(|edge| edge.base.is_enabled(&global_env))
299 .collect()
300 })
301 .collect()
302 })
303 .collect();
304 self.compiled_network
305 .automata
306 .iter()
307 .enumerate()
308 .map(|(index, automaton)| {
309 let location = &automaton.locations[state.locations[index]];
310 location.internal_edges.iter().filter_map(|edge| {
311 if !edge.is_enabled(&global_env) {
312 None
313 } else {
314 let valuations = edge.guard.clock_constraints.iter().fold(
319 state.valuations.clone(),
320 |valuations, constraint| {
321 self.compiled_network.zone_compiler.constrain(
322 valuations,
323 &constraint.difference,
324 constraint.is_strict,
325 constraint.bound.evaluate(&global_env),
326 )
327 },
328 );
329 if self.compiled_network.zone_compiler.is_empty(&valuations) {
330 None
331 } else {
332 Some(Transition {
333 edges: Box::new([edge]),
334 actions: Box::new([Action::Silent]),
335 valuations,
336 action: Action::Silent,
337 })
338 }
339 }
340 })
341 })
342 .flatten()
343 .chain(
344 self.compiled_network
345 .links
346 .iter()
347 .map(|link| {
348 link.sync_vector
349 .iter()
350 .map(|vector_item| {
351 vector_item.compute_link_edges(&global_env, &enabled_edges)
352 })
353 .collect::<Vec<_>>()
354 .iter()
355 .multi_cartesian_product()
356 .filter_map(|edges| {
357 self.compiled_network.compute_transition(
358 &state.valuations,
359 &global_env,
360 link,
361 &edges,
362 )
363 })
364 .collect::<Vec<_>>()
365 })
366 .flatten(),
367 )
368 .collect()
369 }
370
371 pub fn destinations<'c>(
375 &'c self,
376 state: &State<T::Valuations>,
377 transition: &Transition<'c, T>,
378 ) -> Vec<Destination<'c, T>> {
379 transition
380 .edges
381 .iter()
382 .map(|edge| edge.destinations.iter())
383 .multi_cartesian_product()
384 .map(|destinations| Destination {
385 probability: transition.actions.iter().zip(destinations.iter()).fold(
386 1.0,
387 |probability, (action, destination)| {
388 let edge_env = state.edge_env(action.arguments());
389 probability
390 * destination
391 .probability
392 .evaluate(&edge_env)
393 .unwrap_float64()
394 .into_inner()
395 },
396 ),
397 destinations: destinations.into(),
398 })
399 .collect()
400 }
401
402 pub fn successor<'c>(
406 &'c self,
407 state: &State<T::Valuations>,
408 transition: &Transition<'c, T>,
409 destination: &Destination<T>,
410 ) -> State<T::Valuations> {
411 let mut targets = vec![
412 model::Value::Vector(state.global_store.clone().into()),
413 model::Value::Vector(state.transient_store.clone().into()),
414 ];
415 for index in 0..self.compiled_network.assignment_groups.len() {
416 let global_store = targets[0].clone();
417 for (action, automaton_destination) in transition
418 .actions
419 .iter()
420 .zip(destination.destinations.iter())
421 {
422 let env = EdgeEnvironment::new([
423 &global_store.unwrap_vector(),
424 &state.transient_store,
425 action.arguments(),
426 ]);
427 for assignment in automaton_destination.assignments[index].iter() {
428 let value = assignment.value.evaluate(&env);
429 assignment.target.evaluate(&mut targets, &env).store(value);
430 }
431 }
432 }
433
434 let mut locations = state.locations.clone();
435 let mut valuations = transition.valuations().clone();
436 for automaton_destination in destination.destinations.iter() {
437 let automaton_index = automaton_destination.automaton_index;
438 locations[automaton_index] = automaton_destination.location;
439 valuations = self
440 .compiled_network
441 .zone_compiler
442 .reset(valuations, &automaton_destination.reset);
443 }
444
445 let transient_store = self
446 .compiled_network
447 .compute_transient_values(&targets[0].unwrap_vector());
448
449 let state = State::<T::Valuations>::future(
450 State {
451 locations,
452 global_store: targets[0].unwrap_vector().clone().into(),
453 transient_store,
454 valuations,
455 },
456 &self.compiled_network,
457 );
458
459 assert!(!self
461 .compiled_network
462 .zone_compiler
463 .is_empty(&state.valuations));
464
465 state
466 }
467
468 pub fn externalize_transition(&self, transition: &Transition<T>) -> external::Transition<T> {
469 external::Transition {
470 edge_vector: transition
471 .edges
472 .iter()
473 .map(|edge| edge.reference.clone())
474 .collect(),
475 action_vector: transition.actions.clone(),
476 action: transition.action.clone(),
477 valuations: self
478 .compiled_network
479 .zone_compiler
480 .externalize(transition.valuations.clone()),
481 }
482 }
483}
484
485pub type MDPExplorer = Explorer<time::NoClocks>;