Theory Sequential_Composition_Generalized_Non_Destructive

(***********************************************************************************
 * Copyright (c) 2025 Université Paris-Saclay
 *
 * Author: Benoît Ballenghien, Université Paris-Saclay,
 *         CNRS, ENS Paris-Saclay, LMF
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 ***********************************************************************************)


chapter ‹Non Destructiveness Rules›

(*<*)
theory Sequential_Composition_Generalized_Non_Destructive
  imports "HOL-CSP_RS" CSP_PTick_Monotonicities
begin
  (*<*)


section ‹Sequential Composition›

subsection ‹Refinement›

lemma restriction_processptick_Seqptick_FD :
  P ; Q  n FD (P  n) ; (Q  n) (is ?lhs FD ?rhs)
proof -
  show ?lhs FD ?rhs
  proof (rule failure_divergence_refine_optimizedI)
    { fix t assume tF t and t  𝒟 ?rhs
      from this(2) consider (D_P) u v where t = map (ev  of_ev) u @ v u  𝒟 (P  n) tF u ftF v
        | (D_Q) u r v where t = map (ev  of_ev) u @ v u @ [✓(r)]  𝒯 P length u < n tF u v  𝒟 ((Q  n) r)
        by (auto simp add: Seqptick_projs restriction_processptick_projs)
         (metis D_P D_imp_front_tickFree D_restriction_processptickI is_processT3_TR_append linorder_less_linear,
           metis D_P D_imp_front_tickFree D_restriction_processptickI is_processT7 is_processT9)
      hence t  𝒟 ?lhs
      proof cases
        case D_P thus t  𝒟 ?lhs
          by (elim D_restriction_processptickE, simp_all add: Seqptick_projs D_restriction_processptick)
            (metis, metis front_tickFree_append length_map tickFree_map_ev_comp)
      next
        case D_Q
        from D_Q(5) show t  𝒟 ?lhs
        proof (unfold restriction_fun_def, elim D_restriction_processptickE)
          assume v  𝒟 (Q r)
          with D_Q(1, 2, 4) have t  𝒟 (P ; Q) by (auto simp add: Seqptick_projs)
          thus t  𝒟 ?lhs by (simp add: D_restriction_processptickI)
        next
          fix w x assume v = w @ x w  𝒯 (Q r) length w = n tF w ftF x
          from D_Q(2, 4) w  𝒯 (Q r) have map (ev  of_ev) u @ w  𝒯 (P ; Q)
            by (auto simp add: Seqptick_projs)
          moreover have tF (map (ev  of_ev) u @ w) by (simp add: tF w)
          moreover have n  length (map (ev  of_ev) u @ w)
            by (simp add: length w = n)
          ultimately have map (ev  of_ev) u @ w  𝒟 ?lhs
            by (metis D_restriction_processptickI antisym_conv2)
          with D_Q(1) tF t v = w @ x is_processT7 show t  𝒟 (P ; Q  n) by fastforce
        qed
      qed
    }
    thus t  𝒟 ?rhs  t  𝒟 ?lhs for t
      by (metis D_imp_front_tickFree div_butlast_when_non_tickFree_iff front_tickFree_iff_tickFree_butlast)
  next
    have (P  n) ; (Q  n)  P ; Q
      by (simp add: fun_below_iff mono_Seqptick restriction_fun_def
          restriction_processptick_approx_self)
    thus (t, X)   ?rhs  𝒟 ((P  n) ; (Q  n))  𝒟 (P ; Q  n) 
          (t, X)   ?lhs for t X
      by (meson F_restriction_processptickI in_mono is_processT8 le_approx2)
  qed
qed


corollary restriction_processptick_MultiSeqptick_FD :
  ((SEQ l ∈@ L. P l)  n) r FD (SEQ l ∈@ L. (P l  n)) r
proof (induct L arbitrary: r)
  show ((SEQ l ∈@ []. P l)  n) r FD (SEQ l ∈@ []. (P l  n)) r for r
    by (simp add: restriction_fun_def)
next
  fix a L r
  assume hyp: ((SEQ l ∈@ L. P l)  n) r FD (SEQ l ∈@ L. (P l  n)) r for r
  have ((SEQ l ∈@ (a # L). P l)  n) r = P a r ; (SEQ l ∈@ L. P l)  n
    by (simp add: restriction_fun_def)
  also have  FD (P a r  n) ; SEQ l ∈@ L. (P l  n)
    by (fact trans_FD[OF restriction_processptick_Seqptick_FD mono_Seqptick_FD[OF idem_FD hyp]])
  also have  = (SEQ l ∈@ (a # L). (P l  n)) r
    by (simp add: restriction_fun_def)
  finally show ((SEQ l ∈@ (a # L). P l)  n) r FD  .
qed


subsection ‹Non Destructiveness›

lemma Seqptick_non_destructive :
  non_destructive (λ(P, Q :: 'r  ('a, 's) processptick). P ; Q)
proof (rule order_non_destructiveI, clarify)
  fix P P' :: ('a, 'r) processptick and Q Q' :: 'r  ('a, 's) processptick and n
  assume (P, Q)  n = (P', Q')  n 0 < n
  hence P  n = P'  n Q  n = Q'  n
    by (simp_all add: restriction_prod_def)
  show P ; Q  n FD P' ; Q'  n
  proof (rule leFD_restriction_processptickI)
    show t  𝒟 (P' ; Q')  t  𝒟 (P ; Q  n) for t
      by (metis (mono_tags, opaque_lifting) P  n = P'  n Q  n = Q'  n in_mono
                le_ref1 mono_Seqptick_FD restriction_fun_def restriction_processptick_FD_self
                restriction_processptick_Seqptick_FD)
  next
    show (s, X)   (P' ; Q')  (s, X)   (P ; Q  n) for s X
      by (metis (mono_tags, opaque_lifting) P  n = P'  n Q  n = Q'  n
                failure_refine_def leFD_imp_leF mono_Seqptick_FD
                restriction_fun_def restriction_processptick_FD_self
                restriction_processptick_Seqptick_FD subset_iff)
  qed
qed



subsection ‹Setup›

text ‹
We also introduce a third law: the assumption of constructiveness for termg can be
weakened to non destructiveness if we cannot directly perform a tick on the left.
›

lemma Seqptick_restriction_shift_processptick :
  non_destructive f  non_destructive g  non_destructive (λx. f x ; g x)
  constructive f  constructive g  constructive (λx. f x ; g x)
  constructive f  non_destructive g  (x r. ✓(r)  (f x)0)  constructive (λx. f x ; g x)
  for f :: 'b :: restriction  ('a, 'r) processptick
  ― ‹TODO: this can probably by strengthened with a notion of strict initials›
proof -
  show non_destructive f  non_destructive g  non_destructive (λx. f x ; g x)
    by (fact non_destructive_comp_non_destructive
        [OF Seqptick_non_destructive non_destructive_prod_codomain, simplified])
next
  show constructive f  constructive g  constructive (λx. f x ; g x)
    by (fact non_destructive_comp_constructive
        [OF Seqptick_non_destructive constructive_prod_codomain, simplified])
next
  show constructive (λx. f x ; g x)
    if constructive f and non_destructive g and x r. ✓(r)  (f x)0
  proof (rule order_constructiveI)
    fix x y :: 'b and n assume x  n = y  n
    with that(1, 2) have f x  Suc n = f y  Suc n and g x  n = g y  n
      by (auto dest: non_destructiveD constructiveD)
    show f x ; g x  Suc n FD f y ; g y  Suc n
    proof (rule leFD_restriction_processptickI)
      show div : t  𝒟 (f x ; g x  Suc n) if length t  Suc n and t  𝒟 (f y ; g y) for t
      proof (cases n)
        assume n = 0
        with length t  Suc n t  𝒟 (f y ; g y) f x  Suc n = f y  Suc n r. ✓(r)  (f y)0
        show t  𝒟 (f x ; g x  Suc n)
          by (auto simp add: D_restriction_processptick Seqptick_projs)
            (metis D_T D_restriction_processptickI add_leE length_le_in_T_restriction_processptick
                   length_less_in_D_restriction_processptick length_map order_le_imp_less_or_eq tickFree_map_ev_comp,
              metis T_restriction_processptickI add_leD1 front_tickFree_Nil initials_memI' is_processT3_TR_append
                    le_SucE length_greater_0_conv length_le_in_T_restriction_processptick length_map
                    less_numeral_extra(3) one_is_add order_less_le_trans self_append_conv2 tickFree_map_ev_comp)
      next
        fix k assume n = Suc k
        from t  𝒟 (f y ; g y)
        consider (D_P) u v where t = map (ev  of_ev) u @ v u  𝒟 (f y) tF u ftF v
          | (D_Q) u r v where t = map (ev  of_ev) u @ v u @ [✓(r)]  𝒯 (f y) tF u v  𝒟 (g y r)
          unfolding Seqptick_projs by blast
        thus t  𝒟 (f x ; g x  Suc n)
        proof cases
          case D_P
          with  f x  Suc n = f y  Suc n show t  𝒟 (f x ; g x  Suc n)
            by (simp add: D_restriction_processptick Seqptick_projs)
              (metis D_T D_restriction_processptickI length_append length_le_in_T_restriction_processptick
                     length_less_in_D_restriction_processptick length_map linorder_not_less
                     not_less_iff_gr_or_eq that(1) tickFree_map_ev_comp trans_less_add1)
        next
          case D_Q
          from ✓(r)  (f y)0 D_Q(2, 3) obtain a u' where u = ev a # u'
            by (metis append_Nil eventptick.collapse(1) initials_memI neq_Nil_conv tickFree_Cons_iff)
          with length t  Suc n D_Q(1)
          consider v = [] length u = Suc n | u' = [] length v = n | length u  n length v < n
            by simp
              (metis (no_types, opaque_lifting) add_cancel_right_right add_leD2 add_le_same_cancel2
                     antisym length_greater_0_conv linorder_not_less not_less_eq_eq trans_le_add1)
          thus t  𝒟 (f x ; g x  Suc n)
          proof cases
            from D_Q(1-3) f x  Suc n = f y  Suc n
            show v = []  length u = Suc n  t  𝒟 (f x ; g x  Suc n)
              by (simp add: D_restriction_processptick Seqptick_projs)
                (metis T_restriction_processptickI front_tickFree_Nil is_processT3_TR_append le_Suc_eq
                       length_le_in_T_restriction_processptick length_map self_append_conv tickFree_map_ev_comp)
          next
            assume u' = [] length v = n
            from f x  Suc n = f y  Suc n n = Suc k u = ev a # u' u' = []
            have u @ [✓(r)]  𝒯 (f x)
              by simp
                (smt (verit, best) D_Q(2) D_T One_nat_def T_F_spec add_Suc_shift append_Cons
                     append_self_conv2 le_add1 le_approx2 length_Cons list.size(3)
                     non_tickFree_tick not_tickFree_in_D_restriction_processptick_iff plus_1_eq_Suc
                     restriction_processptick_approx_self tickFree_append_iff)
            from D_Q(4) consider tF v v  𝒯 (g x r) | ¬ tF v v  𝒟 (g x r)
              by (metis D_T D_restriction_processptickI g x  n = g y  n length v = n dual_order.refl
                  length_le_in_T_restriction_processptick not_tickFree_in_D_restriction_processptick_iff restriction_fun_def)
            thus t  𝒟 (f x ; g x  Suc n)
            proof cases
              assume tF v v  𝒯 (g x r)
              from D_Q(3) u @ [✓(r)]  𝒯 (f x) v  𝒯 (g x r)
              have map (ev  of_ev) u @ v  𝒯 (f x ; g x)
                by (auto simp add: Seqptick_projs)
              moreover have tF (map (ev  of_ev) u @ v) by (simp add: tF v)
              moreover have length (map (ev  of_ev) u @ v) = Suc n
                by (simp add: length v = n u = ev a # u' u' = [])
              ultimately show t  𝒟 (f x ; g x  Suc n)
                by (metis D_Q(1) D_restriction_processptickI)
            next
              from u @ [✓(r)]  𝒯 (f x) D_Q(1, 3)
              show ¬ tF v  v  𝒟 (g x r)  t  𝒟 (f x ; g x  Suc n)
                by (auto simp add: D_restriction_processptick Seqptick_projs)
            qed
          next
            assume length u  n length v < n
            have u @ [✓(r)]  𝒯 (f x)
              by (metis D_Q(2) T_restriction_processptickI f x  Suc n = f y  Suc n length u  n length_append_singleton
                  length_le_in_T_restriction_processptick nat_add_left_cancel_le plus_1_eq_Suc)
            moreover have v  𝒟 (g x r)
              by (metis D_Q(4) D_restriction_processptickI g x  n = g y  n length v < n
                        length_less_in_D_restriction_processptick restriction_fun_def)
            ultimately have map (ev  of_ev) u @ v  𝒟 (f x ; g x)
              by (simp add: Seqptick_projs) (use D_Q(3) in blast)
            thus t  𝒟 (f x ; g x  Suc n)
              by (simp add: D_Q(1) D_restriction_processptickI)
          qed
        qed
      qed

      fix t X assume length t  Suc n (t, X)   (f y ; g y)
      show (t, X)   (f x ; g x  Suc n)
      proof (cases n)
        assume n = 0
        with length t  Suc n (t, X)   (f y ; g y) f x  Suc n = f y  Suc n r. ✓(r)  (f y)0
        show (t, X)   (f x ; g x  Suc n)
          by (auto simp add: F_restriction_processptick Seqptick_projs)
            (metis F_T F_restriction_processptickI antisym_conv2 append_Nil2 front_tickFree_Nil
                   length_le_in_T_restriction_processptick length_less_in_F_restriction_processptick
                   length_map tickFree_map_ev_comp,
              metis add_leE front_tickFree_Nil initials_memI is_processT3_TR_append le_Suc_eq le_ref2T
                    le_zero_eq length_0_conv length_le_in_T_restriction_processptick length_map one_is_add
                    restriction_processptick_FD_self self_append_conv2 subset_iff tickFree_map_ev_comp,
              metis D_T D_restriction_processptickI add_leD1 le_SucE le_imp_less_Suc
                    length_le_in_T_restriction_processptick length_less_in_D_restriction_processptick
                    length_map tickFree_map_ev_comp)
      next
        fix k assume n = Suc k
        from (t, X)   (f y ; g y) consider t  𝒟 (f y ; g y)
        | (F_P) u where t = map (ev  of_ev) u (u, ref_Seqptick X)   (f y) tF u
        | (F_Q) u r v where t = map (ev  of_ev) u @ v u @ [✓(r)]  𝒯 (f y) tF u (v, X)   (g y r)
        unfolding Seqptick_projs by fast
      thus (t, X)   (f x ; g x  Suc n)
      proof cases
        from div length t  Suc n is_processT8
        show t  𝒟 (f y ; g y)  (t, X)   (f x ; g x  Suc n) by blast
      next
        case F_P
        from length t  Suc n consider length u  n | length u = Suc n
          by (simp add: F_P(1)) linarith
        thus (t, X)   (f x ; g x  Suc n)
        proof cases
          assume length u  n
          with f x  Suc n = f y  Suc n F_P(2)
          have (u, ref_Seqptick X)   (f x)
            by (metis F_restriction_processptickI less_Suc_eq_le
                length_less_in_F_restriction_processptick)
          with F_P(1, 3) have (t, X)   (f x ; g x) by (auto simp add: Seqptick_projs)
          thus (t, X)   (f x ; g x  Suc n)
            by (simp add: F_restriction_processptickI)
        next
          assume length u = Suc n
          with F_P f x  Suc n = f y  Suc n
          have t  𝒯 (f x ; g x)
            by (simp add: Seqptick_projs)
              (metis F_T T_restriction_processptickI le_Suc_eq length_le_in_T_restriction_processptick)
          moreover have length t = Suc n by (simp add: F_P(1) length u = Suc n)
          moreover have tF t by (simp add: F_P(1))
          ultimately have t  𝒟 (f x ; g x  Suc n)
            by (simp add: D_restriction_processptickI)
          thus (t, X)   (f x ; g x  Suc n) by (fact is_processT8)
        qed
      next
        case F_Q
        from ✓(r)  (f y)0 F_Q(2, 3) obtain a u' where u = ev a # u'
            by (metis append_Nil eventptick.collapse(1) initials_memI neq_Nil_conv tickFree_Cons_iff)
          with length t  Suc n F_Q(1)
          consider v = [] length u = Suc n | u' = [] length v = n | length u  n length v < n
            by simp
              (metis (no_types, opaque_lifting) add_cancel_right_right add_leD2 add_le_same_cancel2
                     antisym length_greater_0_conv linorder_not_less not_less_eq_eq trans_le_add1)
          thus (t, X)   (f x ; g x  Suc n)
          proof cases
            from F_Q(1-3) f x  Suc n = f y  Suc n
            show v = []  length u = Suc n  (t, X)   (f x ; g x  Suc n)
              by (simp add: F_restriction_processptick Seqptick_projs)
                (metis T_restriction_processptickI front_tickFree_Nil is_processT3_TR_append le_Suc_eq
                       length_le_in_T_restriction_processptick length_map self_append_conv tickFree_map_ev_comp)
          next
            assume u' = [] length v = n
            from f x  Suc n = f y  Suc n n = Suc k u = ev a # u' u' = []
            have u @ [✓(r)]  𝒯 (f x)
              by simp
                (smt (verit, best) F_Q(2) D_T One_nat_def T_F_spec add_Suc_shift append_Cons
                     append_self_conv2 le_add1 le_approx2 length_Cons list.size(3)
                     non_tickFree_tick not_tickFree_in_D_restriction_processptick_iff plus_1_eq_Suc
                     restriction_processptick_approx_self tickFree_append_iff)
            from F_Q(4) consider tF v v  𝒯 (g x r) | ¬ tF v (v, X)   (g x r)
              by (metis F_T F_restriction_processptickI g x  n = g y  n length v = n dual_order.refl
                  length_le_in_T_restriction_processptick not_tickFree_in_F_restriction_processptick_iff restriction_fun_def)
            thus (t, X)   (f x ; g x  Suc n)
            proof cases
              assume tF v v  𝒯 (g x r)
              from F_Q(3) u @ [✓(r)]  𝒯 (f x) v  𝒯 (g x r)
              have map (ev  of_ev) u @ v  𝒯 (f x ; g x)
                by (auto simp add: Seqptick_projs)
              moreover have tF (map (ev  of_ev) u @ v) by (simp add: tF v)
              moreover have length (map (ev  of_ev) u @ v) = Suc n
                by (simp add: length v = n u = ev a # u' u' = [])
              ultimately have t  𝒟 (f x ; g x  Suc n)
                by (metis F_Q(1) D_restriction_processptickI)
              thus (t, X)   (f x ; g x  Suc n) by (fact is_processT8)
            next
              from u @ [✓(r)]  𝒯 (f x) F_Q(1, 3)
              show ¬ tF v  (v, X)   (g x r)  (t, X)   (f x ; g x  Suc n)
                by (auto simp add: F_restriction_processptick Seqptick_projs)
            qed
          next
            assume length u  n length v < n
            have u @ [✓(r)]  𝒯 (f x)
              by (metis F_Q(2) T_restriction_processptickI f x  Suc n = f y  Suc n length u  n length_append_singleton
                  length_le_in_T_restriction_processptick nat_add_left_cancel_le plus_1_eq_Suc)
            moreover have (v, X)   (g x r)
              by (metis F_Q(4) F_restriction_processptickI g x  n = g y  n length v < n
                        length_less_in_F_restriction_processptick restriction_fun_def)
            ultimately have (map (ev  of_ev) u @ v, X)   (f x ; g x)
              by (simp add: Seqptick_projs) (use F_Q(3) in blast)
            thus (t, X)   (f x ; g x  Suc n)
              by (simp add: F_Q(1) F_restriction_processptickI)
          qed
        qed
      qed
    qed
  qed
qed
   

declare Seqptick_restriction_shift_processptick
  [restriction_shift_processptick_simpset, simp]


text ‹The third one can be adapted for classical sequential composition.›

lemmas Seq_restriction_shift_processptick_3 =
  Seqptick_restriction_shift_processptick(3)[where g = λx r. g x, simplified] for g

declare Seq_restriction_shift_processptick_3 [restriction_shift_processptick_simpset, simp]




corollary MultiSeqptick_restriction_shift_processptick :
  (l. l  set L  non_destructive (f l))  non_destructive (λx. (SEQ l ∈@ L. f l x) r)
  (l. l  set L  constructive (f l))  constructive (λx. (SEQ l ∈@ L. f l x) r)
  (case L of []  True | l0 # L' 
    constructive (f l0)  (x r'. ✓(r')  (f l0 x r)0)  (lset L'. non_destructive (f l)))
     constructive (λx. (SEQ l ∈@ L. f l x) r)
proof -
  show (l. l  set L  constructive (f l))  constructive (λx. (SEQ l ∈@ L. f l x) r)
    by (induct L arbitrary: r; simp add: constructive_fun_iff)
next
  show * : (l. l  set L  non_destructive (f l)) 
            non_destructive (λx. (SEQ l ∈@ L. f l x) r) for L r
    by (induct L arbitrary: r; simp add: non_destructive_fun_iff)

  show (case L of []  True | l0 # L' 
        constructive (f l0)  (x r'. ✓(r')  (f l0 x r)0)  (lset L'. non_destructive (f l)))
         constructive (λx. (SEQ l ∈@ L. f l x) r)
    by (auto split: list.split_asm intro: Seqptick_restriction_shift_processptick(3)
        simp add: constructive_fun_iff non_destructive_fun_iff "*" )
qed


corollary MultiSeqptick_non_destructive :
  non_destructive (λP. (SEQ l ∈@ L. P l) r)
  non_destructive (λP. (SEQ l ∈@ L. P l))
  by (simp_all add: MultiSeqptick_restriction_shift_processptick(1)[of L λl x. x l])


declare MultiSeqptick_restriction_shift_processptick
  [restriction_shift_processptick_simpset, simp]



(*<*)
end
  (*>*)