Theory ASC_Sufficiency

theory ASC_Sufficiency
  imports ASC_Suite
begin

section ‹ Sufficiency of the test suite to test for reduction ›

text ‹
This section provides a proof that the test suite generated by the adaptive state counting algorithm
is sufficient to test for reduction.
›

subsection ‹ Properties of minimal sequences to failures extending the deterministic state cover ›

text ‹
The following two lemmata show that minimal sequences to failures extending the deterministic state
cover do not with their extending suffix visit any state twice or visit a state also reached by a
sequence in the chosen permutation of reactions to the deterministic state cover.
›

lemma minimal_sequence_to_failure_extending_implies_Rep_Pre :
  assumes "minimal_sequence_to_failure_extending V M1 M2 vs xs"
  and     "OFSM M1"
  and     "OFSM M2"
  and     "test_tools M2 M1 FAIL PM V Ω"
  and     "V''  N (vs@xs') M1 V"
  and     "prefix xs' xs"
  shows "¬ Rep_Pre M2 M1 vs xs'"
proof 
  assume "Rep_Pre M2 M1 vs xs'" 
  then obtain xs1 xs2 s1 s2 where  "prefix xs1 xs2"   
                                   "prefix xs2 xs'"
                                   "xs1  xs2"
                                   "io_targets M2 (initial M2) (vs @ xs1) = {s2}" 
                                   "io_targets M2 (initial M2) (vs @ xs2) = {s2}"
                                   "io_targets M1 (initial M1) (vs @ xs1) = {s1}"
                                   "io_targets M1 (initial M1) (vs @ xs2) = {s1}"
    by auto
  then have "s2  io_targets M2 (initial M2) (vs @ xs1)"
            "s2  io_targets M2 (initial M2) (vs @ xs2)"
            "s1  io_targets M1 (initial M1) (vs @ xs1)"
            "s1  io_targets M1 (initial M1) (vs @ xs2)"            
    by auto

  have "vs@xs1  L M1" 
    using io_target_implies_L[OF s1  io_targets M1 (initial M1) (vs @ xs1)] by assumption
  have "vs@xs2  L M1" 
    using io_target_implies_L[OF s1  io_targets M1 (initial M1) (vs @ xs2)] by assumption
  have "vs@xs1  L M2" 
    using io_target_implies_L[OF s2  io_targets M2 (initial M2) (vs @ xs1)] by assumption
  have "vs@xs2  L M2" 
    using io_target_implies_L[OF s2  io_targets M2 (initial M2) (vs @ xs2)] by assumption

  obtain tr1_1 where "path M1 (vs@xs1 || tr1_1) (initial M1)" 
                     "length tr1_1 = length (vs@xs1)" 
                     "target (vs@xs1 || tr1_1) (initial M1) = s1"
    using s1  io_targets M1 (initial M1) (vs @ xs1) by auto
  obtain tr1_2 where "path M1 (vs@xs2 || tr1_2) (initial M1)" 
                     "length tr1_2 = length (vs@xs2)" 
                     "target (vs@xs2 || tr1_2) (initial M1) = s1"
    using s1  io_targets M1 (initial M1) (vs @ xs2) by auto 
  obtain tr2_1 where "path M2 (vs@xs1 || tr2_1) (initial M2)" 
                     "length tr2_1 = length (vs@xs1)" 
                     "target (vs@xs1 || tr2_1) (initial M2) = s2"
    using s2  io_targets M2 (initial M2) (vs @ xs1) by auto
  obtain tr2_2 where "path M2 (vs@xs2 || tr2_2) (initial M2)"
                     "length tr2_2 = length (vs@xs2)"
                     "target (vs@xs2 || tr2_2) (initial M2) = s2"
    using s2  io_targets M2 (initial M2) (vs @ xs2) by auto 


  have "productF M2 M1 FAIL PM" 
    using assms(4) by auto
  have "well_formed M1" 
    using assms(2) by auto
  have "well_formed M2" 
    using assms(3) by auto
  have "observable PM"
    by (meson assms(2) assms(3) assms(4) observable_productF)

  have "length (vs@xs1) = length tr2_1"
    using length tr2_1 = length (vs @ xs1) by presburger
  then have "length tr2_1 = length tr1_1" 
    using length tr1_1 = length (vs@xs1) by presburger

  have "vs@xs1  L PM" 
    using productF_path_inclusion[OF length (vs@xs1) = length tr2_1 length tr2_1 = length tr1_1 
                                     productF M2 M1 FAIL PM well_formed M2 well_formed M1]
    by (meson Int_iff productF M2 M1 FAIL PM vs @ xs1  L M1 vs @ xs1  L M2 well_formed M1 
        well_formed M2 productF_language)
    

  have "length (vs@xs2) = length tr2_2"
    using length tr2_2 = length (vs @ xs2) by presburger
  then have "length tr2_2 = length tr1_2" 
    using length tr1_2 = length (vs@xs2) by presburger

  have "vs@xs2  L PM" 
    using productF_path_inclusion[OF length (vs@xs2) = length tr2_2 length tr2_2 = length tr1_2 
                                     productF M2 M1 FAIL PM well_formed M2 well_formed M1]
    by (meson Int_iff productF M2 M1 FAIL PM vs @ xs2  L M1 vs @ xs2  L M2 well_formed M1 
        well_formed M2 productF_language)


  

  have "io_targets PM (initial M2, initial M1) (vs @ xs1) = {(s2, s1)}" 
    using productF_path_io_targets_reverse
          [OF productF M2 M1 FAIL PM s2  io_targets M2 (initial M2) (vs @ xs1) 
              s1  io_targets M1 (initial M1) (vs @ xs1) vs @ xs1  L M2 vs @ xs1  L M1 ]
  proof -
    have "c f. c  initial (f::('a, 'b, 'c) FSM)  c  nodes f"
      by blast
    then show ?thesis
      by (metis (no_types) observable M2; observable M1; well_formed M2; well_formed M1; 
                             initial M2  nodes M2; initial M1  nodes M1 
                             io_targets PM (initial M2, initial M1) (vs @ xs1) = {(s2, s1)} 
          assms(2) assms(3))
  qed 

  have "io_targets PM (initial M2, initial M1) (vs @ xs2) = {(s2, s1)}" 
    using productF_path_io_targets_reverse
          [OF productF M2 M1 FAIL PM s2  io_targets M2 (initial M2) (vs @ xs2) 
              s1  io_targets M1 (initial M1) (vs @ xs2) vs @ xs2  L M2 vs @ xs2  L M1 ]
  proof -
    have "c f. c  initial (f::('a, 'b, 'c) FSM)  c  nodes f"
      by blast
    then show ?thesis
      by (metis (no_types) observable M2; observable M1; well_formed M2; well_formed M1; 
                             initial M2  nodes M2; initial M1  nodes M1 
                             io_targets PM (initial M2, initial M1) (vs @ xs2) = {(s2, s1)} 
          assms(2) assms(3))
  qed

  have "prefix (vs @ xs1) (vs @ xs2)"
    using prefix xs1 xs2 by auto



  have "sequence_to_failure M1 M2 (vs@xs)" 
    using assms(1) by auto
  

  have "prefix (vs@xs1) (vs@xs')"
    using prefix xs1 xs2 prefix xs2 xs' prefix_order.dual_order.trans same_prefix_prefix 
    by blast 
  have "prefix (vs@xs2) (vs@xs')"
    using prefix xs2 xs' prefix_order.dual_order.trans same_prefix_prefix by blast 

   

  have "io_targets PM (initial PM) (vs @ xs1) = {(s2,s1)}"
    using io_targets PM (initial M2, initial M1) (vs @ xs1) = {(s2, s1)} assms(4) by auto
  have "io_targets PM (initial PM) (vs @ xs2) = {(s2,s1)}"
    using io_targets PM (initial M2, initial M1) (vs @ xs2) = {(s2, s1)} assms(4) by auto


  have "(vs @ xs2) @ (drop (length xs2) xs) = vs@xs"
    by (metis prefix xs2 xs'  append_eq_appendI append_eq_conv_conj assms(6) prefixE) 
  moreover have "io_targets PM (initial PM) (vs@xs) = {FAIL}" 
    using sequence_to_failure_reaches_FAIL_ob[OF sequence_to_failure M1 M2 (vs@xs) assms(2,3) 
                                                 productF M2 M1 FAIL PM] 
    by assumption
  ultimately have "io_targets PM (initial PM) ((vs @ xs2) @ (drop (length xs2) xs)) = {FAIL}" 
    by auto
  
  have "io_targets PM (s2,s1) (drop (length xs2) xs) = {FAIL}" 
    using observable_io_targets_split
          [OF observable PM
              io_targets PM (initial PM) ((vs @ xs2) @ (drop (length xs2) xs)) = {FAIL}
              io_targets PM (initial PM) (vs @ xs2) = {(s2, s1)}] 
    by assumption

  have "io_targets PM (initial PM) (vs@xs1@(drop (length xs2) xs)) = {FAIL}"
    using observable_io_targets_append
          [OF observable PM io_targets PM (initial PM) (vs @ xs1) = {(s2,s1)} 
              io_targets PM (s2,s1) (drop (length xs2) xs) = {FAIL}] 
    by simp
  have "sequence_to_failure M1 M2 (vs@xs1@(drop (length xs2) xs))"
    using sequence_to_failure_alt_def
          [OF io_targets PM (initial PM) (vs@xs1@(drop (length xs2) xs)) = {FAIL} assms(2,3)]
          assms(4) 
    by blast 

  have "length xs1 < length xs2"
    using prefix xs1 xs2 xs1  xs2 prefix_length_prefix by fastforce

  have prefix_drop: "ys = ys1 @ (drop (length ys1)) ys" if "prefix ys1 ys"
    for ys ys1 :: "('a × 'b) list"
    using that by (induction ys1) (auto elim: prefixE)
  then have "xs = (xs1 @ (drop (length xs1) xs))"
    using prefix xs1 xs2 prefix xs2 xs' prefix xs' xs by simp
  then have "length xs1 < length xs"
    using prefix_drop[OF prefix xs2 xs'] prefix xs2 xs' prefix xs' xs
    using length xs1 < length xs2
    by (auto dest!: prefix_length_le)
  have "length (xs1@(drop (length xs2) xs)) < length xs"
    using length xs1 < length xs2 length xs1 < length xs by auto


  have "vs  Lin M1 V 
         sequence_to_failure M1 M2 (vs @ xs1@(drop (length xs2) xs)) 
         length (xs1@(drop (length xs2) xs)) < length xs"
    using length (xs1 @ drop (length xs2) xs) < length xs 
          sequence_to_failure M1 M2 (vs @ xs1 @ drop (length xs2) xs) 
          assms(1) minimal_sequence_to_failure_extending.simps 
    by blast
  
  then have "¬ minimal_sequence_to_failure_extending V M1 M2 vs xs"
    by (meson minimal_sequence_to_failure_extending.elims(2))
   

  then show "False" 
    using assms(1) by linarith
qed
  



lemma minimal_sequence_to_failure_extending_implies_Rep_Cov :
  assumes "minimal_sequence_to_failure_extending V M1 M2 vs xs"
  and     "OFSM M1"
  and     "OFSM M2"
  and     "test_tools M2 M1 FAIL PM V Ω"
  and     "V''  N (vs@xsR) M1 V"
  and     "prefix xsR xs"
shows "¬ Rep_Cov M2 M1 V'' vs xsR"
proof 
  assume "Rep_Cov M2 M1 V'' vs xsR"
  then obtain xs' vs' s2 s1 where "xs'  []" 
                                  "prefix xs' xsR" 
                                  "vs'  V''"
                                  "io_targets M2 (initial M2) (vs @ xs') = {s2}" 
                                  "io_targets M2 (initial M2) (vs') = {s2}"
                                  "io_targets M1 (initial M1) (vs @ xs') = {s1}" 
                                  "io_targets M1 (initial M1) (vs') = {s1}"
    by auto

  then have "s2  io_targets M2 (initial M2) (vs @ xs')"
            "s2  io_targets M2 (initial M2) (vs')"
            "s1  io_targets M1 (initial M1) (vs @ xs')"
            "s1  io_targets M1 (initial M1) (vs')"            
    by auto

  have "vs@xs'  L M1" 
    using io_target_implies_L[OF s1  io_targets M1 (initial M1) (vs @ xs')] by assumption
  have "vs'  L M1" 
    using io_target_implies_L[OF s1  io_targets M1 (initial M1) (vs')] by assumption
  have "vs@xs'  L M2" 
    using io_target_implies_L[OF s2  io_targets M2 (initial M2) (vs @ xs')] by assumption
  have "vs'  L M2" 
    using io_target_implies_L[OF s2  io_targets M2 (initial M2) (vs')] by assumption

  obtain tr1_1 where "path M1 (vs@xs' || tr1_1) (initial M1)"
                     "length tr1_1 = length (vs@xs')"
                     "target (vs@xs' || tr1_1) (initial M1) = s1"
    using s1  io_targets M1 (initial M1) (vs @ xs') by auto
  obtain tr1_2 where "path M1 (vs' || tr1_2) (initial M1)"
                     "length tr1_2 = length (vs')"
                     "target (vs' || tr1_2) (initial M1) = s1"
    using s1  io_targets M1 (initial M1) (vs') by auto 
  obtain tr2_1 where "path M2 (vs@xs' || tr2_1) (initial M2)"
                     "length tr2_1 = length (vs@xs')"
                     "target (vs@xs' || tr2_1) (initial M2) = s2"
    using s2  io_targets M2 (initial M2) (vs @ xs') by auto
  obtain tr2_2 where "path M2 (vs' || tr2_2) (initial M2)"
                     "length tr2_2 = length (vs')"
                     "target (vs' || tr2_2) (initial M2) = s2" 
    using s2  io_targets M2 (initial M2) (vs') by auto 


  have "productF M2 M1 FAIL PM" 
    using assms(4) by auto
  have "well_formed M1" 
    using assms(2) by auto
  have "well_formed M2" 
    using assms(3) by auto
  have "observable PM"
    by (meson assms(2) assms(3) assms(4) observable_productF)

  have "length (vs@xs') = length tr2_1"
    using length tr2_1 = length (vs @ xs') by presburger
  then have "length tr2_1 = length tr1_1" 
    using length tr1_1 = length (vs@xs') by presburger

  have "vs@xs'  L PM" 
    using productF_path_inclusion[OF length (vs@xs') = length tr2_1 length tr2_1 = length tr1_1 
                                     productF M2 M1 FAIL PM well_formed M2 well_formed M1]
    by (meson Int_iff productF M2 M1 FAIL PM vs @ xs'  L M1 vs @ xs'  L M2 well_formed M1
        well_formed M2 productF_language)
    

  have "length (vs') = length tr2_2"
    using length tr2_2 = length (vs') by presburger
  then have "length tr2_2 = length tr1_2" 
    using length tr1_2 = length (vs') by presburger

  have "vs'  L PM" 
    using productF_path_inclusion[OF length (vs') = length tr2_2 length tr2_2 = length tr1_2 
                                     productF M2 M1 FAIL PM well_formed M2 well_formed M1]
    by (meson Int_iff productF M2 M1 FAIL PM vs'  L M1 vs'  L M2 well_formed M1 
        well_formed M2 productF_language)


  

  have "io_targets PM (initial M2, initial M1) (vs @ xs') = {(s2, s1)}" 
    using productF_path_io_targets_reverse
          [OF productF M2 M1 FAIL PM s2  io_targets M2 (initial M2) (vs @ xs') 
              s1  io_targets M1 (initial M1) (vs @ xs') vs @ xs'  L M2 vs @ xs'  L M1 ]
  proof -
    have "c f. c  initial (f::('a, 'b, 'c) FSM)  c  nodes f"
      by blast
    then show ?thesis
      by (metis (no_types) observable M2; observable M1; well_formed M2; well_formed M1; 
                              initial M2  nodes M2; initial M1  nodes M1 
                             io_targets PM (initial M2, initial M1) (vs @ xs') = {(s2, s1)} 
          assms(2) assms(3))
  qed 

  have "io_targets PM (initial M2, initial M1) (vs') = {(s2, s1)}" 
    using productF_path_io_targets_reverse
          [OF productF M2 M1 FAIL PM s2  io_targets M2 (initial M2) (vs') 
              s1  io_targets M1 (initial M1) (vs') vs'  L M2 vs'  L M1 ]
  proof -
    have "c f. c  initial (f::('a, 'b, 'c) FSM)  c  nodes f"
      by blast
    then show ?thesis
      by (metis (no_types) observable M2; observable M1; well_formed M2; well_formed M1; 
                              initial M2  nodes M2; initial M1  nodes M1 
                             io_targets PM (initial M2, initial M1) (vs') = {(s2, s1)} 
          assms(2) assms(3))
  qed
  have "io_targets PM (initial PM) (vs') = {(s2, s1)}"
    by (metis (no_types) io_targets PM (initial M2, initial M1) vs' = {(s2, s1)} 
        productF M2 M1 FAIL PM productF_simps(4))
   

  have "sequence_to_failure M1 M2 (vs@xs)" 
    using assms(1) by auto

  have "xs = xs' @ (drop (length xs') xs)"
    by (metis prefix xs' xsR append_assoc append_eq_conv_conj assms(6) prefixE)
  then have "io_targets PM (initial M2, initial M1) (vs @ xs' @ (drop (length xs') xs)) = {FAIL}"
    by (metis productF M2 M1 FAIL PM sequence_to_failure M1 M2 (vs @ xs) assms(2) assms(3) 
        productF_simps(4) sequence_to_failure_reaches_FAIL_ob)
  then have "io_targets PM (initial M2, initial M1) ((vs @ xs') @ (drop (length xs') xs)) = {FAIL}"    
    by auto
  have "io_targets PM (s2, s1) (drop (length xs') xs) = {FAIL}" 
    using observable_io_targets_split
          [OF observable PM 
              io_targets PM (initial M2,initial M1) ((vs @ xs') @ (drop (length xs') xs)) = {FAIL} 
              io_targets PM (initial M2, initial M1) (vs @ xs') = {(s2, s1)}] 
    by assumption

  have "io_targets PM (initial PM) (vs' @ (drop (length xs') xs)) = {FAIL}" 
    using observable_io_targets_append
          [OF observable PM io_targets PM (initial PM) (vs') = {(s2, s1)}
              io_targets PM (s2, s1) (drop (length xs') xs) = {FAIL}] 
    by assumption

  have "sequence_to_failure M1 M2 (vs' @ (drop (length xs') xs))"   
    using sequence_to_failure_alt_def
          [OF io_targets PM (initial PM) (vs' @ (drop (length xs') xs)) = {FAIL} assms(2,3)] 
          assms(4) 
    by blast

  have "length (drop (length xs') xs) < length xs"
    by (metis (no_types) xs = xs' @ drop (length xs') xs xs'  [] length_append 
        length_greater_0_conv less_add_same_cancel2)   

  have "vs'  Lin M1 V" 
  proof -
    have "V''  Perm V M1" 
      using assms(5) unfolding N.simps by blast

    then obtain f where f_def : "V'' = image f V 
                                   ( v  V . f v  language_state_for_input M1 (initial M1) v)"
      unfolding Perm.simps by blast
    then obtain v where "v  V" "vs' = f v" 
      using vs'  V'' by auto
    then have "vs'  language_state_for_input M1 (initial M1) v" 
      using f_def by auto
    
    have "language_state_for_input M1 (initial M1) v = Lin M1 {v}"
      by auto
    moreover have "{v}  V" 
      using v  V by blast   
    ultimately have "language_state_for_input M1 (initial M1) v  Lin M1 V"
      unfolding language_state_for_inputs.simps language_state_for_input.simps by blast
    then show ?thesis
      usingvs'  language_state_for_input M1 (initial M1) v by blast
  qed
  
  have "¬ minimal_sequence_to_failure_extending V M1 M2 vs xs" 
    using vs'  Lin M1 V
          sequence_to_failure M1 M2 (vs' @ (drop (length xs') xs))
          length (drop (length xs') xs) < length xs
    using minimal_sequence_to_failure_extending.elims(2) by blast 
  then show "False" 
    using assms(1) by linarith
qed




lemma mstfe_no_repetition :
  assumes "minimal_sequence_to_failure_extending V M1 M2 vs xs"
  and     "OFSM M1"
  and     "OFSM M2"
  and     "test_tools M2 M1 FAIL PM V Ω"
  and     "V''  N (vs@xs') M1 V"
  and     "prefix xs' xs"
shows "¬ Rep_Pre M2 M1 vs xs'"
  and "¬ Rep_Cov M2 M1 V'' vs xs'"
  using minimal_sequence_to_failure_extending_implies_Rep_Pre[OF assms]
        minimal_sequence_to_failure_extending_implies_Rep_Cov[OF assms]
  by linarith+


subsection ‹ Sufficiency of the test suite to test for reduction ›

text ‹
The following lemma proves that set of input sequences generated in the final iteration of the
@{verbatim TS} function constitutes a test suite sufficient to test for reduction the FSMs it has 
been generated for.

This proof is performed by contradiction: If the test suite is not sufficient, then some minimal
sequence to a failure extending the deterministic state cover must exist. Due to the test suite
being assumed insufficient, this sequence cannot be contained in it and hence a prefix of it must
have been contained in one of the sets calculated by the @{verbatim R} function. This is only 
possible if the prefix is not a minimal sequence to a failure extending the deterministic state 
cover or if the test suite observes a failure, both of which violates the assumptions.
›


lemma asc_sufficiency :
  assumes "OFSM M1"
  and     "OFSM M2"
  and     "asc_fault_domain M2 M1 m"
  and     "test_tools M2 M1 FAIL PM V Ω"
  and     "final_iteration M2 M1 Ω V m i"  
shows "M1 ≼⟦(TS M2 M1 Ω V m i) . Ω M2  M1  M2"
proof 
  assume "atc_io_reduction_on_sets M1 (TS M2 M1 Ω V m i) Ω M2"
  show "M1  M2"
  proof (rule ccontr)
  
    let ?TS = "λ n . TS M2 M1 Ω V m n"
    let ?C = "λ n . C M2 M1 Ω V m n"
    let ?RM = "λ n . RM M2 M1 Ω V m n"
  
  
    assume "¬ M1  M2"
    obtain vs xs where "minimal_sequence_to_failure_extending V M1 M2 vs xs" 
      using  assms(1) assms(2) assms(4) 
             minimal_sequence_to_failure_extending_det_state_cover_ob[OF _ _ _ _ ¬ M1  M2, of V]
      by blast 
  
    then have "vs  Lin M1 V" 
              "sequence_to_failure M1 M2 (vs @ xs)" 
              "¬ ( io' .  w'  Lin M1 V . sequence_to_failure M1 M2 (w' @ io') 
                                                           length io' < length xs)"
      by auto
  
    then have "vs@xs  L M1 - L M2" 
      by auto
  
    have "vs@xs  Lin M1 {map fst (vs@xs)}"
      by (metis (full_types) Diff_iff vs @ xs  L M1 - L M2 insertI1 
          language_state_for_inputs_map_fst)
  
    have "vs@xs  Lin M2 {map fst (vs@xs)}"
      by (meson Diff_iff vs @ xs  L M1 - L M2 language_state_for_inputs_in_language_state 
          subsetCE) 
  
    have "finite V" 
      using det_state_cover_finite assms(4,2) by auto
    then have "finite (?TS i)"
      using TS_finite[of V M2] assms(2) by auto
    then have "io_reduction_on M1 (?TS i) M2" 
      using io_reduction_from_atc_io_reduction
            [OF atc_io_reduction_on_sets M1 (TS M2 M1 Ω V m i) Ω M2] 
      by auto
  
    have "map fst (vs@xs)  ?TS i"
    proof -
      have f1: "ps P Pa. (ps::('a × 'b) list)  P - Pa  ps  P  ps  Pa"
        by blast
      have "P Pa ps. ¬ P  Pa  (ps::('a × 'b) list)  Pa  ps  P"
        by blast
      then show ?thesis
        using f1 by (metis (no_types) vs @ xs  L M1 - L M2 io_reduction_on M1 (?TS i) M2 
                     language_state_for_inputs_in_language_state language_state_for_inputs_map_fst)
    qed 
  
    have "map fst vs  V"
      using vs  Lin M1 V by auto 
    
    let ?stf = "map fst (vs@xs)"
    let ?stfV = "map fst vs"
    let ?stfX = "map fst xs"
    have "?stf = ?stfV @ ?stfX"
      by simp 
  
    then have "?stfV @ ?stfX  ?TS i"
      using ?stf  ?TS i by auto 
  
    have "mcp (?stfV @ ?stfX) V ?stfV"
      by (metis map fst (vs @ xs) = map fst vs @ map fst xs 
          minimal_sequence_to_failure_extending V M1 M2 vs xs assms(1) assms(2) assms(4) 
          minimal_sequence_to_failure_extending_mcp)
  
    have "set ?stf  inputs M1"
      by (meson DiffD1 vs @ xs  L M1 - L M2 assms(1) language_state_inputs) 
    then have "set ?stf  inputs M2"
      using assms(3) by blast 
    moreover have "set ?stf = set ?stfV  set ?stfX"
      by simp 
    ultimately have "set ?stfX  inputs M2"
      by blast 
  
  
    obtain xr j where "xr  ?stfX" 
                      "prefix xr ?stfX" 
                      "Suc j  i" 
                      "?stfV@xr  RM M2 M1 Ω V m (Suc j)"
      using TS_non_containment_causes_final_suc[OF ?stfV @ ?stfX  ?TS i 
            mcp (?stfV @ ?stfX) V ?stfV set ?stfX  inputs M2 assms(5,2)] 
      by blast
  
    
    let ?yr = "take (length xr) (map snd xs)"
    have "length ?yr = length xr"
      using prefix xr (map fst xs) prefix_length_le by fastforce 
    have "(xr || ?yr) = take (length xr) xs"
      by (metis (no_types, opaque_lifting) prefix xr (map fst xs) append_eq_conv_conj prefixE take_zip
          zip_map_fst_snd) 
  
    have "prefix (vs@(xr || ?yr)) (vs@xs)"
      by (simp add: xr || take (length xr) (map snd xs) = take (length xr) xs take_is_prefix)
  
    have "xr = take (length xr) (map fst xs)"
      by (metis length (take (length xr) (map snd xs)) = length xr 
          xr || take (length xr) (map snd xs) = take (length xr) xs map_fst_zip take_map) 
  
    have "vs@(xr || ?yr)  L M1"
      by (metis DiffD1 prefix (vs @ (xr || take (length xr) (map snd xs))) (vs @ xs) 
          vs @ xs  L M1 - L M2 language_state_prefix prefixE) 
  
    then have "vs@(xr || ?yr)  Lin M1 {?stfV @ xr}"
      by (metis length (take (length xr) (map snd xs)) = length xr insertI1 
          language_state_for_inputs_map_fst map_append map_fst_zip) 
  
    have "length xr < length xs"
      by (metis xr = take (length xr) (map fst xs) xr  map fst xs not_le_imp_less take_all 
          take_map)
  
  
  
    from ?stfV@xr  RM M2 M1 Ω V m (Suc j) have "?stfV@xr  {xs'  C M2 M1 Ω V m (Suc j) .
        (¬ (Lin M1 {xs'}  Lin M2 {xs'}))
         ( io  Lin M1 {xs'} .
            ( V''  N io M1 V .  
              ( S1 . 
                ( vs xs .
                  io = (vs@xs)
                   mcp (vs@xs) V'' vs
                   S1  nodes M2
                   ( s1  S1 .  s2  S1 .
                    s1  s2  
                      ( io1  RP M2 s1 vs xs V'' .
                          io2  RP M2 s2 vs xs V'' .
                           B M1 io1 Ω  B M1 io2 Ω ))
                   m < LB M2 M1 vs xs (TS M2 M1 Ω V m j  V) S1 Ω V'' ))))}" 
      unfolding RM.simps by blast
  
    moreover have " xs'  ?C (Suc j) . Lin M1 {xs'}  Lin M2 {xs'}"
    proof 
      fix xs' assume "xs'  ?C (Suc j)"
      from Suc j  i have "?C (Suc j)  ?TS i"
        using C_subset TS_subset by blast 
      then have "{xs'}  ?TS i" 
        using xs'  ?C (Suc j) by blast
      show "Lin M1 {xs'}  Lin M2 {xs'}" 
        using io_reduction_on_subset[OF io_reduction_on M1 (?TS i) M2 {xs'}  ?TS i] 
        by assumption
    qed
  
    ultimately have "( io  Lin M1 {?stfV@xr} .
            ( V''  N io M1 V .  
              ( S1 . 
                ( vs xs .
                  io = (vs@xs)
                   mcp (vs@xs) V'' vs
                   S1  nodes M2
                   ( s1  S1 .  s2  S1 .
                    s1  s2  
                      ( io1  RP M2 s1 vs xs V'' .
                          io2  RP M2 s2 vs xs V'' .
                           B M1 io1 Ω  B M1 io2 Ω ))
                   m < LB M2 M1 vs xs (TS M2 M1 Ω V m j  V) S1 Ω V'' ))))"
      by blast 
  
    then have "
            ( V''  N (vs@(xr || ?yr)) M1 V .  
              ( S1 . 
                ( vs' xs' .
                  vs@(xr || ?yr) = (vs'@xs')
                   mcp (vs'@xs') V'' vs'
                   S1  nodes M2
                   ( s1  S1 .  s2  S1 .
                    s1  s2  
                      ( io1  RP M2 s1 vs' xs' V'' .
                          io2  RP M2 s2 vs' xs' V'' .
                           B M1 io1 Ω  B M1 io2 Ω ))
                   m < LB M2 M1 vs' xs' (TS M2 M1 Ω V m j  V) S1 Ω V'' )))"
      using vs@(xr || ?yr)  Lin M1 {?stfV @ xr}
      by blast 
  
    then obtain V'' S1 vs' xs' where RM_impl :  
                                     "V''  N (vs@(xr || ?yr)) M1 V"
                                     "vs@(xr || ?yr) = (vs'@xs')"
                                     "mcp (vs'@xs') V'' vs'"
                                     "S1  nodes M2"
                                     "( s1  S1 .  s2  S1 .
                                       s1  s2  
                                          ( io1  RP M2 s1 vs' xs' V'' .
                                              io2  RP M2 s2 vs' xs' V'' .
                                               B M1 io1 Ω  B M1 io2 Ω ))"
                                     " m < LB M2 M1 vs' xs' (TS M2 M1 Ω V m j  V) S1 Ω V''"
      by blast
  
   
    have "?stfV = mcp' (map fst (vs @ (xr || take (length xr) (map snd xs)))) V"
      by (metis (full_types) length (take (length xr) (map snd xs)) = length xr 
          mcp (map fst vs @ map fst xs) V (map fst vs) prefix xr (map fst xs) map_append 
          map_fst_zip mcp'_intro mcp_prefix_of_suffix) 
  
    have "is_det_state_cover M2 V"
      using assms(4) by blast 
    moreover have "well_formed M2" 
      using assms(2) by auto
    moreover have "finite V" 
      using det_state_cover_finite assms(4,2) by auto
    ultimately have "vs  V''"  
                    "vs = mcp' (vs @ (xr || take (length xr) (map snd xs))) V''"
      using N_mcp_prefix[OF ?stfV = mcp' (map fst (vs @ (xr || take (length xr) (map snd xs)))) V 
            V''  N (vs@(xr || ?yr)) M1 V, of M2] 
      by simp+
    
    have "vs' = vs"
      by (metis (no_types) mcp (vs' @ xs') V'' vs' 
          vs = mcp' (vs @ (xr || take (length xr) (map snd xs))) V'' 
          vs @ (xr || take (length xr) (map snd xs)) = vs' @ xs' mcp'_intro)
     
    then have "xs' = (xr || ?yr)"
      using vs @ (xr || take (length xr) (map snd xs)) = vs' @ xs' by blast  
  
  
    have "V  ?TS i"
    proof -
      have "1  i"
        using Suc j  i by linarith
      then have "?TS 1  ?TS i"
        using TS_subset by blast   
      then show ?thesis 
        by auto
    qed
      
    have "?stfV@xr  ?C (Suc j)" 
      using ?stfV@xr  RM M2 M1 Ω V m (Suc j) unfolding RM.simps by blast
  
  
  
    ― ‹show that the prerequisites (@{verbatim Prereq}) for @{verbatim LB} are met by construction›
  
    have "(vs'aV''. prefix vs'a (vs' @ xs')  length vs'a  length vs')"
      using mcp (vs' @ xs') V'' vs' by auto
  
    moreover have "atc_io_reduction_on_sets M1 (?TS j  V) Ω M2"   
    proof -
      have "j < i" 
        using Suc j  i by auto
      then have "?TS j  ?TS i" 
        by (simp add: TS_subset) 
      then show ?thesis 
        using atc_io_reduction_on_subset
              [OF atc_io_reduction_on_sets M1 (TS M2 M1 Ω V m i) Ω M2, of "?TS j"]
        by (meson Un_subset_iff V  ?TS i atc_io_reduction_on_sets M1 (TS M2 M1 Ω V m i) Ω M2
            atc_io_reduction_on_subset) 
    qed
  
    moreover have "finite (?TS j  V)"
    proof -
      have "finite (?TS j)"
        using TS_finite[OF finite V, of M2 M1 Ω m j] assms(2) by auto 
      then show ?thesis 
        using finite V by blast
    qed
  
    moreover have "V  ?TS j  V" 
      by blast
  
    moreover have "( p . (prefix p xs'  p  xs')  map fst (vs' @ p)  ?TS j  V)"
    proof 
      fix p 
      show "prefix p xs'  p  xs'  map fst (vs' @ p)  TS M2 M1 Ω V m j  V"
      proof
        assume "prefix p xs'  p  xs'"
  
        have "prefix (map fst (vs' @ p)) (map fst (vs' @ xs'))"
          by (simp add: prefix p xs'  p  xs' map_mono_prefix)
        have "prefix (map fst (vs' @ p)) (?stfV @ xr)"
          using length (take (length xr) (map snd xs)) = length xr 
                prefix (map fst (vs' @ p)) (map fst (vs' @ xs')) 
                vs' = vs xs' = xr || take (length xr) (map snd xs) 
          by auto
        then have "prefix (map fst vs' @ map fst p) (?stfV @ xr)"
          by simp 
        then have "prefix (map fst p) xr"
          by (simp add: vs' = vs)
  
        have "?stfV @ xr  ?TS (Suc j)" 
        proof (cases j)
          case 0
          then show ?thesis
            using map fst vs @ xr  C M2 M1 Ω V m (Suc j) by auto  
        next
          case (Suc nat)
          then show ?thesis
            using TS.simps(3) map fst vs @ xr  C M2 M1 Ω V m (Suc j) by blast 
        qed
  
        have "mcp (map fst vs @ xr) V (map fst vs)"
          using mcp (map fst vs @ map fst xs) V (map fst vs) prefix xr (map fst xs) 
                mcp_prefix_of_suffix 
          by blast 
  
        have "map fst vs @ map fst p  TS M2 M1 Ω V m (Suc j)"
          using TS_prefix_containment[OF ?stfV @ xr  ?TS (Suc j) 
                                         mcp (map fst vs @ xr) V (map fst vs) 
                                         prefix (map fst p) xr] 
          by assumption
   
  
        have "Suc (length xr) = (Suc j)" 
          using C_index[OF ?stfV@xr  ?C (Suc j) mcp (map fst vs @ xr) V (map fst vs)] 
          by assumption
        
        have"Suc (length p) < (Suc j)"
        proof -
          have "map fst xs' = xr"
            by (metis xr = take (length xr) (map fst xs) 
                xr || take (length xr) (map snd xs) = take (length xr) xs 
                xs' = xr || take (length xr) (map snd xs) take_map)
          then show ?thesis
            by (metis (no_types) Suc_less_eq Suc (length xr) = Suc j prefix p xs'  p  xs' 
                append_eq_conv_conj length_map nat_less_le prefixE prefix_length_le take_all)
        qed
  
        have "mcp (map fst vs @ map fst p) V (map fst vs)"
          using mcp (map fst vs @ xr) V (map fst vs) prefix (map fst p) xr mcp_prefix_of_suffix 
          by blast 
  
        then have "map fst vs @ map fst p  ?C (Suc (length (map fst p)))" 
          using TS_index(2)[OF map fst vs @ map fst p  TS M2 M1 Ω V m (Suc j)] by auto
  
        have "map fst vs @ map fst p  ?TS j"
          using TS_union[of M2 M1 Ω V m j]
        proof -
          have "Suc (length p)  {0..<Suc j}"
            using Suc (length p) < Suc j by force
          then show ?thesis
            by (metis UN_I TS M2 M1 Ω V m j = (jset [0..<Suc j]. C M2 M1 Ω V m j) 
                map fst vs @ map fst p  C M2 M1 Ω V m (Suc (length (map fst p))) 
                length_map set_upt)
        qed 
  
        then show "map fst (vs' @ p)  TS M2 M1 Ω V m j  V"
          by (simp add: vs' = vs) 
      qed
    qed
  
    
    moreover have "vs' @ xs'  L M2  L M1"
      by (metis (no_types, lifting) IntI RM_impl(2) 
          xs'C M2 M1 Ω V m (Suc j). Lin M1 {xs'}  Lin M2 {xs'} 
          map fst vs @ xr  C M2 M1 Ω V m (Suc j) 
          vs @ (xr || take (length xr) (map snd xs))  Lin M1 {map fst vs @ xr} 
          language_state_for_inputs_in_language_state subsetCE)
      
          
    
    ultimately have "Prereq M2 M1 vs' xs' (?TS j  V) S1 Ω V''"
      using RM_impl(4,5) unfolding Prereq.simps by blast
  
    have "V''  Perm V M1"
      using V''  N (vs@(xr || ?yr)) M1 V unfolding N.simps by blast
  
    have prefix (xr || ?yr) xs
      by (simp add: xr || take (length xr) (map snd xs) = take (length xr) xs take_is_prefix)
  
  
    ― ‹ show that furthermore neither @{verbatim Rep_Pre} nor @{verbatim Rep_Cov} holds ›

    have "¬ Rep_Pre M2 M1 vs (xr || ?yr)"
      using minimal_sequence_to_failure_extending_implies_Rep_Pre
            [OF minimal_sequence_to_failure_extending V M1 M2 vs xs assms(1,2) 
                test_tools M2 M1 FAIL PM V Ω RM_impl(1) 
                prefix (xr || take (length xr) (map snd xs)) xs]
      by assumption
    then have "¬ Rep_Pre M2 M1 vs' xs'"
      using vs' = vs xs' = xr || ?yr by blast 
  
    have "¬ Rep_Cov M2 M1 V'' vs (xr || ?yr)" 
      using minimal_sequence_to_failure_extending_implies_Rep_Cov
            [OF minimal_sequence_to_failure_extending V M1 M2 vs xs assms(1,2) 
                test_tools M2 M1 FAIL PM V Ω RM_impl(1) 
                prefix (xr || take (length xr) (map snd xs)) xs]
      by assumption
    then have "¬ Rep_Cov M2 M1 V'' vs' xs'"
      using vs' = vs xs' = xr || ?yr by blast 
  
    have "vs'@xs'  L M1"
      using vs @ (xr || take (length xr) (map snd xs))  L M1 
            vs' = vs xs' = xr || take (length xr) (map snd xs) 
      by blast 
    
  
    ― ‹ therefore it is impossible to remove the prefix of the minimal sequence to a failure,
         as this would require @{verbatim M1} to have more than m states ›
    
    have "LB M2 M1 vs' xs' (?TS j  V) S1 Ω V''  card (nodes M1)"
      using LB_count[OF vs'@xs'  L M1 assms(1,2,3) test_tools M2 M1 FAIL PM V Ω 
                        V''  Perm V M1 Prereq M2 M1 vs' xs' (?TS j  V) S1 Ω V'' 
                        ¬ Rep_Pre M2 M1 vs' xs' ¬ Rep_Cov M2 M1 V'' vs' xs']
      by assumption
    then have "LB M2 M1 vs' xs' (?TS j  V) S1 Ω V''  m" 
      using assms(3) by linarith
  
    then show "False" 
      using m < LB M2 M1 vs' xs' (?TS j  V) S1 Ω V'' by linarith
  qed
qed




subsection ‹ Main result ›

text ‹
The following lemmata add to the previous result to show that some FSM @{verbatim M1} is a reduction 
of FSM @{verbatim M2} if and only if it is a reduction on the test suite generated by the adaptive 
state counting algorithm for these FSMs.
›

lemma asc_soundness :
  assumes     "OFSM M1"
  and         "OFSM M2"
shows "M1  M2  atc_io_reduction_on_sets M1 T Ω M2"
  using atc_io_reduction_on_sets_reduction assms by blast



lemma asc_main_theorem :
  assumes "OFSM M1"
  and     "OFSM M2"
  and     "asc_fault_domain M2 M1 m"
  and     "test_tools M2 M1 FAIL PM V Ω"
  and     "final_iteration M2 M1 Ω V m i"
shows     "M1  M2  atc_io_reduction_on_sets M1 (TS M2 M1 Ω V m i) Ω M2"
by (metis asc_sufficiency assms(1-5) atc_io_reduction_on_sets_reduction)




end