1
use merc_lts::LTS;
2
use merc_lts::StateIndex;
3
use merc_reduction::diverges;
4

            
5
use crate::CounterExampleConstructor;
6
use crate::CounterExampleTree;
7
use crate::ExplorationStrategy;
8
use crate::is_refinement_generic;
9
use crate::is_stable;
10

            
11
/// Checks for the impossible futures refinement between the initial state of
12
/// the `lts` and the `initial_spec` state.
13
///
14
/// # Details
15
///
16
/// Impossible futures are defined in the following article:
17
///
18
/// > Marc Voorhoeve, Sjouke Mauw. Impossible futures and determinism, Inf. Process. Lett. 80, 2001.
19
133
pub fn is_impossible_futures_refinement<L: LTS, CE: CounterExampleTree>(
20
133
    lts: &L,
21
133
    initial_spec: StateIndex,
22
133
    strategy: ExplorationStrategy,
23
133
    counter_example: &mut CE,
24
133
) -> (bool, Option<CE::Index>, Option<Vec<Vec<L::Label>>>) {
25
133
    is_refinement_generic(
26
133
        strategy,
27
133
        lts,
28
133
        lts.initial_state_index(),
29
133
        initial_spec,
30
484
        |impl_state, spec_states| {
31
484
            if !is_stable(lts, impl_state) {
32
                // We can skip unstable states as an optimisation.
33
93
                debug_assert!(!diverges(lts, impl_state), "Implementation states should not diverge.");
34
93
                return None;
35
391
            }
36

            
37
            // Observe that the weak trace inclusion is inverted, this exactly
38
            // corresponds to checking for impossible futures.
39
391
            if !spec_states
40
391
                .iter()
41
431
                .any(|t| is_weak_trace_refinement(lts, *t, impl_state, strategy, &mut ()).0)
42
            {
43
44
                let mut futures = Vec::new();
44

            
45
55
                for t in spec_states {
46
                    // Run the weak trace refinement again with a counter example.
47
55
                    let mut ce_constructor = CounterExampleConstructor::new();
48

            
49
55
                    let (result, ce) = is_weak_trace_refinement(lts, *t, impl_state, strategy, &mut ce_constructor);
50
55
                    debug_assert!(
51
55
                        !result,
52
                        "The weak trace refinement should fail according to the previous check."
53
                    );
54

            
55
55
                    let trace = ce_constructor
56
55
                        .reconstruct_trace(ce.expect("A counter example was requested"))
57
55
                        .iter()
58
172
                        .map(|l| lts.labels()[*l].clone())
59
55
                        .collect();
60

            
61
55
                    futures.push(trace);
62
                }
63

            
64
44
                return Some(futures);
65
347
            }
66

            
67
347
            None
68
484
        },
69
        true,
70
133
        counter_example,
71
    )
72
133
}
73

            
74
/// Checks for the various weak trace refinement. This is a helper function for
75
/// the impossible futures refinement check.
76
486
fn is_weak_trace_refinement<L: LTS, CE: CounterExampleTree>(
77
486
    lts: &L,
78
486
    impl_state: StateIndex,
79
486
    spec_state: StateIndex,
80
486
    strategy: ExplorationStrategy,
81
486
    counter_example: &mut CE,
82
486
) -> (bool, Option<CE::Index>) {
83
486
    let (result, counter_example, inner_ce) = is_refinement_generic(
84
486
        strategy,
85
486
        lts,
86
486
        impl_state,
87
486
        spec_state,
88
        |_, _| Option::<()>::None,
89
        true,
90
486
        counter_example,
91
    );
92

            
93
486
    debug_assert!(inner_ce.is_none(), "The counter example from check is trivial");
94

            
95
486
    (result, counter_example)
96
486
}