Theory SAT_Plan_Extensions
theory SAT_Plan_Extensions
  imports SAT_Plan_Base
begin
section "Serializable SATPlan Encodings"
text ‹ A SATPlan encoding with exclusion of operator interference (see definition
\ref{def:sat-plan-encoding-with-interference-exclusion}) can be defined by extending the basic
SATPlan encoding with clauses
  @{text[display, indent=4] "
    ❙¬(Atom (Operator k (index ops op⇩1))
    ❙∨ ❙¬(Atom (Operator k (index ops op⇩2))"}
for all pairs of distinct interfering operators \<^term>‹op⇩1›, \<^term>‹op⇩2› for all time points
\<^term>‹k < t› for a given estimated plan length \<^term>‹t›. Definitions
\ref{isadef:interfering-operator-pair-exclusion-encoding} and
\ref{isadef:interfering-operator-exclusion-encoding} implement the encoding for operator pairs
resp. for all interfering operator pairs and all time points. ›
definition encode_interfering_operator_pair_exclusion
  :: "'variable strips_problem
    ⇒ nat
    ⇒ 'variable strips_operator
    ⇒ 'variable strips_operator
    ⇒ sat_plan_variable formula"
  where "encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2
    ≡ let ops = operators_of Π in
      ❙¬(Atom (Operator k (index ops op⇩1)))
      ❙∨ ❙¬(Atom (Operator k (index ops op⇩2)))"
definition encode_interfering_operator_exclusion
  :: "'variable strips_problem ⇒ nat ⇒ sat_plan_variable formula"
  where "encode_interfering_operator_exclusion Π t ≡ let
      ops = operators_of Π
      ; interfering = filter (λ(op⇩1, op⇩2). index ops op⇩1 ≠ index ops op⇩2
        ∧ are_operators_interfering op⇩1 op⇩2) (List.product ops ops)
    in foldr (❙∧) [encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2.
      (op⇩1, op⇩2) ← interfering, k ← [0..<t]] (❙¬⊥)"
text ‹ A SATPlan encoding with interfering operator pair exclusion can now be defined by
simplying adding the conjunct \<^term>‹encode_interfering_operator_exclusion Π t› to the basic
SATPlan encoding. ›
definition encode_problem_with_operator_interference_exclusion
  :: "'variable strips_problem ⇒ nat ⇒ sat_plan_variable formula"
  (‹Φ⇩∀ _ _› 52)
  where "encode_problem_with_operator_interference_exclusion Π t
    ≡ encode_initial_state Π
      ❙∧ (encode_operators Π t
      ❙∧ (encode_all_frame_axioms Π t
      ❙∧ (encode_interfering_operator_exclusion Π t
      ❙∧ (encode_goal_state Π t))))"
lemma cnf_of_encode_interfering_operator_pair_exclusion_is_i[simp]:
  "cnf (encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) = {{
    (Operator k (index (strips_problem.operators_of Π) op⇩1))¯
      , (Operator k (index (strips_problem.operators_of Π) op⇩2))¯ }}"
proof -
  let ?ops = "strips_problem.operators_of Π"
  have "cnf (encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2)
    = cnf (❙¬(Atom (Operator k (index ?ops op⇩1))) ❙∨ ❙¬(Atom (Operator k (index ?ops op⇩2))))"
    unfolding encode_interfering_operator_pair_exclusion_def
    by metis
  also have "… = { C ∪ D | C D.
    C ∈ cnf (❙¬(Atom (Operator k (index ?ops op⇩1))))
    ∧ D ∈ cnf (❙¬(Atom (Operator k (index ?ops op⇩2)))) }"
    by simp
  finally show ?thesis
    by auto
qed
lemma cnf_of_encode_interfering_operator_exclusion_is_ii[simp]:
  "set [encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2.
      (op⇩1, op⇩2) ← filter (λ(op⇩1, op⇩2).
          index (strips_problem.operators_of Π) op⇩1 ≠ index (strips_problem.operators_of Π) op⇩2
          ∧ are_operators_interfering op⇩1 op⇩2)
        (List.product (strips_problem.operators_of Π) (strips_problem.operators_of Π))
        , k ← [0..<t]]
    = (⋃(op⇩1, op⇩2)
        ∈ { (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π).
          index (strips_problem.operators_of Π) op⇩1 ≠ index (strips_problem.operators_of Π) op⇩2
          ∧ are_operators_interfering op⇩1 op⇩2 }.
      (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) ` {0..<t})"
proof -
  let ?ops = "strips_problem.operators_of Π"
  let ?interfering = "filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2
    ∧ are_operators_interfering op⇩1 op⇩2) (List.product ?ops ?ops)"
  let ?fs = "[encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2.
    (op⇩1, op⇩2) ← ?interfering, k ← [0..<t]]"
  have "set ?fs = ⋃(set
    ` (λ(op⇩1, op⇩2). map (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) [0..<t])
    ` (set (filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2 ∧ are_operators_interfering op⇩1 op⇩2)
      (List.product ?ops ?ops))))"
    unfolding set_concat set_map
    by blast
  
  also have "… = ⋃((λ(op⇩1, op⇩2).
      set (map (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) [0..<t]))
    ` (set (filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2 ∧ are_operators_interfering op⇩1 op⇩2)
      (List.product ?ops ?ops))))"
    unfolding image_comp[of
        set "λ(op⇩1, op⇩2). map (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) [0..<t]"]
      comp_apply
    by fast
  also have "… = ⋃((λ(op⇩1, op⇩2).
      (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) ` {0..<t})
    ` (set (filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2 ∧ are_operators_interfering op⇩1 op⇩2)
      (List.product ?ops ?ops))))"
    unfolding set_map[of _ "[0..<t]"] atLeastLessThan_upt[of 0 t]
    by blast
  also have "… = ⋃((λ(op⇩1, op⇩2).
      (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) ` {0..<t})
    ` (Set.filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2 ∧ are_operators_interfering op⇩1 op⇩2)
      (set (List.product ?ops ?ops))))"
    unfolding set_filter[of "λ(op⇩1, op⇩2). are_operators_interfering op⇩1 op⇩2" "List.product ?ops ?ops"]
    by force
  
  finally show ?thesis
    unfolding operators_of_def set_product[of ?ops ?ops]
    by fastforce
qed
lemma cnf_of_encode_interfering_operator_exclusion_is_iii[simp]:
  
  fixes Π :: "'variable strips_problem"
  shows "cnf ` set [encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2.
      (op⇩1, op⇩2) ← filter (λ(op⇩1, op⇩2).
          index (strips_problem.operators_of Π) op⇩1 ≠ index (strips_problem.operators_of Π) op⇩2
          ∧ are_operators_interfering op⇩1 op⇩2)
        (List.product (strips_problem.operators_of Π) (strips_problem.operators_of Π))
      , k ← [0..<t]]
    = (⋃(op⇩1, op⇩2)
        ∈ { (op⇩1, op⇩2) ∈ set (strips_problem.operators_of Π) × set (strips_problem.operators_of Π).
          index (strips_problem.operators_of Π) op⇩1 ≠ index (strips_problem.operators_of Π) op⇩2
          ∧ are_operators_interfering op⇩1 op⇩2 }.
      {{{ (Operator k (index (strips_problem.operators_of Π) op⇩1))¯
        , (Operator k (index (strips_problem.operators_of Π) op⇩2))¯ }} | k. k ∈ {0..<t}})"
proof -
  let ?ops = "strips_problem.operators_of Π"
  let ?interfering = "filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2
    ∧ are_operators_interfering op⇩1 op⇩2) (List.product ?ops ?ops)"
  let ?fs = "[encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2.
    (op⇩1, op⇩2) ← ?interfering, k ← [0..<t]]"
  have "cnf ` set ?fs = cnf ` (⋃(op⇩1, op⇩2) ∈ { (op⇩1, op⇩2).
    (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π) ∧ index ?ops op⇩1 ≠ index ?ops op⇩2
      ∧ are_operators_interfering op⇩1 op⇩2 }.
    (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) ` {0..<t})"
    unfolding cnf_of_encode_interfering_operator_exclusion_is_ii
    by blast
  also have "… = (⋃(op⇩1, op⇩2) ∈ { (op⇩1, op⇩2).
    (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π) ∧ index ?ops op⇩1 ≠ index ?ops op⇩2
      ∧ are_operators_interfering op⇩1 op⇩2 }.
    (λk. cnf (encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2)) ` {0..<t})"
    unfolding image_Un image_comp comp_apply
    by blast
  also have "… = (⋃(op⇩1, op⇩2) ∈ { (op⇩1, op⇩2).
    (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π) ∧ index ?ops op⇩1 ≠ index ?ops op⇩2
      ∧ are_operators_interfering op⇩1 op⇩2 }.
    (λk. {{ (Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯ }}) ` {0..<t})"
    by simp
  also have "… = (⋃(op⇩1, op⇩2) ∈ { (op⇩1, op⇩2).
    (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π) ∧ index ?ops op⇩1 ≠ index ?ops op⇩2
        ∧ are_operators_interfering op⇩1 op⇩2 }.
      (λk. {{ (Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯ }})
        ` { k | k. k ∈ {0..<t}})"
    by blast
  
  finally show ?thesis
    unfolding operators_of_def setcompr_eq_image[of _ "λk. k ∈ {0..<t}"]
    by force
qed
lemma cnf_of_encode_interfering_operator_exclusion_is:
  "cnf (encode_interfering_operator_exclusion Π t) = ⋃(⋃(op⇩1, op⇩2)
      ∈ { (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π).
        index (strips_problem.operators_of Π) op⇩1 ≠ index (strips_problem.operators_of Π) op⇩2
          ∧ are_operators_interfering op⇩1 op⇩2 }.
    {{{ (Operator k (index (strips_problem.operators_of Π) op⇩1))¯
      , (Operator k (index (strips_problem.operators_of Π) op⇩2))¯ }} | k. k ∈ {0..<t}})"
proof -
  let ?ops = "strips_problem.operators_of Π"
  let ?interfering = "filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2
    ∧ are_operators_interfering op⇩1 op⇩2) (List.product ?ops ?ops)"
  let ?fs = "[encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2.
    (op⇩1, op⇩2) ← ?interfering, k ← [0..<t]]"
  have "cnf (encode_interfering_operator_exclusion Π t) = cnf (foldr (❙∧) ?fs (❙¬⊥))"
    unfolding encode_interfering_operator_exclusion_def
    by metis
  also have "… = ⋃(cnf ` set ?fs)"
    unfolding cnf_foldr_and[of ?fs]..
  finally show ?thesis
    unfolding cnf_of_encode_interfering_operator_exclusion_is_iii[of Π t]
    by blast
qed
lemma cnf_of_encode_interfering_operator_exclusion_contains_clause_if:
  
  fixes Π :: "'variable strips_problem"
  assumes "k < t"
    and "op⇩1 ∈ set (strips_problem.operators_of Π)" and "op⇩2 ∈ set (strips_problem.operators_of Π)"
    and "index (strips_problem.operators_of Π) op⇩1 ≠ index (strips_problem.operators_of Π) op⇩2"
    and "are_operators_interfering op⇩1 op⇩2"
  shows "{ (Operator k (index (strips_problem.operators_of Π) op⇩1))¯
      , (Operator k (index (strips_problem.operators_of Π) op⇩2))¯}
    ∈ cnf (encode_interfering_operator_exclusion Π t)"
proof -
  let ?ops = "strips_problem.operators_of Π"
    and ?Φ⇩X = "encode_interfering_operator_exclusion Π t"
  let ?Ops = "{ (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π).
        index ?ops op⇩1 ≠ index ?ops op⇩2 ∧ are_operators_interfering op⇩1 op⇩2 }"
    and ?f = "λ(op⇩1, op⇩2). {{{ (Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯ }}
      | k. k ∈ {0..<t}}"
  let ?A = "(⋃(op⇩1, op⇩2) ∈ ?Ops. ?f (op⇩1, op⇩2))"
  let ?B = "⋃?A"
    and ?C = "{ (Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯ }"
  {
    have "(op⇩1, op⇩2) ∈ ?Ops"
      using assms(2, 3, 4, 5)
      unfolding operators_of_def
      by force
    moreover have "{ ?C } ∈ ?f (op⇩1, op⇩2)"
      using assms(1)
      by auto
    moreover have "{ ?C } ∈ ?A"
      using UN_iff[of ?C _ ?Ops] calculation(1, 2)
      by blast
    
    ultimately have "∃X ∈ ?A. ?C ∈ X"
      by auto
  }
  
  thus ?thesis
    unfolding cnf_of_encode_interfering_operator_exclusion_is
    using Union_iff[of ?C ?A]
    by auto
qed
lemma is_cnf_encode_interfering_operator_exclusion:
  
  fixes Π :: "'variable strips_problem"
  shows "is_cnf (encode_interfering_operator_exclusion Π t)"
proof -
  let ?ops = "strips_problem.operators_of Π"
  let ?interfering = "filter (λ(op⇩1, op⇩2). index ?ops op⇩1 ≠ index ?ops op⇩2
    ∧ are_operators_interfering op⇩1 op⇩2) (List.product ?ops ?ops)"
  let ?fs = "[encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2.
    (op⇩1, op⇩2) ← ?interfering, k ← [0..<t]]"
  let ?Fs = "(⋃(op⇩1, op⇩2)
        ∈ { (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π). are_operators_interfering op⇩1 op⇩2 }.
      (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) ` {0..<t})"
  {
    fix f
    assume "f ∈ set ?fs"
    then have "f ∈ ?Fs"
      unfolding cnf_of_encode_interfering_operator_exclusion_is_ii
      by blast
    then obtain op⇩1 op⇩2
      where "(op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π)"
      and "are_operators_interfering op⇩1 op⇩2"
      and "f ∈ (λk. encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2) ` {0..<t}"
      by fast
    then obtain k where "f = encode_interfering_operator_pair_exclusion Π k op⇩1 op⇩2"
      by blast
    then have "f = ❙¬(Atom (Operator k (index ?ops op⇩1))) ❙∨ ❙¬(Atom (Operator k (index ?ops op⇩2)))"
      unfolding encode_interfering_operator_pair_exclusion_def
      by metis
    hence "is_cnf f"
      by force
  }
  thus ?thesis
    unfolding encode_interfering_operator_exclusion_def
    using is_cnf_foldr_and_if[of ?fs]
    by meson
qed
lemma is_cnf_encode_problem_with_operator_interference_exclusion:
  assumes "is_valid_problem_strips Π"
  shows "is_cnf (Φ⇩∀ Π t)"
  using is_cnf_encode_problem is_cnf_encode_interfering_operator_exclusion assms
  unfolding encode_problem_with_operator_interference_exclusion_def SAT_Plan_Base.encode_problem_def
    is_cnf.simps(1)
  by blast
lemma cnf_of_encode_problem_with_operator_interference_exclusion_structure:
  shows "cnf (Φ⇩I Π) ⊆ cnf (Φ⇩∀ Π t)"
    and "cnf ((Φ⇩G Π) t) ⊆ cnf (Φ⇩∀ Π t)"
    and "cnf (encode_operators Π t) ⊆ cnf (Φ⇩∀ Π t)"
    and "cnf (encode_all_frame_axioms Π t) ⊆ cnf (Φ⇩∀ Π t)"
    and "cnf (encode_interfering_operator_exclusion Π t) ⊆ cnf (Φ⇩∀ Π t)"
  unfolding encode_problem_with_operator_interference_exclusion_def encode_problem_def SAT_Plan_Base.encode_problem_def
    encode_initial_state_def
    encode_goal_state_def
  by auto+
lemma encode_problem_with_operator_interference_exclusion_has_model_then_also_partial_encodings:
  assumes "𝒜 ⊨ Φ⇩∀ Π t"
  shows "𝒜 ⊨ SAT_Plan_Base.encode_initial_state Π"
    and "𝒜 ⊨ SAT_Plan_Base.encode_operators Π t"
    and "𝒜 ⊨ SAT_Plan_Base.encode_all_frame_axioms Π t"
    and "𝒜 ⊨ encode_interfering_operator_exclusion Π t"
    and "𝒜 ⊨ SAT_Plan_Base.encode_goal_state Π t"
  using assms
  unfolding encode_problem_with_operator_interference_exclusion_def encode_problem_def SAT_Plan_Base.encode_problem_def
  by simp+
text ‹ Just as for the basic SATPlan encoding we defined local context for the SATPlan encoding
with interfering operator exclusion. We omit this here since it is basically identical to the one
shown in the basic SATPlan theory replacing only the definitions of \isaname{encode_transitions}
and \isaname{encode_problem}. The sublocale proof is shown below. It confirms that the new
encoding again a CNF as required by locale \isaname{sat_encode_strips}. ›
subsection "Soundness"
text ‹ The Proof of soundness for the SATPlan encoding with interfering operator exclusion follows
directly from the proof of soundness of the basic SATPlan encoding. By looking at the structure of
the new encoding which simply extends the basic SATPlan encoding with a conjunct, any model for
encoding with exclusion of operator interference also models the basic SATPlan encoding and the
soundness of the new encoding therefore follows from theorem
\ref{isathm:soundness-satplan-encoding}.
Moreover, since we additionally added interfering operator exclusion clauses at every timestep, the
decoded parallel plan cannot contain any interfering operators in any parallel operator (making it
serializable). ›
lemma encode_problem_serializable_sound_i:
  assumes "is_valid_problem_strips Π"
    and "𝒜 ⊨ Φ⇩∀ Π t"
    and "k < t"
    and "ops ∈ set (subseqs ((Φ¯ Π 𝒜 t) ! k))"
  shows "are_all_operators_non_interfering ops"
proof -
  let ?ops = "strips_problem.operators_of Π"
    and ?π = "Φ¯ Π 𝒜 t"
    and ?Φ⇩X = "encode_interfering_operator_exclusion Π t"
  let ?π⇩k = "(Φ¯ Π 𝒜 t) ! k"
  
  {
    fix C
    assume C_in: "C ∈ cnf ?Φ⇩X"
    have "cnf_semantics 𝒜 (cnf ?Φ⇩X)"
      using cnf_semantics_monotonous_in_cnf_subsets_if[OF assms(2)
        is_cnf_encode_problem_with_operator_interference_exclusion[OF assms(1)]
        cnf_of_encode_problem_with_operator_interference_exclusion_structure(5)].
    hence "clause_semantics 𝒜 C"
      unfolding cnf_semantics_def
      using C_in
      by fast
  } note nb⇩1 = this
  {
    fix op⇩1 op⇩2
    assume "op⇩1 ∈ set ?π⇩k" and "op⇩2 ∈ set ?π⇩k"
      and index_op⇩1_is_not_index_op⇩2: "index ?ops op⇩1 ≠ index ?ops op⇩2"
    moreover have op⇩1_in: "op⇩1 ∈ set ?ops" and 𝒜_models_op⇩1:"𝒜 (Operator k (index ?ops op⇩1))"
      and op⇩2_in: "op⇩2 ∈ set ?ops" and 𝒜_models_op⇩2: "𝒜 (Operator k (index ?ops op⇩2))"
      using decode_plan_step_element_then[OF assms(3)] calculation
      unfolding decode_plan_def
      by blast+
    moreover {
      let ?C = "{ (Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯ }"
      assume "are_operators_interfering op⇩1 op⇩2"
      moreover have "?C ∈ cnf ?Φ⇩X"
        using cnf_of_encode_interfering_operator_exclusion_contains_clause_if[OF
            assms(3) op⇩1_in op⇩2_in index_op⇩1_is_not_index_op⇩2] calculation
        by blast
      moreover have "¬clause_semantics 𝒜 ?C"
        using 𝒜_models_op⇩1 𝒜_models_op⇩2
        unfolding clause_semantics_def
        by auto
      ultimately have False
        using nb⇩1
        by blast
    }
    ultimately have "¬are_operators_interfering op⇩1 op⇩2"
      by blast
  } note nb⇩3 = this
  show ?thesis
    using assms
    proof (induction ops)
      case (Cons op⇩1 ops)
      have "are_all_operators_non_interfering ops"
        using Cons.IH[OF Cons.prems(1, 2, 3) Cons_in_subseqsD[OF Cons.prems(4)]]
        by blast
      moreover {
        fix op⇩2
        assume op⇩2_in_ops: "op⇩2 ∈ set ops"
        moreover have op⇩1_in_π⇩k: "op⇩1 ∈ set ?π⇩k" and op⇩2_in_π⇩k: "op⇩2 ∈ set ?π⇩k"
          using element_of_subseqs_then_subset[OF Cons.prems(4)] calculation(1)
          by auto+
        moreover
        {
          have "distinct (op⇩1 # ops)"
            using subseqs_distinctD[OF Cons.prems(4)]
              decode_plan_step_distinct[OF Cons.prems(3)]
            unfolding decode_plan_def
            by blast
          moreover have "op⇩1 ∈ set ?ops" and "op⇩2 ∈ set ?ops"
            using decode_plan_step_element_then(1)[OF Cons.prems(3)] op⇩1_in_π⇩k op⇩2_in_π⇩k
            unfolding decode_plan_def
            by force+
          moreover have "op⇩1 ≠ op⇩2"
            using op⇩2_in_ops calculation(1)
            by fastforce
          ultimately have "index ?ops op⇩1 ≠ index ?ops op⇩2"
            using index_eq_index_conv
            by auto
        }
        ultimately have "¬are_operators_interfering op⇩1 op⇩2"
          using nb⇩3
          by blast
      }
      ultimately show ?case
        using list_all_iff
        by auto
    qed simp
qed
theorem encode_problem_serializable_sound:
  assumes "is_valid_problem_strips Π"
    and "𝒜 ⊨ Φ⇩∀ Π t"
  shows "is_parallel_solution_for_problem Π (Φ¯ Π 𝒜 t)"
    and "∀k < length (Φ¯ Π 𝒜 t). are_all_operators_non_interfering ((Φ¯ Π 𝒜 t) ! k)"
proof -
  {
    have "𝒜 ⊨ SAT_Plan_Base.encode_initial_state Π"
      and "𝒜 ⊨ SAT_Plan_Base.encode_operators Π t"
      and "𝒜 ⊨ SAT_Plan_Base.encode_all_frame_axioms Π t"
      and "𝒜 ⊨ SAT_Plan_Base.encode_goal_state Π t"
      using assms(2)
      unfolding encode_problem_with_operator_interference_exclusion_def
      by simp+
    then have "𝒜 ⊨ SAT_Plan_Base.encode_problem Π t"
      unfolding SAT_Plan_Base.encode_problem_def
      by simp
  }
  thus "is_parallel_solution_for_problem Π (Φ¯ Π 𝒜 t)"
    using encode_problem_parallel_sound assms(1, 2)
    unfolding decode_plan_def
    by blast
next
  let ?π = "Φ¯ Π 𝒜 t"
  {
    fix k
    assume "k < t"
    moreover have "?π ! k ∈ set (subseqs (?π ! k))"
      using subseqs_refl
      by blast
    ultimately have "are_all_operators_non_interfering (?π ! k)"
      using encode_problem_serializable_sound_i[OF assms]
      unfolding SAT_Plan_Base.decode_plan_def decode_plan_def
      by blast
  }
  moreover have "length ?π = t"
    unfolding SAT_Plan_Base.decode_plan_def decode_plan_def
    by simp
  ultimately show "∀k < length ?π. are_all_operators_non_interfering (?π ! k)"
    by simp
qed
subsection "Completeness"
lemma encode_problem_with_operator_interference_exclusion_complete_i:
  assumes "is_valid_problem_strips Π"
    and "is_parallel_solution_for_problem Π π"
    and "∀k < length π. are_all_operators_non_interfering (π ! k)"
  shows "valuation_for_plan Π π ⊨ encode_interfering_operator_exclusion Π (length π)"
proof -
  let ?𝒜 = "valuation_for_plan Π π"
    and ?Φ⇩X = "encode_interfering_operator_exclusion Π (length π)"
    and ?ops = "strips_problem.operators_of Π"
    and ?t = "length π"
  let ?τ = "trace_parallel_plan_strips ((Π)⇩I) π"
  let ?Ops = "{ (op⇩1, op⇩2). (op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π)
    ∧ index ?ops op⇩1 ≠ index ?ops op⇩2
    ∧ are_operators_interfering op⇩1 op⇩2 }"
    and ?f = "λ(op⇩1, op⇩2). {{{ (Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯ }}
      | k. k ∈ {0..<length π} }"
  let ?A = "⋃(?f ` ?Ops)"
  let ?B = "⋃?A"
  have nb⇩1: "∀ops ∈ set π. ∀op ∈ set ops. op ∈ set (operators_of Π)"
    using is_parallel_solution_for_problem_operator_set[OF assms(2)]
    unfolding operators_of_def
    by blast
  
  {
    fix k op
    assume "k < length π" and "op ∈ set (π ! k)"
    hence "lit_semantics ?𝒜 ((Operator k (index ?ops op))⇧+) = (k < length ?τ - 1)"
      using encode_problem_parallel_complete_vi_a[OF assms(2)]
        encode_problem_parallel_complete_vi_b[OF assms(2)] initial_of_def
      by(cases "k < length ?τ - 1"; simp)
  } note nb⇩2 = this
  {
    fix k op⇩1 op⇩2
    assume "k < length π"
      and "op⇩1 ∈ set (π ! k)"
      and "index ?ops op⇩1 ≠ index ?ops op⇩2"
      and "are_operators_interfering op⇩1 op⇩2"
    moreover have "are_all_operators_non_interfering (π ! k)"
      using assms(3) calculation(1)
      by blast
    moreover have "op⇩1 ≠ op⇩2"
      using calculation(3)
      by blast
    ultimately have "op⇩2 ∉ set (π ! k)"
      using are_all_operators_non_interfering_set_contains_no_distinct_interfering_operator_pairs
        assms(3)
      by blast
  } note nb⇩3 = this
  {
    fix C
    assume "C ∈ cnf ?Φ⇩X"
    then have "C ∈ ?B"
      using cnf_of_encode_interfering_operator_exclusion_is[of Π "length π"]
      by argo
    then obtain C' where "C' ∈ ?A" and C_in: "C ∈ C'"
      using Union_iff[of C ?A]
      by meson
    then obtain op⇩1 op⇩2 where "(op⇩1, op⇩2) ∈ set (operators_of Π) × set (operators_of Π)"
      and index_op⇩1_is_not_index_op⇩2: "index ?ops op⇩1 ≠ index ?ops op⇩2"
      and are_operators_interfering_op⇩1_op⇩2: "are_operators_interfering op⇩1 op⇩2"
      and C'_in: "C' ∈ {{{(Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯}}
        | k. k ∈ {0..<length π}}"
      using UN_iff[of C' ?f ?Ops]
      by blast
    then obtain k where "k ∈ {0..<length π}"
      and C_is: "C = { (Operator k (index ?ops op⇩1))¯, (Operator k (index ?ops op⇩2))¯ }"
      using C_in C'_in
      by blast
    then have k_lt_length_π: "k < length π"
      by simp
    consider (A) "op⇩1 ∈ set (π ! k)"
     | (B) "op⇩2 ∈ set (π ! k)"
     | (C) "¬op⇩1 ∈ set (π ! k) ∨ ¬op⇩2 ∈ set (π ! k)"
      by linarith
    hence "clause_semantics ?𝒜 C"
      proof (cases)
        case A
        moreover have "op⇩2 ∉ set (π ! k)"
          using nb⇩3 k_lt_length_π calculation index_op⇩1_is_not_index_op⇩2 are_operators_interfering_op⇩1_op⇩2
          by blast
        moreover have "¬?𝒜 (Operator k (index ?ops op⇩2))"
          using encode_problem_parallel_complete_vi_d[OF assms(2) k_lt_length_π]
            calculation(2)
          by blast
        ultimately show ?thesis
          using C_is
          unfolding clause_semantics_def
          by force
      next
        case B
        moreover have "op⇩1 ∉ set (π ! k)"
          using nb⇩3 k_lt_length_π calculation index_op⇩1_is_not_index_op⇩2 are_operators_interfering_op⇩1_op⇩2
          by blast
        moreover have "¬?𝒜 (Operator k (index ?ops op⇩1))"
          using encode_problem_parallel_complete_vi_d[OF assms(2) k_lt_length_π]
            calculation(2)
          by blast
        ultimately show ?thesis
          using C_is
          unfolding clause_semantics_def
          by force
      next
        case C
        then show ?thesis
          proof (rule disjE)
            assume "op⇩1 ∉ set (π ! k)"
            then have "¬?𝒜 (Operator k (index ?ops op⇩1))"
              using encode_problem_parallel_complete_vi_d[OF assms(2) k_lt_length_π]
              by blast
            thus "clause_semantics (valuation_for_plan Π π) C"
              using C_is
              unfolding clause_semantics_def
              by force
          next
            assume "op⇩2 ∉ set (π ! k)"
            then have "¬?𝒜 (Operator k (index ?ops op⇩2))"
              using encode_problem_parallel_complete_vi_d[OF assms(2) k_lt_length_π]
              by blast
            thus "clause_semantics (valuation_for_plan Π π) C"
              using C_is
              unfolding clause_semantics_def
              by force
          qed
      qed
  }
  then have "cnf_semantics ?𝒜 (cnf ?Φ⇩X)"
    unfolding cnf_semantics_def..
  thus ?thesis
    using cnf_semantics[OF is_nnf_cnf[OF is_cnf_encode_interfering_operator_exclusion]]
    by fast
qed
text ‹ Similar to the soundness proof, we may reuse the previously established
facts about the valuation for the completeness proof of the basic SATPlan encoding
(\ref{isathm:completeness-satplan-encoding}).
To make it clearer why this is true we have a look at the form of the clauses for interfering operator
pairs \<^term>‹op⇩1› and \<^term>‹op⇩2› at the same time index \<^term>‹k› which have the form shown below:
  @{text[display, indent=4] "{ (Operator k (index ops op⇩1))¯, (Operator k (index ops op⇩2))¯ }"}
where \<^term>‹ops ≡ strips_problem.operators_of Π›.
Now, consider an operator \<^term>‹op⇩1› that is contained in the \<^term>‹k›-th plan step \<^term>‹π ! k›
(symmetrically for \<^term>‹op⇩2›). Since \<^term>‹π› is a serializable solution, there can be no
interference between \<^term>‹op⇩1› and \<^term>‹op⇩2› at time \<^term>‹k›. Hence \<^term>‹op⇩2› cannot be in \<^term>‹π ! k›
This entails that for \<^term>‹𝒜 ≡ valuation_for_plan Π π› it holds that
  @{text[display, indent=4] "𝒜 ⊨ ❙¬ Atom (Operator k (index ops op⇩2))"}
and \<^term>‹𝒜› therefore models the clause.
Furthermore, if neither is present, than \<^term>‹𝒜› will evaluate both atoms to false and the clause
therefore evaluates to true as well.
It follows from this that each clause in the extension of the SATPlan encoding evaluates to true
for \<^term>‹𝒜›. The other parts of the encoding evaluate to true as per the completeness of the
basic SATPlan encoding (theorem \ref{isathm:completeness-satplan-encoding}).›
theorem encode_problem_serializable_complete:
  assumes "is_valid_problem_strips Π"
    and "is_parallel_solution_for_problem Π π"
    and "∀k < length π. are_all_operators_non_interfering (π ! k)"
  shows "valuation_for_plan Π π ⊨ Φ⇩∀ Π (length π)"
proof -
  let ?𝒜 = "valuation_for_plan Π π"
    and ?Φ⇩X = "encode_interfering_operator_exclusion Π (length π)"
  have "?𝒜 ⊨ SAT_Plan_Base.encode_problem Π (length π)"
    using assms(1, 2) encode_problem_parallel_complete
    by auto
  moreover have "?𝒜 ⊨ ?Φ⇩X"
    using encode_problem_with_operator_interference_exclusion_complete_i[OF assms].
  ultimately show ?thesis
    unfolding encode_problem_with_operator_interference_exclusion_def encode_problem_def
      SAT_Plan_Base.encode_problem_def
    by force
qed
value  "stop" 
lemma encode_problem_forall_step_decoded_plan_is_serializable_i:
  assumes "is_valid_problem_strips Π"
    and "𝒜 ⊨ Φ⇩∀ Π t"
  shows "(Π)⇩G ⊆⇩m execute_serial_plan ((Π)⇩I) (concat (Φ¯ Π 𝒜 t))"
proof -
  let ?G = "(Π)⇩G"
    and ?I = "(Π)⇩I"
    and ?π = "Φ¯ Π 𝒜 t"
  let ?π' = "concat (Φ¯ Π 𝒜 t)"
    and ?τ = "trace_parallel_plan_strips ?I ?π"
    and ?σ = "map (decode_state_at Π 𝒜) [0..<Suc (length ?π)]"
  {
    fix k
    assume k_lt_length_π: "k < length ?π"
    moreover have "𝒜 ⊨ SAT_Plan_Base.encode_problem Π t"
      using assms(2)
      unfolding encode_problem_with_operator_interference_exclusion_def
        encode_problem_def SAT_Plan_Base.encode_problem_def
      by simp
    moreover have "length ?σ = length ?τ"
      using encode_problem_parallel_correct_vii assms(1) calculation
      unfolding decode_state_at_def decode_plan_def initial_of_def
      by fast
    ultimately have "k < length ?τ - 1" and "k < t"
      unfolding decode_plan_def SAT_Plan_Base.decode_plan_def
      by force+
  } note nb = this
  {
    have "?G ⊆⇩m execute_parallel_plan ?I ?π"
      using encode_problem_serializable_sound assms
      unfolding is_parallel_solution_for_problem_def decode_plan_def
        goal_of_def initial_of_def
      by blast
    hence "?G ⊆⇩m last (trace_parallel_plan_strips ?I ?π)"
      using execute_parallel_plan_reaches_goal_iff_goal_is_last_element_of_trace
      by fast
  }
  moreover {
    fix k
    assume k_lt_length_π: "k < length ?π"
    moreover have "k < length ?τ - 1" and "k < t"
      using nb calculation
      by blast+
    moreover have "are_all_operators_applicable (?τ ! k) (?π ! k)"
      and "are_all_operator_effects_consistent (?π ! k)"
      using trace_parallel_plan_strips_operator_preconditions calculation(2)
      by blast+
    moreover have "are_all_operators_non_interfering (?π ! k)"
      using encode_problem_serializable_sound(2)[OF assms(1, 2)] k_lt_length_π
      by blast
    ultimately have "are_all_operators_applicable (?τ ! k) (?π ! k)"
      and "are_all_operator_effects_consistent (?π ! k)"
      and "are_all_operators_non_interfering (?π ! k)"
      by blast+
  }
  ultimately show ?thesis
    using execute_parallel_plan_is_execute_sequential_plan_if assms(1)
    by metis
qed
lemma encode_problem_forall_step_decoded_plan_is_serializable_ii:
  
  fixes Π :: "'variable strips_problem"
  shows "list_all (λop. ListMem op (strips_problem.operators_of Π))
    (concat (Φ¯ Π 𝒜 t))"
proof -
  let ?π = "Φ¯ Π 𝒜 t"
  let ?π' = "concat ?π"
  
  {
    have "set ?π' = ⋃(set `  (⋃k < t. { decode_plan' Π 𝒜 k }))"
      unfolding decode_plan_def decode_plan_set_is set_concat
      by auto
    also have "… = ⋃(⋃k < t. { set (decode_plan' Π 𝒜 k) })"
      by blast
    finally have "set ?π' = (⋃k < t. set (decode_plan' Π 𝒜 k))"
      by blast
  } note nb = this
  {
    fix op
    assume "op ∈ set ?π'"
    then obtain k where "k < t" and "op ∈ set (decode_plan' Π 𝒜 k)"
      using nb
      by blast
    moreover have "op ∈ set (decode_plan Π 𝒜 t ! k)"
      using calculation
      unfolding decode_plan_def SAT_Plan_Base.decode_plan_def
      by simp
    ultimately have "op ∈ set (operators_of Π)"
      using decode_plan_step_element_then(1)
      unfolding operators_of_def decode_plan_def
      by blast
  }
  thus ?thesis
    unfolding list_all_iff ListMem_iff operators_of_def
    by blast
qed
text ‹ Given the soundness and completeness of the SATPlan encoding with interfering operator
exclusion \<^term>‹Φ⇩∀ Π t›, we can
now conclude this part with showing that for a parallel plan \<^term>‹π ≡ Φ¯ Π 𝒜 t›
that was decoded from a model \<^term>‹𝒜› of \<^term>‹Φ⇩∀ Π t› the serialized plan
\<^term>‹π' ≡ concat π› is a serial solution for \<^term>‹Π›. To this end, we have to show that
\begin{itemize}
  \item the state reached by serial execution of \<^term>‹π'› subsumes \<^term>‹G›, and
  \item all operators in \<^term>‹π'› are operators contained in \<^term>‹𝒪›.
\end{itemize}
While the proof of the latter step is rather straight forward, the proof for the
former requires a bit more work. We use the previously established theorem on serial and parallel
STRIPS equivalence (theorem \ref{isathm:equivalence-parallel-serial-strips-plans}) to show the
serializability of \<^term>‹π› and therefore have to show that \<^term>‹G› is subsumed by the last state
of the trace of \<^term>‹π'›
  @{text[display, indent=4] "G ⊆⇩m last (trace_sequential_plan_strips I π')"}
and moreover that at every step of the parallel plan execution, the parallel operator execution
condition as well as non interference are met
  @{text[display, indent=4] "∀k < length π. are_all_operators_non_interfering (π ! k)"}.
\footnote{These propositions are shown in lemmas \texttt{encode\_problem\_forall\_step\_decoded\_plan\_is\_serializable\_ii} and
\texttt{encode\_problem\_forall\_step\_decoded\_plan\_is\_serializable\_i} which have been omitted for
brevity.}
Note that the parallel operator execution condition is implicit in the existence of the parallel
trace for \<^term>‹π› with
  @{text[display, indent=4] "G ⊆⇩m last (trace_parallel_plan_strips I π)"}
warranted by the soundness of \<^term>‹Φ⇩∀ Π t›. ›
theorem serializable_encoding_decoded_plan_is_serializable:
  assumes "is_valid_problem_strips Π"
    and "𝒜 ⊨ Φ⇩∀ Π t"
  shows "is_serial_solution_for_problem Π (concat (Φ¯ Π 𝒜 t))"
  using encode_problem_forall_step_decoded_plan_is_serializable_i[OF assms]
    encode_problem_forall_step_decoded_plan_is_serializable_ii
  unfolding is_serial_solution_for_problem_def goal_of_def
    initial_of_def decode_plan_def
  by blast
end