Theory IDE_CP_Core

chapter ‹Integrated Deduction Environment for Programming (IDE-P)›

theory IDE_CP_Core
  imports Phi_BI.Phi_BI Phi_Element_Path
  keywords
    "proc" :: thy_goal_stmt
  and "as" "→" "⟼" "←" "^" "^*" "⟸" "⟸'" "$" "subj"
    "var" "val" "invar" "⟹" "@tag" "∃" "throws" "holds_fact"
    "input" "certified" "apply_rule" "]." ")." ".$" "!."
      :: quasi_command
  and "❴" :: prf_goal % "proof"
  and ";;" ";" :: prf_goal % "proof"
  and "❵" :: prf_goal % "proof"
  and "φlang_parser" :: thy_decl % "ML"
  and (* "φinterface" "φexport_llvm" *) "φoverloads" "declare_φlang_operator" :: thy_decl
abbrevs
  "!!" = "!!"
  and "<label>" = "𝗅𝖺𝖻𝖾𝗅"
  and "<by>" = "by"
  and "<try>" = "try"
  and "<obligation>" = "𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇"
  and ">->" = "↣"
  and "<;>" = "⨾"
  and "<val>" = "𝗏𝖺𝗅"
  and "<ret>" = "ret"
  and "<is>" = "𝗂𝗌"
  and "|>" = "‣"
  and "<-" = "←"
  and "←->" = "⟷"
  and ";;" = ";"
begin

section ‹Preliminary Configuration›

named_theorems φlemmata ‹Contextual facts during the programming. They are automatically
       aggregated from every attached prop‹P› in prop‹𝖼𝗎𝗋𝗋𝖾𝗇𝗍 blk in [R] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 Sth 𝗌𝗎𝖻𝗃 P›
       during the programming. Do not modify it manually because it is managed automatically and
       cleared frequently›

subsubsection ‹Syntax \& Prelude ML›

ML_file ‹library/syntax/Phi_Syntax.ML›
ML_file ‹library/syntax/procedure2.ML›

section ‹Antecedent Jobs \& Annotations in Sequents›

subsection ‹Text Label›

text ‹This part presents a mechanism to encode text symbol inside sequent.
  It may be used anywhere needing some text annotation for any purpose.›

paragraph ‹Label tag› text ‹embeds any text string in the name of a lambda abstraction from
  typunit to typunit, i.e. term ‹Abs ("embeded text", unit, Bound 0)› if readers are familiar with
  the internal representation of terms in Isabelle.

  This way encodes text strings using machine string which reaches the optimal performance.
  A deficiency is it is unstable for α-conversion. Fortunately, α-conversion doesn't happen during
  the unification with a schematic variable, although the unification with another label makes
  the result undecidable.
›

datatype label = LABEL_TAG "unit  unit"

lemma [cong]: "LABEL_TAG x  LABEL_TAG x"  using reflexive .
lemma label_eq: "x = y" for x :: label by (cases x, cases y) auto
syntax "_LABEL_" :: "idt  label" ("LABEL _" [0] 1000)
translations "LABEL name" == "CONST LABEL_TAG (λname. ())"


paragraph ‹Label Input› (*deprecated*)

definition LabelTag :: " label  bool" ("𝗅𝖺𝖻𝖾𝗅 _" [1000] 26) where "𝗅𝖺𝖻𝖾𝗅 x  True"

text ‹The term𝗅𝖺𝖻𝖾𝗅 x indicate termx is a typlabel that should be set by user, e.g.,
  prop𝗅𝖺𝖻𝖾𝗅 name  do_something_relating name.
  The φ-processor `set_label` processes the term𝗅𝖺𝖻𝖾𝗅 x antecedent.›

lemma LabelTag: "𝗅𝖺𝖻𝖾𝗅 x" unfolding LabelTag_def ..


paragraph ‹Label Binding of Objects›

definition Labelled :: "label  'a::{}  'a" where [iff]: "Labelled name x  x"

lemma Labelled_def_sym: x::'a::{}  Labelled name x unfolding Labelled_def .
lemma Labelled_I': PROP P  PROP (Labelled name (PROP P)) unfolding Labelled_def .
lemma Labelled_I : P  PROP Trueprop (Labelled name P) unfolding Labelled_def .

syntax "_LABELED_" :: "idt  logic  logic" ("_:/ (_)" [1000,11] 10)
translations "name: X" == "CONST Labelled (LABEL name) X"

syntax "_LABELED_PROP_" :: "idt  prop  prop" ("_:/ (_)" [1000,11] 10)
translations "_LABELED_PROP_ name X" => "CONST Labelled (LABEL name) X"

ML_file ‹library/syntax/label.ML›
ML_file ‹library/tools/named_premises.ML›


definition Labelled_embed :: "label  bool  bool" where "Labelled_embed name x  x"

lemma [iso_atomize_rules, symmetric, iso_rulify_rules]:
  Labelled L (Trueprop P)  Trueprop (Labelled_embed L P)
  unfolding Labelled_embed_def Labelled_def .

subsection ‹General Syntax›

subsubsection ‹Technical Tag›

text ‹A general syntactic tag used for hiding internal things.›

definition Technical :: 'a::{}  'a ("TECHNICAL _" [18] 17) where Technical x  x
  ― ‹TODO: Unify all tags›


lemma Technical_I : P  Technical P unfolding Technical_def .
lemma Technical_I': PROP P  PROP Technical P unfolding Technical_def .
lemma Technical_D : Technical P  P unfolding Technical_def .
lemma Technical_D': PROP Technical P  PROP P unfolding Technical_def .

optional_translation_group φhide_techinicals
  ‹Hides internal techinical constructions›
 
optional_translations (φhide_techinicals)
  ("aprop") "Y" <= ("aprop") "(CONST Pure.imp) (CONST Trueprop (CONST Technical X)) Y"
  ("aprop") "Y" <= ("aprop") "(CONST Pure.imp) (CONST Trueprop (name: CONST Technical X)) Y"
  ("aprop") "Y" <= ("aprop") "(CONST Pure.imp) (CONST Technical X) Y"
  ("aprop") "Y" <= ("aprop") "(CONST Pure.imp) (name: CONST Technical X) Y"
  "L" <= "CONST Technical X L"
  "R" <= "R  CONST Technical X"
  "R L" <= "R  CONST Technical X L"
  "𝖼𝗎𝗋𝗋𝖾𝗇𝗍 𝗌𝗍𝖺𝗍𝖾: XCONST Void" <= "𝖼𝗎𝗋𝗋𝖾𝗇𝗍 𝗌𝗍𝖺𝗍𝖾: TECHNICAL X"
  "𝖼𝗎𝗋𝗋𝖾𝗇𝗍 𝗏𝗂𝖾𝗐: XCONST Void" <= "𝖼𝗎𝗋𝗋𝖾𝗇𝗍 𝗏𝗂𝖾𝗐: TECHNICAL X"

declare [[φhide_techinicals,
          φpremise_attribute [THEN Technical_D ] for Technical ?P       (%φattr_normalize),
          φpremise_attribute [THEN Technical_D'] for PROP Technical ?P  (%φattr_normalize) ]]

definition Technical_embed :: bool  bool where Technical_embed X  X

lemma [iso_atomize_rules, symmetric, iso_rulify_rules]:
  Technical (Trueprop P)  Trueprop (Technical_embed P)
  unfolding Technical_def Technical_embed_def .

lemma [φreason 1000]:
  X 𝗂𝗆𝗉𝗅𝗂𝖾𝗌 C
 TECHNICAL X 𝗂𝗆𝗉𝗅𝗂𝖾𝗌 C
  unfolding Technical_def .

lemma [φreason 1000]:
  C 𝗌𝗎𝖿𝖿𝗂𝖼𝖾𝗌 X
 C 𝗌𝗎𝖿𝖿𝗂𝖼𝖾𝗌 TECHNICAL X
  unfolding Technical_def .

paragraph ‹Reasoning Rules›

lemma [φreason 1200]:
  Identity_ElementI X P
 Identity_ElementI (TECHNICAL X) P
  unfolding Technical_def .

lemma [φreason 1200]:
  Identity_ElementE X
 Identity_ElementE (TECHNICAL X)
  unfolding Technical_def .



ML_file ‹library/system/reasoners.ML›


subsection ‹Annotations on φ-Types›

typedecl struct_tag

definition Struct_Tag :: 'a BI  struct_tag  'a BI ("__" [17,17] 16)
  where Struct_Tag S tg  S

text ‹In a ToA like termx  TA𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 y  UA , termx  TA represents the
  termx  T may come from a larger structure A› containing it, and after the transformation,
  it hints the system to put termy  U back to the original position of termx  T in A›.

  It is useful when we access or modify a field in a complex structure, and the original structure
  of A› will not be broken after the access.
›

subsubsection ‹Implementation›

definition Changes_To :: 'a BI  ('b,'c) φ  'a BI (infix "<changes-to>" 16)
  where (S <changes-to> _) = S

definition Auto_Transform_Hint :: 'b BI  'a BI  bool
  where Auto_Transform_Hint residue result = True



subsection ‹Programming Modes›

typedecl working_mode

consts working_mode_procedure   :: working_mode
       working_mode_implication :: working_mode
       working_mode_view_shift  :: working_mode

definition φProgramming_Method :: prop  working_mode  prop  prop  prop  prop
  where φProgramming_Method Target mode Programming_Deduction Post_Reasoning Future_Works
           (   PROP Programming_Deduction
             PROP Post_Reasoning
             PROP Future_Works
             PROP Target)

declare [[φreason_default_pattern
      PROP φProgramming_Method ?T _ _ _ _  PROP φProgramming_Method ?T _ _ _ _ (100)
]]

φreasoner_group φprogramming_method = (1000, [1000,1999])
  for PROP φProgramming_Method Target mode Programming_Deduction Post_Reasoning Future_Works
  ‹Rules indicating how to derive the given property ‹Target›, under what ‹mode›, with what reasoning
   goals ‹Post_Reasoning› to be processed using φ-LPR after the programming, and with what remaining
   goals ‹Future_Works› presenting to the user to be processed later.
   The Programming_Deduction have to be in Harrop form:
      ‹⋀xs. premses ⟹ conclsion›
   where ‹xs› are local variables to be fixed, ‹premises› are local assumptions which can be prefixed
   by ‹name:› (see const‹Labelled›) giving the name binding the premise. Among the premises, there
   must be one of name ‹φ𝗂𝗇𝗂𝗍𝗂𝖺𝗅› which is the initial sequent of user deduction. From the inital sequent,
   users are expected to deduce the conclusion proposition.

   Any rule specifying programming methods should be cutting.
›

lemma reason_programming:
  PROP φProgramming_Method Target working_mode Programming_Deduction Post_Reasoning Future_Works
 TERM working_mode
 PROP Programming_Deduction
 PROP Post_Reasoning
 PROP Future_Works
 PROP Target
  unfolding φProgramming_Method_def
  subgoal premises prems using prems(1)[OF prems(3) prems(4) prems(5)] . .

ML_file ‹library/system/Phi_Working_Mode.ML›
ML_file ‹library/system/Phi_Envir.ML›

hide_fact introduce_Ex_ToA_subj_P introduce_Ex_ToA_subj introduce_Ex_ToA
          introduce_Ex_pending_E introduce_Ex_pending introduce_Ex_subj introduce_Ex


subsubsection ‹General Rules Normalizing Programming Methods›

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method G1 M D R F
 PROP φProgramming_Method (PROP G1 &&& PROP G2) M D R (PROP F &&& PROP G2)
  unfolding φProgramming_Method_def conjunction_imp
  by (rule conjunctionI)

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method (Trueprop Q) M D R F
 PROP φProgramming_Method (Trueprop (P  Q)) M (P  PROP D) (P  PROP R) (P  PROP F)
  unfolding φProgramming_Method_def
proof (intro impI)
  assume A: PROP D  PROP R  PROP F  Q
    and  D: P  PROP D
    and  R: P  PROP R
    and  F: P  PROP F
    and  P: P
  show Q using A[OF D[OF P] R[OF P] F[OF P]] .
qed

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method Q M D R F
 PROP φProgramming_Method (PROP P  PROP Q) M (PROP P  PROP D) (PROP P  PROP R)
                             (PROP P  PROP F)
  unfolding φProgramming_Method_def
proof -
  assume A: PROP D  PROP R  PROP F  PROP Q
    and  D: PROP P  PROP D
    and  R: PROP P  PROP R
    and  F: PROP P  PROP F
    and  P: PROP P
  show PROP Q using A[OF D[OF P] R[OF P] F[OF P]] .
qed

lemma φProgramming_Method_All:
  (x. PROP φProgramming_Method (Trueprop (P x)) M (D x) (R x) (F x))
 PROP φProgramming_Method (Trueprop (All P)) M (x. PROP D x) (x. PROP R x) (x. PROP F x)
  unfolding φProgramming_Method_def
proof (intro allI)
  fix x :: 'a
  assume A: x. PROP D x  PROP R x  PROP F x  P x
    and  D: x. PROP D x
    and  R: x. PROP R x
    and  F: x. PROP F x
  show P x using A[OF D R F] .
qed

lemma φProgramming_Method_ALL:
  (x. PROP φProgramming_Method (P x) M (D x) (R x) (F x))
 PROP φProgramming_Method (x. PROP P x) M (x. PROP D x) (x. PROP R x) (x. PROP F x)
  unfolding φProgramming_Method_def
proof -
  fix x :: 'a
  assume A: x. PROP D x  PROP R x  PROP F x  PROP P x
    and  D: x. PROP D x
    and  R: x. PROP R x
    and  F: x. PROP F x
  show PROP P x using A[OF D R F] .
qed

φreasoner_ML φProgramming_Method (Trueprop (All P)) 1000
  (PROP φProgramming_Method (Trueprop (All ?P)) _ _ _ _)
  = fn (_, (ctxt,sequent)) =>
  let val _ $ (_ $ (_ $ P)) $ _ $ _ $ _ $ _ = Thm.major_prem_of sequent
      fun rename N' (Abs ("x",T,X)) = Abs (N',T,X)
        | rename N' (X $ Y) = rename N' X $ rename N' Y
        | rename _ X = X
      val rule = @{thm φProgramming_Method_All}
      val rule' = case P of Abs (N,_,_) => Thm.renamed_prop (rename N (Thm.prop_of rule)) rule
                          | _ => rule
  in Phi_Reasoners.wrap (Phi_Reasoner.single_RS rule') (ctxt,sequent)
  end

φreasoner_ML φProgramming_Method (Pure.all P) 1000
  (PROP φProgramming_Method (Pure.all ?P) _ _ _ _)
  = fn (_, (ctxt,sequent)) =>
  let val _ $ (_ $ P) $ _ $ _ $ _ $ _ = Thm.major_prem_of sequent
      fun rename N' (Abs ("x",T,X)) = Abs (N',T,X)
        | rename N' (X $ Y) = rename N' X $ rename N' Y
        | rename _ X = X
      val rule = @{thm φProgramming_Method_ALL}
      val rule' = case P of Abs (N,_,_) => Thm.renamed_prop (rename N (Thm.prop_of rule)) rule
                          | _ => rule
  in Phi_Reasoners.wrap (Phi_Reasoner.single_RS rule') (ctxt,sequent)
  end

hide_fact φProgramming_Method_All φProgramming_Method_ALL


subsubsection ‹Built-in Programming Methods›

paragraph ‹Transformation›

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method
            (Trueprop (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P))
            working_mode_implication
            (ℭc. φ𝗂𝗇𝗂𝗍𝗂𝖺𝗅: (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(ℭc) 𝗂𝗌 X)  𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(ℭc) 𝗂𝗌 Y 𝗌𝗎𝖻𝗃 P)
            (Trueprop True)
            (Trueprop True)
  unfolding φProgramming_Method_def conjunction_imp all_conjunction Action_Tag_def
            Labelled_def
  using φmake_implication .

paragraph ‹View Shift›

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method
            (Trueprop (X 𝗌𝗁𝗂𝖿𝗍𝗌 Y 𝗐𝗂𝗍𝗁 P))
            working_mode_view_shift
            (ℭc ℜr. φ𝗂𝗇𝗂𝗍𝗂𝖺𝗅: (𝗏𝗂𝖾𝗐 ℭc [ℜr] 𝗂𝗌 X)  𝗏𝗂𝖾𝗐 ℭc [ℜr] 𝗂𝗌 Y 𝗌𝗎𝖻𝗃 P)
            (Trueprop True)
            (Trueprop True)
  unfolding φProgramming_Method_def conjunction_imp all_conjunction Action_Tag_def Labelled_def
  using φmake_view_shift .

(* I think we can allow users to still deduce some pure facts?
lemma [φreason 1100 for ‹PROP φProgramming_Method (Trueprop (?X 𝗌𝗁𝗂𝖿𝗍𝗌 ?Y 𝗐𝗂𝗍𝗁 ?var_P)) _ _ _ _›]:
  ‹ PROP φProgramming_Method
            (Trueprop (X 𝗌𝗁𝗂𝖿𝗍𝗌 Y))
            working_mode_view_shift
            (⋀ℭc ℜr. φ𝗂𝗇𝗂𝗍𝗂𝖺𝗅: (𝗏𝗂𝖾𝗐 ℭc [ℜr] 𝗂𝗌 X) ⟹ 𝗏𝗂𝖾𝗐 ℭc [ℜr] 𝗂𝗌 Y 𝗌𝗎𝖻𝗃 True)
            (Trueprop True)
            (Trueprop True)›
  unfolding φProgramming_Method_def conjunction_imp all_conjunction Action_Tag_def Labelled_def
  using φmake_view_shift . *)

paragraph ‹Procedure›

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method
            (Trueprop (𝗉𝗋𝗈𝖼 G  X  Y  𝗍𝗁𝗋𝗈𝗐𝗌 E))
            working_mode_procedure
            (𝔖s ℜr. φ𝗂𝗇𝗂𝗍𝗂𝖺𝗅: (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 𝔖s [ℜr] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 X)  𝗉𝖾𝗇𝖽𝗂𝗇𝗀 G 𝗈𝗇 𝔖s [ℜr] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 Y 𝗍𝗁𝗋𝗈𝗐𝗌 E)
            (Trueprop True)
            (Trueprop True)
  unfolding φProgramming_Method_def conjunction_imp all_conjunction Action_Tag_def Labelled_def
  using φreassemble_proc_final .

hide_fact φmake_implication φmake_view_shift φreassemble_proc_final


paragraph ‹Object_Equiv›

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method (x y. 𝗉𝗋𝖾𝗆𝗂𝗌𝖾 eq x y  x  T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 y  T) M D R F
 PROP φProgramming_Method (Trueprop (Object_Equiv T eq)) M D R ((x. eq x x) &&& PROP F)
  unfolding φProgramming_Method_def Object_Equiv_def Premise_def conjunction_imp
  by clarsimp

paragraph ‹Identity Element›

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method (Trueprop (A 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 1 𝗐𝗂𝗍𝗁 P)) M D R F
 PROP φProgramming_Method (Trueprop (Identity_ElementI A P)) M D R F
  unfolding φProgramming_Method_def Identity_ElementI_def
  by simp

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method (Trueprop (1 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 A)) M D R F
 PROP φProgramming_Method (Trueprop (Identity_ElementE A)) M D R F
  unfolding φProgramming_Method_def Identity_ElementE_def
  by simp

paragraph ‹Is_Functional›

context begin

private lemma Is_Functional_imp'':
  S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S' 𝗐𝗂𝗍𝗁 Is_Functional S'
 Is_Functional S
  unfolding Transformation_def Is_Functional_def
  by blast

lemma [φreason %φprogramming_method]:
  PROP φProgramming_Method (Trueprop (S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S' 𝗌𝗎𝖻𝗃-𝗋𝖾𝖺𝗌𝗈𝗇𝗂𝗇𝗀 Is_Functional S')) M D R F
 Friendly_Help TEXT(‹Hi! You are trying to show› S ‹is functional›
      ‹Now you entered the programming mode and you need to transform the specification to›
      ‹someone which is functional, so that we can verify your claim.›)
 PROP φProgramming_Method (Trueprop (Is_Functional S)) M D R F
  unfolding φProgramming_Method_def  ToA_Construction_def conjunction_imp
            Subj_Reasoning_def
  by (rule Is_Functional_imp''[where S'=S']; simp)

end


subsection ‹Automation›

named_theorems φsledgehammer_simps ‹Simplification rules used before applying slegehammer automation›

ML_file ‹library/tools/sledgehammer_solver.ML›


subsection ‹Ad-hoc Overload›

ML_file ‹library/system/app_rules.ML›

φoverloads cast

text ‹
Convention of Overloading Distance:

 0. Transparent, the matching is perfect.
 1. Almost Transparent, but still incomparable to the really transparent, meaning tiny cost still
      exists, maybe in time or reasoning only
 3. Expected Conversion: some conversion and therefore information lost is inevitable but it is
      expected so can be accepted.
 5. Less Expected Conversion: in some (rare) case the information lost can be severe
        but generally still can be accepted for most of usages.
 9. Slightly Aggressive.
 12. Aggressive in most of the situations.
 15. Bad.

Threshold Cost Always!
›

subsection ‹Synthesis›

text ‹The synthesis involves not only making a program but also finding a view shift or a ToA.

Given a target assertion X› intended to be synthesized,
on a ready state of a construction like 𝖼𝗎𝗋𝗋𝖾𝗇𝗍 blk [H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 S› or (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S)›,
the mechanism synthesizes programs or deduces ToA to deduce the state sequent into
 𝖼𝗎𝗋𝗋𝖾𝗇𝗍 blk [H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 X❟ S'› or (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 X❟ S')›.

On a state sequent having antecedents, e.g. P ⟹ Q›, the synthesis mechanism solve the antecedent
P› according to the given specification from user.
For example, the P› can be the specification of a procedure to be programmed, like the guard
P ≡ 𝗉𝗋𝗈𝖼 ?f ⦃ X ⟼ ?cond ⦂ 𝗏𝖺𝗅 𝔹 ⦄› of the branch statement. In this case
the mechanism is to synthesis that guard according to the user-given specification, like $x > 2›
to synthesis 𝗉𝗋𝗈𝖼 ?f ⦃ X ⟼ $x > 2 ⦂ 𝗏𝖺𝗅 𝔹 ⦄›.
›

consts synthesis :: action

definition DoSynthesis :: 'a  prop  prop  prop
  where DoSynthesis term sequent result  (PROP sequent  PROP result)

definition Synthesis_Parse :: 'a  'b  bool
  where Synthesis_Parse input parsed   True

declare [[φreason_default_pattern Synthesis_Parse ?in _  Synthesis_Parse ?in _ (100)]]

lemma φsynthesis:
  PROP sequent
 PROP DoSynthesis X sequent result
 PROP result
  unfolding DoSynthesis_def .

text ‹
  Overall, the synthesis procedure consists of 2 phases.
  The first phase is a pre-process parsing the user input. Performed by antecedent
    schematic_propSynthesis_Parse input ?parsed,
  it rewrites the user terminput to schematic_term?parsed.

  The rewrite process enables user to input partially instead of always giving the complete
  assertion every time, for example, just the abstract object termx to
  denote pattern_termx  _ and leave the type unspecified to accept anything.
  For example, user may input just an abstract object termx to mean to
    synthesis termx  T for some unspecified termT;
    user may also input term0::nat to mean to synthesis term0  Natural_Number.

  One can disable φ_synthesis_parsing to disable this feature.

  The second phase does the real work, synthesising the ?parsed›.

  As the given specifications are on abstraction, ways to synthesis an abstract specification
  are many and not uniquely determined syntactically of course.
  Therefore we apply an A* algorithm according to explicitly annotated cost. The algorithm finds the
  solution having the minimum cost.

  Besides, in order to reduce the search space, we assume a large amount of operators having
  specific programs to refine them (such as plus and subtract),
  so that synthesising a composite expression can be split structurally (and syntactically) to
  several small problems for synthesising its operands and for finding a proper program refining the operator.

  To find such a proper instantiation requires to know the abstraction relations of the operands,
  but it is not an easy problem because transformation of abstraction can happen at every application.
  The choice of the abstraction relation of a sub-expression affects the synthesis of the inner
  operations of the sub-expression and also the outer operation using it.
  Choices of the intermediate abstraction relations have to be counted globally.

  Therefore the synthesis reasoning also contains two phases. The first phase split the synthesis
  problem for the original big composite expression down to several small problems of
  choosing the intermediate abstraction relations and instantiating proper refinement for each
  operators. And the second phase is an heuristic search finding the optimum choices
  and the instantiations.
  The first phase is a greedy algorithm as what we assumed.
  The first-reached solution (according to the PLPR priority of the configured rules) is adopted
  and the remains are dropped.
  The second phase is exhaustive for every possible search branches (with pruning).

  Candidates of the second phase are measured by the distance of the transformation used inside.
  An ideal solution is to involve no transformation at all.
  A transformation is an edge and each one is labelled with a distance manually.
  The distance of a path e1;e2;…;en is the maximum distance of its edges (transformations),
  max{ei}›.

›

definition DoSynthesis_embed :: 'a  bool  bool  bool
  where DoSynthesis_embed term sequent result  (sequent  result)

lemma [iso_atomize_rules, symmetric, iso_rulify_rules]:
  DoSynthesis term (Trueprop sequent) (Trueprop result)  Trueprop (DoSynthesis_embed term sequent result)
  unfolding DoSynthesis_def DoSynthesis_embed_def atomize_imp .

(*definition Optimal_Synthesis :: ‹prop ⇒ prop› ("OPTIMAL'_SYNTHESIS _" [3] 2)
  where ‹Optimal_Synthesis P ≡ P›
definition End_Optimal_Synthesis where ‹End_Optimal_Synthesis ⟷ True›

lemma Do_Optimal_Synthesis:
  ‹ PROP P
⟹ PROP Optimal_Synthesis P›
  unfolding Optimal_Synthesis_def .

lemma End_Optimal_Synthesis_I:
  ‹End_Optimal_Synthesis› unfolding End_Optimal_Synthesis_def ..

φreasoner_ML End_Optimal_Synthesis 1000 (‹End_Optimal_Synthesis›) = ‹
   apsnd (fn th => @{thm End_Optimal_Synthesis_I} RS th)
#> PLPR_Optimum_Solution.finish
›

φreasoner_ML Optimal_Synthesis 1000 (‹PROP Optimal_Synthesis _›) = ‹fn (ctxt,sequent) =>
  Phi_Sys_Reasoner.gen_defer_antecedent (fn _ =>
    find_index (fn const‹Trueprop› $ (Const (const_name‹End_Optimal_Synthesis›, _)) => true
                 | _ => false)
  ) (@{thm Do_Optimal_Synthesis} RS sequent)
  |> Seq.map (pair ctxt)
›
*)

subsubsection ‹Conventions›

declare [[φreason_default_pattern
      𝗉𝗋𝗈𝖼 _  ?X  λret. ?Z ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 ?R   𝗍𝗁𝗋𝗈𝗐𝗌 _ @tag synthesis 
      𝗉𝗋𝗈𝖼 _  ?X  λret. ?Z ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 ?R'  𝗍𝗁𝗋𝗈𝗐𝗌 _ @tag synthesis    (100)
  and 𝗉𝗋𝗈𝖼 _  ?X  λret. ?x  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 ?R   𝗍𝗁𝗋𝗈𝗐𝗌 _ @tag synthesis 
      𝗉𝗋𝗈𝖼 _  ?X  λret. ?x  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 ?R'  𝗍𝗁𝗋𝗈𝗐𝗌 _ @tag synthesis    (110)
  and (?X::assn) 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?Z 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ @tag synthesis 
      ?X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?Z 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ @tag synthesis    (100)
  and (?X::assn) 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?x  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ @tag synthesis 
      ?X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?x  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ @tag synthesis    (110)
    ― ‹In ordinary reasoning of ToA, the target φ-type has to be given while the target object is
        optional, as it yields a function from the source object to the target. However, in synthesis
        process, this is reversed where the φ-type can be unknown but the target object, as the target
        of the synthesis, has to be given. For this reason, we cannot always simply reuse ToA reasoning
        but may provide (or at least declare, as there is rule generation from ToA rules) specific rules.›
  and ?X 𝗌𝗁𝗂𝖿𝗍𝗌 ?Z 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ 𝗐𝗂𝗍𝗁 _  @tag synthesis 
      ?X 𝗌𝗁𝗂𝖿𝗍𝗌 ?Z 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ 𝗐𝗂𝗍𝗁 _ @tag synthesis   (100)
  and ?X 𝗌𝗁𝗂𝖿𝗍𝗌 ?x  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ 𝗐𝗂𝗍𝗁 _ @tag synthesis 
      ?X 𝗌𝗁𝗂𝖿𝗍𝗌 ?x  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 _ 𝗐𝗂𝗍𝗁 _ @tag synthesis   (100)
  and ?X @tag synthesis 
      ERROR TEXT(‹Malformed Synthesis rule›  ?X) (0)
]]

φreasoner_group φsynthesis_all = (100, [1, 3000]) for _ @tag synthesis
      ‹Rules implementing Synthesis mechanism of IDE-CP›
  and φsynthesis_red = (2500, [2500, 2799]) in φsynthesis_all
      ‹Reductions and Evaluations›
  and φsynthesis = (100, [10, 500]) in φsynthesis_all
      ‹usual rules›
  and φsynthesis_literal = (470, [450, 500]) in φsynthesis
      ‹literal›
  and φsynthesis_fallback = (9, [9,9]) in φsynthesis_all and < φsynthesis
      ‹fallbacks›
  and φsynthesis_cut = (1000, [1000, 1500]) in φsynthesis_all and > φsynthesis and < φsynthesis_red
      ‹cutting rules›
  and φsynthesis_split = (1530, [1530, 1550]) in φsynthesis_all and > φsynthesis_cut
      ‹Splitting the targets into each sub-reasoning goal›
  and φsynthesis_normalize = (2000, [2000,2400]) in φsynthesis_all and > φsynthesis_split
      ‹normalization›
  and φsynthesis_weak_normalize = (800, [800,900]) in φsynthesis_all and < φsynthesis_cut
      ‹normalization with backtracking›

  and interp_φsynthesis = (%cutting, [%cutting, %cutting+30]) for PROP DoSynthesis _ _ _
      ‹describing how to carry out the synthesis in detail on specific IDE-CP sequent›

  and φsynthesis_parse_all = (1000, [10, 3000]) for Synthesis_Parse input parsed
      ‹Synthesis Parsing›
  and φsynthesis_parse = (1000, [1000, 1030]) in φsynthesis_parse_all
      ‹usual rules›
  and φsynthesis_parse_success = (3000, [3000, 3000]) in φsynthesis_parse_all and > φsynthesis_parse
      ‹direct success›
  and φsynthesis_parse_default = (10, [10,29]) in φsynthesis_parse_all and < φsynthesis_parse
      ‹default parsing›
  and φsynthesis_parse_number = (40, [30, 70]) in φsynthesis_parse_all
                                               and < φsynthesis_parse and > φsynthesis_parse_default
      ‹parsing numbers›
  and φsynthesis_parse_guess_literal_type = (60, [60, 60]) in φsynthesis_parse_number
      ‹see Guess_Literal_Type_Synthesis_Parse›


subsubsection ‹Parse the Term to be Synthesised›

lemma [φreason %φsynthesis_parse_success for
          Synthesis_Parse (?X'::?'ret  assn) (?X::?'ret  assn)
          Synthesis_Parse (?X'::?'c BI) (?X::?'c BI)
]:
  Synthesis_Parse X X
  ― ‹We do not need to rewrite the input once it is already an assertion›
  unfolding Synthesis_Parse_def ..

lemma [
  φreason %φsynthesis_parse_success for
      Synthesis_Parse (?X'::assn) (?X::?'ret  assn),
  φreason default %φsynthesis_parse_default for
      Synthesis_Parse (?X'::?'a BI) (?X::?'ret  assn)
]:
  Synthesis_Parse X (λ_. X) for X :: assn
  ― ‹We do not need to rewrite the input once it is already an assertion›
  unfolding Synthesis_Parse_def ..

lemma [φreason default %φsynthesis_parse_default
    for Synthesis_Parse ?x (?Y::?'ret  assn)
    except Synthesis_Parse (?x  ?T) ?Y
           Synthesis_Parse (?x::assn) ?Y
           Synthesis_Parse (?x::?'ret  assn) ?Y
]:
  Synthesis_Parse x (λret. (x  𝗏𝖺𝗅[ret] X :: assn))
  ― ‹The fallback parser recognizes the input to be the abstract object and leaves
      the φ-type unspecified to be arbitrarily anything.›
  unfolding Synthesis_Parse_def ..

lemma [φreason default %φsynthesis_parse_default]:
  Synthesis_Parse T (x  T)
  unfolding Synthesis_Parse_def ..


lemma [φreason default %φsynthesis_parse_default+10
  for Synthesis_Parse (numeral ?n::?'bb::numeral) ?X
      Synthesis_Parse (0::?'cc::zero) ?X
      Synthesis_Parse (1::?'dd::one) ?X
  except Synthesis_Parse (?n::nat) ?X
]:
  Synthesis_Parse (n :: nat) X
 Synthesis_Parse n X
 ― ‹Given any input of 0, 1, or schematic_termnumeral ?sth, of a schematic type
      unspecified by user, the input is regarded as of natural number type.›
  unfolding Synthesis_Parse_def
  ..


lemma [φreason default %φsynthesis_parse_default+10 for Synthesis_Parse (?T :: ?'ret2  (fiction,?'x) φ) (?Y::?'ret  assn)]:
  Synthesis_Parse T (λret. x  T ret :: assn)
  unfolding Synthesis_Parse_def ..

lemma [φreason default %φsynthesis_parse_default+10 for Synthesis_Parse (?T :: (fiction,?'x) φ) (?Y::?'ret  assn)]:
  Synthesis_Parse T (λret. x  T :: assn)
  unfolding Synthesis_Parse_def ..


subsubsection ‹Guess the φ›-Type of Literals›

ML_file ‹library/tools/guess_literal_number_type.ML›

φreasoner_ML Guess_Literal_Type_Synthesis_Parse %φsynthesis_parse_guess_literal_type
                                                (Synthesis_Parse _ (?X :: ?'ret  assn))
  = fn (_, (ctxt,sequent)) => Seq.make (fn () =>
      let val (bvtys, _ (*Trueprop*) $ (Const(const_nameSynthesis_Parse, _) $ literal $ X))
                = Phi_Help.strip_meta_hhf_bvtys (Phi_Help.leading_antecedent' sequent)
          val time = Phi_Envir.the_time ctxt
       in if Phi_Type_of_Literal.is_literal literal
          then Phi_Type_of_Literal.guess ctxt bvtys time literal
       |> Option.map (fn phi_type =>
            ((ctxt,
              instantiateT=phi_type
                       and n=Thm.var (("n", Thm.maxidx_of_cterm phi_type + 1),
                                       Thm.dest_ctyp0 (Thm.ctyp_of_cterm phi_type))
                       and X=Thm.cterm_of ctxt X
                       and 'c=Thm.dest_ctyp0 (Thm.dest_ctyp1 (Thm.ctyp_of_cterm phi_type))
                       and 'x=Thm.dest_ctyp0 (Thm.ctyp_of_cterm phi_type)
                       and 'any=Thm.ctyp_of ctxt (Term.fastype_of1 (bvtys, X))
                        in lemma Synthesis_Parse (n  T) X
                                Synthesis_Parse n X
                              for T :: ('c,'x) φ and X :: 'any
                              by (simp add: Synthesis_Parse_def) RS sequent), Seq.empty))
          else NONE
      end )


subsubsection ‹Tagging the target of a synthesis rule›

(* definition Synthesis :: ‹'a BI ⇒ 'a BI› ("SYNTHESIS _" [17] 16) where [iff]: ‹Synthesis S = S› *)

text ‹
  Only procedure rules need to be tagged by constsynthesis. The view shift and the ToA do not.


  Occurring in the post-condition of a rule (either a procedure specification or a view shift
    or an implication), SYNTHESIS tags the target of the rule, i.e., the construct that this
    procedure or this transformation synthesises.
  For example, prop𝗉𝗋𝗈𝖼 f  X  λret. Z ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 Y  @tag synthesis
    represents the procedure f generates
    something that meets Z, and it is a synthesis rule for synthesising the target Z›.

  Occurring during reasoning, antecedent like
    schematic_prop𝗉𝗋𝗈𝖼 ?f  X  λret. Z ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 Y  @tag synthesis  C,
  represents a reasoning task to find some procedure or some transformation to synthesis
  something meeting Z.

TODO: update the comment.
›

(* depreciate
subsubsection ‹Post_Synthesis Simplification›

ML ‹
structure Post_Synthesis_SS = Simpset (
  val initial_ss = Simpset_Configure.Minimal_SS
  val binding = SOME binding‹post_synthesis_simp›
  val comment = "Rules simplifying after the synthesis operation."
  val attribute = NONE
  val post_merging = I
)
›

consts post_synthesis_simp :: mode

φreasoner_ML post_synthesis_simp %cutting (‹Simplify post_synthesis_simp ?X' ?X›)
  = ‹Phi_Reasoners.wrap (PLPR_Simplifier.simplifier_by_ss' (K Seq.empty) Post_Synthesis_SS.get' {fix_vars=true}) o snd›
*)

subsubsection ‹Synthesis Operations›

paragraph ‹Fallback›

text ‹On programming mode, the synthesis operation always tries to find a procedure.
  View shifts have to be wrapped in a procedure. The following is an automatic wrapper. ›

lemma Synthesis_Proc_fallback_VS
  [φreason default %φsynthesis_fallback for 𝗉𝗋𝗈𝖼 _  _  λv. ?X 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 ?R  𝗍𝗁𝗋𝗈𝗐𝗌 _ @tag synthesis]:
  S1 𝗌𝗁𝗂𝖿𝗍𝗌 X' 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 S2 𝗐𝗂𝗍𝗁 Any
 𝗉𝗋𝗈𝖼 Return φV_none  S1  λv. X' 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 S2  @tag synthesis
  unfolding φProcedure_def Return_def det_lift_def View_Shift_def Action_Tag_def less_eq_BI_iff
  by simp

lemma [φreason default %φsynthesis_fallback]:
  A 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 B 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R 𝗐𝗂𝗍𝗁 P @tag synthesis
 A 𝗌𝗁𝗂𝖿𝗍𝗌 B 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R 𝗐𝗂𝗍𝗁 P @tag synthesis
  unfolding Action_Tag_def
  using view_shift_by_implication .


paragraph ‹Construction on Programming›

lemma [φreason %interp_φsynthesis
    for PROP DoSynthesis ?X (Trueprop (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 ?blk [?H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?S1)) ?RET
]:
  " 𝗋CALL Synthesis_Parse X X'
 Begin_Optimum_Solution
 𝗉𝗋𝗈𝖼 f  S1  λv. X' v 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 S2  𝗍𝗁𝗋𝗈𝗐𝗌 E @tag synthesis
 End_Optimum_Solution
 (v. 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] (X'' v, E'') : (X' v, E))
 𝗋Success
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP DoSynthesis X
      (Trueprop (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 blk [H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 S1))
      (Trueprop (𝗉𝖾𝗇𝖽𝗂𝗇𝗀 f 𝗈𝗇 blk [H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 (λv. X'' v * S2) 𝗍𝗁𝗋𝗈𝗐𝗌 E''))"
  unfolding REMAINS_def Action_Tag_def DoSynthesis_def Simplify_def
  using φapply_proc by fastforce

paragraph ‹Construction on View Shifting›

text ‹On view shifting mode, the synthesis operation tries to find a view shifting.›

lemma [φreason %interp_φsynthesis
    for PROP DoSynthesis ?X (Trueprop (𝗏𝗂𝖾𝗐 ?blk [?H] 𝗂𝗌 ?S1)) ?RET
]:
  " 𝗋CALL Synthesis_Parse X X'
 S1 𝗌𝗁𝗂𝖿𝗍𝗌 X' 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 S2 𝗐𝗂𝗍𝗁 P
 𝗋Success
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X'' : X'
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP DoSynthesis X
      (Trueprop (𝗏𝗂𝖾𝗐 blk [H] 𝗂𝗌 S1))
      (Trueprop ((𝗏𝗂𝖾𝗐 blk [H] 𝗂𝗌 X'' * S2)  P))"
  unfolding REMAINS_def Action_Tag_def DoSynthesis_def Simplify_def
  using φapply_view_shift
  by metis

paragraph ‹Construction on ToA›

lemma [φreason %interp_φsynthesis+10
    for PROP DoSynthesis ?X (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?x) 𝗂𝗌 (?S1::?'c::sep_magma_1 BI))) ?RET
]:
  " 𝗋CALL Synthesis_Parse X X'
 S1 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X' 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 S2 𝗐𝗂𝗍𝗁 P
 𝗋Success
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X'' : X'
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP DoSynthesis X
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S1))
      (Trueprop ((𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 X'' * S2)  P))"
  unfolding REMAINS_def Action_Tag_def DoSynthesis_def Simplify_def
  by (meson φapply_implication_impl)


lemma [φreason %interp_φsynthesis
    for PROP DoSynthesis ?X (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?x) 𝗂𝗌 ?S1)) ?RET
]:
  " 𝗋CALL Synthesis_Parse X X'
 Ψ[Some] S1 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Ψ[Some] X' 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 S2 𝗐𝗂𝗍𝗁 P
 Ψ[Some] X' * S2 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Ψ[Some] RET @clean
 𝗋Success
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] RET' : RET
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP DoSynthesis X
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S1))
      (Trueprop ((𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 RET')  P))"
  unfolding REMAINS_def Action_Tag_def DoSynthesis_def Simplify_def
  by (smt (verit) ToA_Construction_def Transformation_def World_Shift_expn option.inject)


paragraph ‹Solving an antecedent by Synthesis›

(*TODO: rename this to Synthesis_of*)
definition Synthesis_by :: 'a  prop  prop
  where Synthesis_by X Q  Q

text ‹If the synthesis procedure is invoked on an inference rule like propP  Q,
  it invokes the Synthesis_by procedure which tries to solve the antecedent propP
    under the instruction of the given termX to be synthesised,
  by reasoning antecedent propPROP Synthesis_by X P.

  Note the procedure of Synthesis_by will not trigger Synthesis_Parse because this
    generic procedure does not the type to be synthesised. Lacking of this type information
    affects the preciseness of Synthesis_Parse rule. The procedure of Synthesis_Parse
    should be triggered at the entry point of each specific operation, where the expected type
    is clear.›

definition Synthesis_by_embed :: 'a  bool  bool where Synthesis_by_embed X Q  Q

lemma [iso_atomize_rules, symmetric, iso_rulify_rules]:
  Synthesis_by X (Trueprop P)  Trueprop (Synthesis_by_embed X P)
  unfolding Synthesis_by_embed_def Synthesis_by_def .

declare [[φreason_default_pattern PROP Synthesis_by ?X ?Q  PROP Synthesis_by ?X ?Q (100)]]

φreasoner_group φant_by_synthesis_all = (1000, [1,3000]) for PROP Synthesis_by X Ant
      ‹how to solve an antecedent ‹Ant› with the annotated synthesis target ‹X››
  and φant_by_synthesis = (1000, [1000,1030]) in φant_by_synthesis_all
      ‹cutting rules›
  and φant_by_synthesis_red = (2500, [2500, 2800]) in φant_by_synthesis_all and > φant_by_synthesis
      ‹Reduction or Evaluation›

lemma [φreason %interp_φsynthesis
    for PROP DoSynthesis ?X (PROP ?P  PROP ?Q) ?RET
]:
  " PROP Synthesis_by X (PROP P)
 𝗋Success
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP DoSynthesis X (PROP P  PROP Q) (PROP Q)"
  unfolding DoSynthesis_def Synthesis_by_def Action_Tag_def .

lemma [φreason %φant_by_synthesis]:
  (x. PROP Synthesis_by X (PROP P x))
 PROP Synthesis_by X (x. PROP P x)
  unfolding Synthesis_by_def .

lemma [φreason %φant_by_synthesis]:
  (PROP P  PROP Synthesis_by X (PROP Q))
 PROP Synthesis_by X (PROP P  PROP Q)
  unfolding Synthesis_by_def .

(*
lemma [φreason %φant_by_synthesis+10]:
  ‹ 𝗋CALL Synthesis_Parse X' X
⟹ Begin_Optimum_Solution
⟹ 𝗉𝗋𝗈𝖼 f ⦃ R1 ⟼ λret. X ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R2 ⦄ 𝗍𝗁𝗋𝗈𝗐𝗌 E @tag synthesis
⟹ End_Optimum_Solution
⟹ Simplify post_synthesis_simp X'' X
⟹ Simplify (assertion_simps ABNORMAL) E'' E
⟹ PROP Synthesis_by X' (Trueprop (𝗉𝗋𝗈𝖼 f ⦃ R1 ⟼ λret. X'' ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R2 ⦄ 𝗍𝗁𝗋𝗈𝗐𝗌 E'' ))›
  unfolding Synthesis_by_def Action_Tag_def Simplify_def by fastforce
*)
lemma [φreason %φant_by_synthesis]:
  𝗋CALL Synthesis_Parse A A'
 Begin_Optimum_Solution
 𝗉𝗋𝗈𝖼 f  X  λret. A' ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R  𝗍𝗁𝗋𝗈𝗐𝗌 E' @tag synthesis
 End_Optimum_Solution
― ‹BUG! TODO›
 (ret. 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] (A'' ret, E'') : (A' ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R, E'))
 (ret. A'' ret 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y ret)
 (e. E'' e 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 E e)
 PROP Synthesis_by A (Trueprop (𝗉𝗋𝗈𝖼 f  X  Y  𝗍𝗁𝗋𝗈𝗐𝗌 E ))
  unfolding Synthesis_by_def Action_Tag_def Simplify_def
  by (simp, meson "_φcast_proc_exception_internal_rule_" "_φcast_proc_return_internal_rule_" Action_Tag_def Premise_True 𝗋Success_I)

lemma [φreason %φant_by_synthesis]:
  (x. PROP Synthesis_by X (Trueprop (P x)))
 PROP Synthesis_by X (Trueprop (All P))
  unfolding Synthesis_by_def Action_Tag_def ..

lemma [φreason %φant_by_synthesis]:
  (P  PROP Synthesis_by X (Trueprop Q))
 PROP Synthesis_by X (Trueprop (P  Q))
  unfolding Synthesis_by_def Action_Tag_def ..


subsubsection ‹General Synthesis Rules›

lemma [φreason %φant_by_synthesis_red]:
  𝗉𝗋𝗈𝖼 F  R1  λret. f x  T ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R2  @tag synthesis
 𝗉𝗋𝗈𝖼 F  R1  λret. case_named f (tag x)  T ret 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R2  @tag synthesis
  by simp

lemma [φreason %φant_by_synthesis_red]:
  PROP Synthesis_by X (Trueprop P)
 PROP Synthesis_by X (Trueprop (𝗎𝗌𝖾𝗋 P))
  unfolding Argument_def .

lemma [φreason %φant_by_synthesis_red]:
  PROP Synthesis_by X (PROP P)
 PROP Synthesis_by X (PROP (Argument P))
  unfolding Argument_def .

lemma [φreason %φant_by_synthesis for PROP Synthesis_by ?X (Trueprop (_ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?X' 𝗐𝗂𝗍𝗁 _))]:
  A 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X 𝗐𝗂𝗍𝗁 P
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X' : X
 PROP Synthesis_by X (Trueprop (A 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X' 𝗐𝗂𝗍𝗁 P))
  unfolding Synthesis_by_def Simplify_def by meson

lemma [φreason %φant_by_synthesis for PROP Synthesis_by ?X (Trueprop (_ 𝗌𝗁𝗂𝖿𝗍𝗌 ?X' 𝗐𝗂𝗍𝗁 _))]:
  A 𝗌𝗁𝗂𝖿𝗍𝗌 X 𝗐𝗂𝗍𝗁 P
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X' : X
 PROP Synthesis_by X (Trueprop (A 𝗌𝗁𝗂𝖿𝗍𝗌 X' 𝗐𝗂𝗍𝗁 P))
  unfolding Synthesis_by_def Simplify_def by meson

lemma [φreason %φant_by_synthesis for PROP Synthesis_by ?X (a. _ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 ?P)]:
  (a. A a 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X a 𝗐𝗂𝗍𝗁 P)
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X' : X
 PROP Synthesis_by X (a. A a 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X' a 𝗐𝗂𝗍𝗁 P)
  unfolding Synthesis_by_def Simplify_def by meson

lemma [φreason %φant_by_synthesis for PROP Synthesis_by ?X (a. ?A a 𝗌𝗁𝗂𝖿𝗍𝗌 ?B a 𝗐𝗂𝗍𝗁 ?P)]:
  (a. A a 𝗌𝗁𝗂𝖿𝗍𝗌 X a 𝗐𝗂𝗍𝗁 P)
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X' : X
 PROP Synthesis_by X (a. A a 𝗌𝗁𝗂𝖿𝗍𝗌 X' a 𝗐𝗂𝗍𝗁 P)
  unfolding Synthesis_by_def Simplify_def by meson

lemma [φreason %φant_by_synthesis for PROP Synthesis_by ?X (a. 𝗎𝗌𝖾𝗋 _ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 ?P)]:
  (a. A a 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X a 𝗐𝗂𝗍𝗁 P)
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X' : X
 PROP Synthesis_by X (a. 𝗎𝗌𝖾𝗋 A a 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X' a 𝗐𝗂𝗍𝗁 P)
  unfolding Synthesis_by_def Argument_def Simplify_def by meson

lemma [φreason %φant_by_synthesis for PROP Synthesis_by ?X (a. 𝗎𝗌𝖾𝗋 ?A a 𝗌𝗁𝗂𝖿𝗍𝗌 ?B a 𝗐𝗂𝗍𝗁 ?P)]:
  (a. A a 𝗌𝗁𝗂𝖿𝗍𝗌 X a 𝗐𝗂𝗍𝗁 P)
 𝗌𝗂𝗆𝗉𝗅𝗂𝖿𝗒[programming_mode] X' : X
 PROP Synthesis_by X (a. 𝗎𝗌𝖾𝗋 A a 𝗌𝗁𝗂𝖿𝗍𝗌 X' a 𝗐𝗂𝗍𝗁 P)
  unfolding Synthesis_by_def Argument_def Simplify_def by meson


subsection ‹Application›
― ‹of procedures, ToA, and any other things›

text ‹It is a generic framework allowing to apply general things on the state sequent.
These general things named ‹application› includes
 procedures --- therefore appending a procedure on the current construction
 transformations of abstraction and view shifts --- transforming the abstract state
 actions --- meta operations combining several applications or transformations, cf. section Action.
›

definition φApplication :: prop  prop  prop  prop
  where φApplication App_Rules State Result
                       (PROP State  PROP App_Rules  PROP Result)

(* lemma φApplication_cong[cong]:
  ‹ App1 ≡ App2 ⟹ Stat1 ≡ Stat2 ⟹ Res1 ≡ Res2
⟹ φApplication App1 Stat1 Res1 ≡ φApplication App2 Stat2 Res2›
  unfolding φApplication *)

lemma φapplication:
  PROP Apps
 PROP State
 PROP φApplication Apps State Result
 𝗋Success
 PROP Result
  unfolding φApplication_def Pure.prop_def Optimum_Solution_def Optimum_Among_def .

definition φApplication_Conv :: prop  prop  prop
  where φApplication_Conv  (⟹)

definition φApp_Conv :: bool  bool  bool
  where φApp_Conv  (⟶)

lemma φApplication_Conv:
  PROP P
 PROP φApplication_Conv P Q
 𝗋Success
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP Q
  unfolding φApplication_Conv_def .

ML_file ‹library/system/application.ML›

φreasoner_group φapplication_all = (1000, [10,3000]) for (PROP φApplication Apps State Result)
    ‹describs how to apply ‹Apps› over ‹State››
  and φapplication_traverse_apps = (70, [70,70]) in φapplication_all
    ‹attemps each application candidate in order›
  and φapplication = (1000, [1000, 1100]) in φapplication_all > φapplication_traverse_apps
    ‹usual cutting rules›

  and φapp_conv_all = (1000, [0,3000]) for ((PROP φApplication_Conv Antcedent Consequent),
                                             φApp_Conv Antcedent Consequent)
    ‹application as converting ‹Antecedent› to ‹Consequent››
  and φapp_conv_success = (3000, [3000,3000]) in φapp_conv_all
    ‹direct success›
  and φapp_conv_normalize = (2000, [2000,2300]) in φapp_conv_all and < φapp_conv_success
    ‹normalization rules›
  and φapp_conv = (1000, [1000,1200]) in φapp_conv_all and < φapp_conv_normalize
    ‹usual cutting rules›
  and φapp_conv_derived = (50, [50, 60]) in φapp_conv_all and < φapp_conv
    ‹derived rules›
  and φapp_conv_failure = (0, [0,0]) in φapp_conv_all and < φapp_conv_derived
    ‹failures›

declare [[
  φreason_default_pattern PROP φApplication ?Apps ?State _  PROP φApplication ?Apps ?State _ (100),
  φdefault_reasoner_group PROP φApplication _ _ _ : %φapplication (100)
]]


subsubsection ‹Common Rules of Application Methods›

(*
lemma φApplication_opt_L:
  ‹ Stop_Divergence
⟹ PROP φApplication (PROP App) State (PROP Result)
⟹ PROP φApplication (Optimum_Among (PROP App &&& PROP Apps)) State (PROP Result)›
  unfolding prop_def φApplication_def conjunction_imp Optimum_Among_def .

lemma φApplication_opt_R:
  ‹ PROP φApplication (Optimum_Among Apps) State (PROP Result)
⟹ PROP φApplication (Optimum_Among (PROP App &&& PROP Apps)) State (PROP Result)›
  unfolding prop_def φApplication_def conjunction_imp Optimum_Among_def .

declare [[φreason 1010 φApplication_opt_L φApplication_opt_R for
            ‹PROP φApplication (Optimum_Among (PROP ?App &&& PROP ?Apps)) ?State ?Result›]]

lemma [φreason 1000 φApplication_opt_L φApplication_opt_R for
            ‹PROP φApplication (Optimum_Among ?App) ?State ?Result›]:
  ‹ Stop_Divergence
⟹ PROP φApplication App State (PROP Result)
⟹ PROP φApplication (Optimum_Among App) State (PROP Result)›
  unfolding prop_def φApplication_def Optimum_Among_def .
*)

context begin

private lemma φApp_L:
  PROP φApplication (PROP App) State (PROP Result)
 PROP φApplication (PROP App &&& PROP Apps) State (PROP Result)
  unfolding prop_def φApplication_def conjunction_imp .

private lemma φApp_R:
  PROP φApplication (PROP Apps) State (PROP Result)
 PROP φApplication (PROP App &&& PROP Apps) State (PROP Result)
  unfolding prop_def φApplication_def conjunction_imp .

declare [[
  φreason %φapplication_traverse_apps φApp_L φApp_R
      for PROP φApplication (PROP ?App &&& PROP ?Apps) ?State ?Result
]]

end

lemma φapply_eager_antecedent_meta:
  PROP φApplication (PROP App) State (PROP Result)
 PROP Prem
 PROP φApplication (PROP Prem  PROP App) State (PROP Result)
  unfolding prop_def φApplication_def imp_implication
  subgoal premises prems using prems(1)[OF prems(3) prems(4)[OF prems(2)]] . .

lemma φapply_eager_antecedent:
  PROP φApplication (Trueprop App) State (PROP Result)
 Prem
 PROP φApplication (Trueprop (Prem  App)) State (PROP Result)
  unfolding prop_def φApplication_def imp_implication
  subgoal premises prems using prems(1)[OF prems(3) prems(4)[OF prems(2)]] . .

lemma φapply_user_antecedent_meta:
  PROP φApplication (PROP App) State (PROP Result)
 PROP φApplication (PROP Prem  PROP App) State (PROP Prem  PROP Result)
  unfolding prop_def φApplication_def imp_implication
  subgoal premises prems using prems(1)[OF  prems(2) prems(3)[OF prems(4)]] . .

lemma φapply_user_antecedent:
  PROP φApplication (Trueprop App) State Result
 PROP φApplication (Trueprop (Prem  App)) State (Prem  PROP Result)
  unfolding prop_def φApplication_def imp_implication
  subgoal premises prems using prems(1)[OF prems(2) prems(3)[OF prems(4)]] . .

φreasoner_ML φapply_admit_antecedent %φapplication
  ( PROP φApplication (PROP ?Prem  PROP ?App) ?State ?Result
  | PROP φApplication (Trueprop (?Prem'  ?App')) ?State ?Result )
= fn (_, (ctxt,sequent)) => Seq.make (fn () =>
  let val _ $ app $ _ $ _ = Thm.major_prem_of sequent
      val (user_rule, eager_rule) =
               case app of Const(const_nameTrueprop, _) $ _ =>
                              (@{thm φapply_user_antecedent}, @{thm φapply_eager_antecedent})
                         | Const(const_namePure.imp, _) $ _ $ _ =>
                              (@{thm φapply_user_antecedent_meta}, @{thm φapply_eager_antecedent_meta})
      fun process (Const(const_nameTrueprop, _) $ X) met_sequent = process X met_sequent
        | process (Const(const_namePure.imp, _) $ A $ X) (met,eager,sequent) =
            process X (if met > 0 orelse Phi_Sys_Reasoner.is_user_dependent_antecedent A
                       then (met + 1, eager, user_rule RS sequent)
                       else (met, eager + 1, eager_rule RS sequent))
        | process (Const(const_nameHOL.implies, _) $ A $ X) (met,eager,sequent) =
            process X (if met > 0 orelse Phi_Sys_Reasoner.is_user_dependent_antecedent A
                       then (met + 1, eager, user_rule RS sequent)
                       else (met, eager + 1, eager_rule RS sequent))
        | process _ sequent = sequent
      val (_, eager, sequent') = process app (0,0,sequent)
      val N = Thm.nprems_of sequent'
      val sequent'2 =
        if eager <= 1 then sequent'
        else let val sequent'3 = Thm.permute_prems 1 (eager-1) sequent'
                 fun perm i sqt = if i = eager + 1 then sqt
                                  else perm (i+1) (Thm.permute_prems i (N-i-1) sqt)
              in perm 2 sequent'3 end
   in SOME ((ctxt, sequent'2), Seq.empty)
  end
)

lemma [φreason %φapplication]:
  PROP φApplication (Trueprop App) State (PROP Result)
 PROP φApplication (Trueprop (App @tag Act)) State (PROP Result)
  unfolding prop_def φApplication_def Action_Tag_def
  subgoal premises prems using prems(1)[OF prems(2) prems(3)] . .

(*
lemma [φreason %φapplication+100]:
  ‹ PROP φApplication (⋀a b. PROP App (a,b)) State (PROP Result)
⟹ PROP φApplication (Pure.all App) State (PROP Result)›
  unfolding split_paired_all .
*)

lemma [φreason %φapplication]:
  PROP φApplication (PROP App x) State (PROP Result)
 PROP φApplication (x. PROP App x) State (PROP Result)
  unfolding φApplication_def
proof -
  assume p1: PROP State  PROP App x  PROP Result
     and p2: PROP State
     and p3: x. PROP App x
  show PROP Result
    by (rule p1, rule p2, rule p3)
qed

lemma [φreason %φapplication+100]:
  PROP φApplication (a. PROP App (φV_pair x a)) State (PROP Result)
 PROP φApplication (x. PROP App x) State (PROP Result)
  unfolding φApplication_def
proof -
  assume p1: PROP State  (a. PROP App (x, a))  PROP Result
     and p2: PROP State
     and p3: x. PROP App x
  show PROP Result
    by (rule p1, rule p2, rule p3)
qed

(*
lemma [φreason %φapplication+100]:
  ‹ PROP φApplication (Trueprop (∀a b. App (a,b))) State (PROP Result)
⟹ PROP φApplication (Trueprop (All App)) State (PROP Result)›
  unfolding split_paired_All .
*)

lemma [φreason %φapplication]:
  PROP φApplication (Trueprop (App x)) State (PROP Result)
 PROP φApplication (Trueprop (All App)) State (PROP Result)
  unfolding φApplication_def
  subgoal premises p by (rule p(1), rule p(2), rule p(3)[THEN spec[where x=x]]) .

lemma [φreason %φapplication+100]:
  PROP φApplication (Trueprop (a. App (φV_pair x a))) State (PROP Result)
 PROP φApplication (Trueprop (All App)) State (PROP Result)
  unfolding φApplication_def
  subgoal premises p by (rule p(1), rule p(2), rule, rule p(3)[THEN spec]) .

lemma [φreason %φapplication]:
  PROP φApplication (Trueprop (X = Y)) S (PROP R)
 PROP φApplication (X  Y) S (PROP R)
  unfolding atomize_eq .



subsubsection ‹Application as a Resolution›

lemma [φreason %φapplication]:
  PROP φApplication_Conv X' X
 PROP φApplication X' (PROP X  PROP Y) Y
  unfolding φApplication_def φApplication_Conv_def
  subgoal premises prems using prems(3)[THEN prems(1), THEN prems(2)] . .

lemma [φreason %φapplication]:
  φApp_Conv X' X
 PROP φApplication (Trueprop X') (Trueprop (X  Y)) (Trueprop Y)
  unfolding φApplication_def φApplication_Conv_def φApp_Conv_def
  by blast

subsubsection ‹Conversion of Applying Rule›

paragraph ‹By φApp_Conv›

subparagraph ‹Basic Rules›

lemma [φreason %φapp_conv_success]:
  φApp_Conv X Y
 PROP φApplication_Conv (Trueprop X) (Trueprop Y)
  unfolding φApplication_Conv_def φApp_Conv_def
  by blast

subparagraph ‹Direct Success›

lemma [φreason %φapp_conv_success for PROP φApplication_Conv (PROP ?X) (PROP ?X')]:
  PROP φApplication_Conv (PROP X) (PROP X)
  unfolding φApplication_Conv_def .

lemma [φreason %φapp_conv_success for φApp_Conv ?X ?X']:
  φApp_Conv X X
  unfolding φApp_Conv_def ..


subparagraph ‹Over Logic Connectives›

lemma [φreason %φapp_conv]:
  PROP φApplication_Conv (A x) X
 PROP φApplication_Conv (Pure.all A) X
  unfolding φApplication_Conv_def
proof -
  assume A: PROP A x  PROP X
    and  B: x. PROP A x
  from A[OF B[of x]] show PROP X .
qed

lemma [φreason %φapp_conv]:
  φApp_Conv (A x) X
 φApp_Conv (All A) X
  unfolding φApp_Conv_def
  by blast

lemma [φreason %φapp_conv_normalize]:
  (x. PROP φApplication_Conv X (Y x))
 PROP φApplication_Conv X (Pure.all Y)
  unfolding φApplication_Conv_def
  apply (simp add: norm_hhf_eq)
  subgoal premises prems for x
    by (rule prems(1), rule prems(2)) .

lemma [φreason %φapp_conv_normalize]:
  (x. φApp_Conv X (Y x))
 φApp_Conv X (x. Y x)
  unfolding φApp_Conv_def
  by blast

lemma [φreason %φapp_conv]:
  PROP May_By_Assumption X
 PROP φApplication_Conv A Y
 PROP φApplication_Conv (PROP X  PROP A) Y
  unfolding φApplication_Conv_def May_By_Assumption_def
  subgoal premises p using p(1)[THEN p(3), THEN p(2)] . .

lemma [φreason %φapp_conv_normalize]:
  (PROP A  PROP φApplication_Conv X Y)
 PROP φApplication_Conv (PROP X) (PROP A  PROP Y)
  unfolding φApplication_Conv_def
  subgoal premises prems
    by (rule prems(1), rule prems(3), rule prems(2)) .

lemma [φreason %φapp_conv]:
  PROP May_By_Assumption (Trueprop A)
 φApp_Conv X Y
 φApp_Conv (A  X) Y
  unfolding φApp_Conv_def May_By_Assumption_def
  by blast

lemma [φreason %φapp_conv_normalize]:
  (A  φApp_Conv X Y)
 φApp_Conv X (A  Y)
  unfolding φApp_Conv_def
  by blast

paragraph ‹Reduction›

lemma [φreason %φapp_conv]:
  φApp_Conv X Y
 φApp_Conv X (Y @tag A)
  unfolding Action_Tag_def .

lemma [φreason %φapp_conv]:
  φApp_Conv Y X
 φApp_Conv (Y @tag A) X
  unfolding Action_Tag_def .

lemma [φreason %φapp_conv]:
  φApp_Conv Y X
 φApp_Conv (TECHNICAL Y) X
  unfolding Technical_def .

lemma [φreason %φapp_conv]:
  φApp_Conv Y X
 φApp_Conv Y (TECHNICAL X)
  unfolding Technical_def .


paragraph ‹Specifically for ToA›

definition ToA_App_Conv :: 'ca itself  'c itself  ('c, 'a) φ  bool  bool  bool
  where ToA_App_Conv _ _ T App Converted  App  Converted
  ― ‹The deductive programming is working on the algebra of 'c›, with leading item of φ-type T›.
      Given a ToA that is on the algebra of 'ca› other than 'c›, how to convert
      the ToA to a one on 'c› so that it can be applied in the programming.›

declare [[φreason_default_pattern ToA_App_Conv ?TYa ?TY ?T' (?x  ?T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?y  ?U 𝗐𝗂𝗍𝗁 ?P) (_  _ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _  _ 𝗐𝗂𝗍𝗁 _) 
                                  ToA_App_Conv ?TYa ?TY ?T' (?x  ?T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?y  ?U 𝗐𝗂𝗍𝗁 ?P) (_ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 _)    (100)
                              and ToA_App_Conv ?TYa ?TY ?T' ?var_X (_  _ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _  _ 𝗐𝗂𝗍𝗁 _) 
                                  ToA_App_Conv ?TYa ?TY ?T' ?X     (_ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 _)    (100)
                              and ToA_App_Conv ?TYa ?TY ?T' (a. ?Q a  (a  ?T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?y  ?U 𝗐𝗂𝗍𝗁 ?P)) (_ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 _) 
                                  ToA_App_Conv ?TYa ?TY ?T' (a. ?Q a  (a  ?T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?y  ?U 𝗐𝗂𝗍𝗁 ?P)) (_ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 _)    (100)
                              and ToA_App_Conv ?TYa ?TY ?T' ?App ?C 
                                  ERROR TEXT(‹Bad rule› (ToA_App_Conv ?TYa ?TY ?T ?App ?C)) (0)]]

subparagraph ‹Basic Rules›

lemma [φreason %φapp_conv_success for ToA_App_Conv ?TY ?TY' ?T ?App _]:
  ToA_App_Conv TY TY T App App
  unfolding ToA_App_Conv_def
  by blast

subparagraph ‹Failure›

lemma [φreason default %φapp_conv_failure for ToA_App_Conv _ _ _ (_ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 _) (_ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 _)]:
  ERROR TEXT(‹The programming is working on algbera› TYPE('c) ‹but the applying ToA is on› TYPE('ca)
               ‹I don't know how to convert› (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P))
 ToA_App_Conv TYPE('ca) TYPE('c) T (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P) (X' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P')
  for X :: 'ca BI and X' :: 'c BI
  unfolding ERROR_def
  by blast

subsubsection ‹Application on Procedure Mode›

text ‹TODO: move this to user manual.

\begin{convention}
In an application, source schematic_term?X denotes the pattern matching the whole state
and the frame rule is not used by which schematic_term?X can actually match any leading items,
whereas source schematic_term?x  ?T matches only the first φ-type.
In this way, we differentiate the representation of the purpose for transforming the whole state
and that for only the single leading item.
\end{convention}

\begin{convention}
The construction in a ready state should always be specified by a simple MTF.
\end{convention}
›

φreasoner_group φapp_on_proc_or_VS = (1000, [1000,2000])
      for PROP φApplication App (Trueprop (CurrentConstruction mode blk R S)) Result
       in φapplication_all and > φapplication_traverse_apps
      ‹applications in construction process of procedures›
  and φapp_ToA_on_proc_or_VS = (1000, [1000,1200])
      for PROP φApplication (Trueprop (S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P)) (Trueprop (CurrentConstruction mode blk R S)) Result
       in φapp_on_proc_or_VS
      ‹applying ToA›
  and φapp_VS_on_proc_or_VS = (1000, [1000,1200])
      for PROP φApplication (Trueprop (S 𝗌𝗁𝗂𝖿𝗍𝗌 T 𝗐𝗂𝗍𝗁 P)) (Trueprop (CurrentConstruction mode blk R S)) Result
       in φapp_on_proc_or_VS
      ‹applying VS›
  and φapp_proc_on_proc_or_VS = (1000, [1000,1200])
      for PROP φApplication (Trueprop (𝗉𝗋𝗈𝖼 f  S  T  𝗍𝗁𝗋𝗈𝗐𝗌 E ))
                             (Trueprop (CurrentConstruction mode blk R S)) Result
      ‹applying procedures›


paragraph ‹Transformation Methods›

(* TODO: can I remove this?
lemma [φreason 3000 for ‹
  PROP φApplication (Trueprop (?x ⦂ ?X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
          (Trueprop (CurrentConstruction ?mode ?blk ?RR (?x' ⦂ ?X'))) ?Result
›]:
  ‹ PROP φApplication (Trueprop (x ⦂ X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk R (Void❟ x' ⦂ X')))
      (Trueprop ((CurrentConstruction mode blk R T') ∧ P'))
⟹ PROP φApplication (Trueprop (x ⦂ X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk R (x' ⦂ X')))
      (Trueprop ((CurrentConstruction mode blk R T') ∧ P'))›
  by simp
*)

subparagraph ‹Shortcuts›

lemma [φreason %φapp_ToA_on_proc_or_VS+110
    for PROP φApplication (Trueprop (?S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                           (Trueprop (CurrentConstruction ?mode ?blk ?R ?S))
                           (PROP _)
        PROP φApplication (Trueprop (?var 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                           (Trueprop (CurrentConstruction ?mode ?blk ?R ?S))
                           (PROP _) ]:
  PROP φApplication (Trueprop (S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk R S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk R T)  P)
  unfolding φApplication_def
  using φapply_implication .

lemma [φreason %φapp_ToA_on_proc_or_VS+100
    for PROP φApplication (Trueprop (?S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                           (Trueprop (CurrentConstruction ?mode ?blk ?RR (?S ?R)))
                           (PROP _)
        PROP φApplication (Trueprop (?var 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                           (Trueprop (CurrentConstruction ?mode ?blk ?RR (?S ?R)))
                           (PROP _)]:
  PROP φApplication (Trueprop (S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk RR (S R)))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk RR (T R))  P)
  unfolding φApplication_def
  using φapply_implication transformation_right_frame by blast


subparagraph ‹ToA_App_Conv›

lemma [φreason %φapp_ToA_on_proc_or_VS+50]:
  ToA_App_Conv TYPE('ca) TYPE(fiction) T (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P') (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P)
 x  T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X 𝗐𝗂𝗍𝗁 P2
 PROP φApplication (Trueprop (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P'))
      (Trueprop (CurrentConstruction mode blk R (x  T)))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk R Y)  P  P2)
  for T' :: ('ca,'aa) φ
  unfolding φApplication_def ToA_App_Conv_def
  using φapply_implication by blast


lemma [φreason %φapp_ToA_on_proc_or_VS+50]:
  ToA_App_Conv TYPE('ca) TYPE(fiction) T (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P') (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P)
 φIntroFrameVar R' X'' X Y'' Y
 x  T R 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X'' 𝗐𝗂𝗍𝗁 P2
 PROP φApplication (Trueprop (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P'))
      (Trueprop (CurrentConstruction mode blk RR (x  T R)))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk RR Y'')  P  P2)
  for T' :: ('ca,'aa) φ
  unfolding φApplication_def ToA_App_Conv_def φIntroFrameVar_def
  by (cases R'; simp; metis φapply_view_shift φframe_view_right mult.commute view_shift_by_implication)


subparagraph ‹Normal›

lemma φapply_transformation_fully[φreason %φapp_ToA_on_proc_or_VS]:
  " φIntroFrameVar R S'' S' T'' T'
 S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S'' 𝗐𝗂𝗍𝗁 Any
 PROP φApplication (Trueprop (S' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T' 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk RR S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk RR T'')  P)"
  unfolding φIntroFrameVar_def φApplication_def Action_Tag_def φApp_Conv_def
  by (cases R; simp; meson φapply_view_shift φview_shift_intro_frame view_shift_by_implication)


subparagraph ‹Variant›

lemma [φreason %φapp_ToA_on_proc_or_VS]:
  " PROP φApplication (Trueprop (S' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T'))
      (Trueprop (CurrentConstruction mode blk RR S))
      (PROP Result)
 PROP φApplication (Trueprop (S' = T'))
      (Trueprop (CurrentConstruction mode blk RR S))
      (PROP Result)"
  unfolding φApplication_def BI_eq_ToA
  subgoal premises prems
    by (rule prems(1); insert prems(2-); blast) .

(* TODO: planned
subparagraph ‹Quantified Source Object›

lemma [φreason %φapp_ToA_on_proc_or_VS ]:
  ‹ ToA_App_Conv TYPE('ca) TYPE(fiction) T (∀a. Q' a ⟶ (a ⦂ T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P' a))
                                           (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P)
⟹ x ⦂ T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X 𝗐𝗂𝗍𝗁 P2
⟹ PROP φApplication (Trueprop (∀a. Q' a ⟶ (a ⦂ T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 f' a ⦂ U' 𝗐𝗂𝗍𝗁 P' a)))
      (Trueprop (CurrentConstruction mode blk RR (x ⦂ T)))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True ⟹ CurrentConstruction mode blk RR Y ∧ P ∧ P2) ›
  for T' :: ‹('ca,'aa) φ›
  unfolding φApplication_def ToA_App_Conv_def
  

lemma [φreason %φapp_ToA_on_proc_or_VS ]:
  ‹ PROP φApplication (Q a ⟹ a ⦂ T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' a 𝗐𝗂𝗍𝗁 P a)
      (Trueprop (CurrentConstruction mode blk RR X))
      (PROP Result)

⟹ PROP φApplication (Trueprop (∀a. Q a ⟶ (a ⦂ T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' a 𝗐𝗂𝗍𝗁 P a)))
      (Trueprop (CurrentConstruction mode blk RR X))
      (PROP Result) ›
  unfolding φApplication_def
  subgoal premises prems
    by (rule prems(1), rule prems(2), insert prems(3), blast) .
*)

paragraph ‹View Shift Methods›

(*TODO: can I remove this?
lemma [φreason 3000 for ‹
  PROP φApplication (Trueprop (?x ⦂ ?X 𝗌𝗁𝗂𝖿𝗍𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
          (Trueprop (CurrentConstruction ?mode ?blk ?RR (?x' ⦂ ?X'))) ?Result
›]:
  ‹ PROP φApplication (Trueprop (x ⦂ X 𝗌𝗁𝗂𝖿𝗍𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk R (Void❟ x' ⦂ X')))
      (Trueprop ((CurrentConstruction mode blk R T') ∧ P'))
⟹ PROP φApplication (Trueprop (x ⦂ X 𝗌𝗁𝗂𝖿𝗍𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk R (x' ⦂ X')))
      (Trueprop ((CurrentConstruction mode blk R T') ∧ P'))›
  by simp
*)

lemma φapply_view_shift_fast[φreason %φapp_VS_on_proc_or_VS+200 for PROP φApplication (Trueprop (?S' 𝗌𝗁𝗂𝖿𝗍𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
          (Trueprop (CurrentConstruction ?mode ?blk ?RR ?S)) ?Result]:
  PROP φApplication (Trueprop (S 𝗌𝗁𝗂𝖿𝗍𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk R S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk R T)  P)
  unfolding φApplication_def
  using "φapply_view_shift" .

lemma [φreason %φapp_VS_on_proc_or_VS+100 for PROP φApplication (Trueprop (?S' 𝗌𝗁𝗂𝖿𝗍𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
          (Trueprop (CurrentConstruction ?mode ?blk ?RR (?S ?R))) ?Result]:
  PROP φApplication (Trueprop (S 𝗌𝗁𝗂𝖿𝗍𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (CurrentConstruction mode blk RR (S R)))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk RR (T R))  P)
  unfolding φApplication_def
  using "φapply_view_shift" φview_shift_intro_frame by blast

lemma φapply_view_shift_fully[φreason %φapp_VS_on_proc_or_VS for PROP φApplication (Trueprop (?S' 𝗌𝗁𝗂𝖿𝗍𝗌 ?T' 𝗐𝗂𝗍𝗁 ?P))
      (Trueprop (CurrentConstruction ?mode ?blk ?RR ?S)) ?Result]:
  "φIntroFrameVar R S'' S' T T'
 S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S'' 𝗐𝗂𝗍𝗁 P1
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (S' 𝗌𝗁𝗂𝖿𝗍𝗌 T' 𝗐𝗂𝗍𝗁 P2))
      (Trueprop (CurrentConstruction mode blk RR S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (CurrentConstruction mode blk RR T)  (P1  P2))"
  unfolding φIntroFrameVar_def φApplication_def Action_Tag_def
  by (cases R; simp, insert φapply_implication φapply_view_shift φview_shift_intro_frame, blast+)


paragraph ‹Procedure Methods›

lemma apply_proc_fast[φreason %φapp_proc_on_proc_or_VS+200 for PROP φApplication (Trueprop (𝗉𝗋𝗈𝖼 ?f  ?S  ?T  𝗍𝗁𝗋𝗈𝗐𝗌 ?E ))
          (Trueprop (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 ?blk [?H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?S)) ?Result  PROP φApplication (Trueprop (𝗉𝗋𝗈𝖼 ?f  ?var_S  ?T  𝗍𝗁𝗋𝗈𝗐𝗌 ?E ))
          (Trueprop (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 ?blk [?H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?S)) ?Result
]:
  PROP φApplication (Trueprop (𝗉𝗋𝗈𝖼 f  S  T  𝗍𝗁𝗋𝗈𝗐𝗌 E ))
      (Trueprop (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 blk [H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  𝗉𝖾𝗇𝖽𝗂𝗇𝗀 f 𝗈𝗇 blk [H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 T 𝗍𝗁𝗋𝗈𝗐𝗌 E)
  unfolding φApplication_def
  using φapply_proc .


lemma φapply_proc_fully[φreason %φapp_proc_on_proc_or_VS for
    PROP φApplication (Trueprop (𝗉𝗋𝗈𝖼 ?f  ?S'  ?T'  𝗍𝗁𝗋𝗈𝗐𝗌 ?E ))
            (Trueprop (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 ?blk [?RR] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?S)) ?Result
]:
  φIntroFrameVar' R S'' S' T T' E'' E'
 S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S'' 𝗐𝗂𝗍𝗁 P
 Simplify (assertion_simps ABNORMAL) E''' E''
 (v. Remove_Values (E''' v) (E v))
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (𝗉𝗋𝗈𝖼 f  S'  T'  𝗍𝗁𝗋𝗈𝗐𝗌 E' ))
    (Trueprop (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 blk [RR] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 S))
    (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (𝗉𝖾𝗇𝖽𝗂𝗇𝗀 f 𝗈𝗇 blk [RR] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 T 𝗍𝗁𝗋𝗈𝗐𝗌 E)  P)
  unfolding φApplication_def φIntroFrameVar'_def
            Simplify_def Action_Tag_def Simplify_def Remove_Values_def
  apply rule
  subgoal premises prems
    apply (simp only: prems(1))
    using φapply_proc[OF 𝖼𝗎𝗋𝗋𝖾𝗇𝗍 _ [_] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 _,
          OF 𝗉𝗋𝗈𝖼 f  S'  T'  𝗍𝗁𝗋𝗈𝗐𝗌 E'[THEN φframe[where R=R],
              THEN φCONSEQ[rotated 1, OF view_shift_by_implication[OF S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S'' 𝗐𝗂𝗍𝗁 P],
                OF view_shift_refl, OF view_shift_by_implication[OF E''' _ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 E _],
                simplified prems(1), unfolded E''' = E'', simplified prems(1)]]] .
  using φapply_implication by blast



subsubsection ‹Application on a Block / End a Block›

definition Simple_HO_Unification f f'  (f = f')

text schematic_propSimple_HO_Unification A (?f x1  xn) encodes a higher order unification
  which find an instantiation of f› where terms x1, …, xn are not free in f›.

  Such f› is the most general if x1, …, xn are all variables.
  To prove this, we show there is a unique f› such that f x ≡ A› if x› is a variable
    not free in f›.
  Assume f1 x ≡ A› and f2 x ≡ A› then we have f1 x ≡ f2 x›
  and then (λx. f1 x) ≡ (λx. f2 x)›.
  Because x is not free in f1, f2, by eta-contraction, we have f1 ≡ f2.
  The ≡› here means alpha-beta-eta equivalence.
›

lemma Simple_HO_Unification_I:
  Premise procedure_ss (f = f')
 Simple_HO_Unification f f'
  unfolding Simple_HO_Unification_def Premise_def by simp

φreasoner_ML Simple_HO_Unification 1200 (Simple_HO_Unification ?f ?f') = let

fun inc_bound 0 X = X
  | inc_bound d (Bound i) = Bound (i+d)
  | inc_bound d (A $ B) = inc_bound d A $ inc_bound d B
  | inc_bound d (Abs (N,T,X)) = Abs (N,T, inc_bound d X)
  | inc_bound _ X = X

fun abstract_bound_over (x, body) =
  let
    fun abs x lev tm =
      if x aconv tm then Bound lev
      else
        (case tm of
          Abs (a, T, t) => Abs (a, T, abs (inc_bound 1 x) (lev + 1) t)
        | t $ u =>
            (abs x lev t $ (abs x lev u handle Same.SAME => u)
              handle Same.SAME => t $ abs x lev u)
        | _ => raise Same.SAME)
  in abs x 0 body handle Same.SAME => body end

fun my_abstract_over _ (v as Free (name,ty)) body =
      Abs (name, ty, abstract_over (v,body))
  | my_abstract_over btys (Bound i) body =
      Abs ("", nth btys i, abstract_bound_over (Bound i,body))
  | my_abstract_over _ (v as Const (_,ty)) body =
      Abs ("", ty, abstract_over (v,body))
  | my_abstract_over _ v body =
      Abs ("", fastype_of v, abstract_bound_over (v,body))

fun dec_bound_level d [] = []
  | dec_bound_level d (h::l) = inc_bound (d+1) h :: (dec_bound_level (d+1) l)

in
  fn (_, (ctxt,sequent)) =>
    let
      val (Vs, _, constTrueprop $ (Const (const_nameSimple_HO_Unification, _) $ f $ f'))
        = Phi_Help.leading_antecedent (Thm.prop_of sequent)
      val btys = rev (map snd Vs)
      val f' = Envir.beta_eta_contract f'
    in (case Term.strip_comb f' of (Var v, args) =>
        if forall is_Bound args
        then sequent
        else Thm.instantiate (TVars.empty, Vars.make [
                (v, Thm.cterm_of ctxt (fold_rev (my_abstract_over btys)
                                                (dec_bound_level (~ (length args)) args) f))])
             sequent
        | _ => sequent)
       |> (fn seq => Seq.single (ctxt, @{thm Simple_HO_Unification_I} RS seq))
    end
end

lemma [φreason %φapp_conv for φApp_Conv (𝗉𝗋𝗈𝖼 ?f  ?X  ?Y  𝗍𝗁𝗋𝗈𝗐𝗌 ?E) (𝗉𝗋𝗈𝖼 ?f'  ?X'  ?Y'  𝗍𝗁𝗋𝗈𝗐𝗌 ?E')]:
  Simple_HO_Unification f f'
 X' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X 𝗐𝗂𝗍𝗁 Any1
 (ret. Y ret 𝗌𝗁𝗂𝖿𝗍𝗌 Y' ret 𝗐𝗂𝗍𝗁 Any2)
 (ex.  E ex 𝗌𝗁𝗂𝖿𝗍𝗌 E' ex 𝗐𝗂𝗍𝗁 Any3)
 φApp_Conv (𝗉𝗋𝗈𝖼 f  X  Y  𝗍𝗁𝗋𝗈𝗐𝗌 E ) (𝗉𝗋𝗈𝖼 f'  X'  Y'  𝗍𝗁𝗋𝗈𝗐𝗌 E')
  unfolding φApp_Conv_def Simple_HO_Unification_def Action_Tag_def
  using φCONSEQ view_shift_by_implication by blast

lemma [φreason %φapp_conv for φApp_Conv (PendingConstruction _ _ _ _ _) (PendingConstruction _ _ _ _ _)]:
  Simple_HO_Unification f f'
 (ret. S ret 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S' ret 𝗐𝗂𝗍𝗁 Any2)
 (ex.  E ex 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 E' ex 𝗐𝗂𝗍𝗁 Any3)
 φApp_Conv (PendingConstruction f s R S E) (PendingConstruction f' s R S' E')
  unfolding φApp_Conv_def Simple_HO_Unification_def Action_Tag_def
  using φapply_implication_pending φapply_implication_pending_E by blast


subsubsection ‹Applying on View Shift Construction›

lemma [φreason %φapp_conv for φApp_Conv (?X 𝗌𝗁𝗂𝖿𝗍𝗌 ?Y 𝗐𝗂𝗍𝗁 ?P) (?X' 𝗌𝗁𝗂𝖿𝗍𝗌 ?Y' 𝗐𝗂𝗍𝗁 ?P')]:
  X' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X 𝗐𝗂𝗍𝗁 Any1
 Y 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 Any2
 𝗉𝗋𝖾𝗆𝗂𝗌𝖾 (Any1  Any2  P  P')
 φApp_Conv (X 𝗌𝗁𝗂𝖿𝗍𝗌 Y 𝗐𝗂𝗍𝗁 P) (X' 𝗌𝗁𝗂𝖿𝗍𝗌 Y' 𝗐𝗂𝗍𝗁 P')
  unfolding φApp_Conv_def Simple_HO_Unification_def Action_Tag_def Premise_def
  by (metis View_Shift_def view_shift_by_implication)


subsubsection ‹Application on ToA Construction›

φreasoner_group φapp_ToA_on_ToA = (1000, [1000, 1200])
  for PROP φApplication (Trueprop (S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
                         (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S))
                         Result
   in φapplication_all and > φapplication_traverse_apps
  ‹applying ToA on ToA construction mode›

lemma apply_cast_on_imply_exact
      [φreason %φapp_ToA_on_ToA+110 for PROP φApplication (Trueprop (?S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                                                           (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?x) 𝗂𝗌 ?S))
                                                           (PROP _)
                                        PROP φApplication (Trueprop (?var_S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                                                           (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?x) 𝗂𝗌 ?S))
                                                           (PROP _)
      ]:
  PROP φApplication (Trueprop (S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
                      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S))
                      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  ((𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 T)  P))
  unfolding φApplication_def Transformation_def ToA_Construction_def
  by blast

lemma apply_cast_on_imply_right_prod
      [φreason %φapp_ToA_on_ToA+100 for PROP φApplication (Trueprop (?S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                                                            (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?x) 𝗂𝗌 ?S * ?R))
                                                            (PROP _)
                                        PROP φApplication (Trueprop (?var 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 ?T 𝗐𝗂𝗍𝗁 ?P))
                                                            (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?x) 𝗂𝗌 ?S * ?R))
                                                            (PROP _)
      ]:
  PROP φApplication
            (Trueprop (S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
            (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S * R))
            (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  ((𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 T * R)  P))
  unfolding φApplication_def ToA_Construction_def
  using transformation_right_frame by (metis Transformation_def)


lemma [φreason %φapp_ToA_on_ToA+50]:
  " ToA_App_Conv TYPE('ca) TYPE('c) T (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P') (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P)
 φIntroFrameVar R X'' X Y'' Y
 x  T 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X'' 𝗐𝗂𝗍𝗁 P2
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P'))
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇() 𝗂𝗌 x  T))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇() 𝗂𝗌 Y'')  P  P2)"
  for T :: ('c::sep_magma,'a) φ and T' :: ('ca::sep_magma,'aa) φ
  unfolding φIntroFrameVar_def φApplication_def Action_Tag_def ToA_App_Conv_def
  by ((cases R; simp),
      metis φapply_implication_impl,
      meson φapply_implication_impl transformation_right_frame)


lemma [φreason %φapp_ToA_on_ToA+50]:
  " ToA_App_Conv TYPE('ca) TYPE('c) T (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P') (X 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y 𝗐𝗂𝗍𝗁 P)
 φIntroFrameVar R'' X'' X Y'' Y
 (x  T) * R 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 X'' 𝗐𝗂𝗍𝗁 P2
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (x'  T' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 Y' 𝗐𝗂𝗍𝗁 P'))
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇() 𝗂𝗌 (x  T) * R))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇() 𝗂𝗌 Y'')  P  P2)"
  for T :: ('c::sep_magma,'a) φ and T' :: ('ca::sep_magma,'aa) φ
  unfolding φIntroFrameVar_def φApplication_def Action_Tag_def ToA_App_Conv_def
  by ((cases R''; simp),
      metis φapply_implication_impl,
      meson φapply_implication_impl transformation_right_frame)


lemma [φreason %φapp_ToA_on_ToA+20]:
  "φIntroFrameVar R S'' S' T T'
 S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S'' 𝗐𝗂𝗍𝗁 Any
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (S' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T' 𝗐𝗂𝗍𝗁 P))
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 T)  P)"
  for S' :: 'c::sep_magma BI
  unfolding φIntroFrameVar_def φApplication_def Action_Tag_def
  by (cases R; simp; meson φapply_implication_impl transformation_right_frame)

lemma [φreason %φapp_ToA_on_ToA+20]:
  "φIntroFrameVar R S'' S' T T'
 S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S'' 𝗐𝗂𝗍𝗁 Any
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (S' = T'))
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 T))"
  for S' :: 'c::sep_magma BI
  unfolding φIntroFrameVar_def φApplication_def Action_Tag_def
  by (cases R; simp; meson φapply_implication_impl transformation_left_frame)


lemma [φreason %φapp_ToA_on_ToA]:
  " S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S' 𝗐𝗂𝗍𝗁 Any
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (S' 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 T 𝗐𝗂𝗍𝗁 P))
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇() 𝗂𝗌 S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇() 𝗂𝗌 T)  P)"
  for S' :: 'c::type BI
  unfolding φApplication_def Action_Tag_def ToA_Construction_def Transformation_def
  by metis

lemma [φreason %φapp_ToA_on_ToA]:
  " S 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 S' 𝗐𝗂𝗍𝗁 Any
 𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True
 PROP φApplication (Trueprop (S' = T))
      (Trueprop (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 S))
      (𝗈𝖻𝗅𝗂𝗀𝖺𝗍𝗂𝗈𝗇 True  (𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(x) 𝗂𝗌 T))"
  for S' :: 'c::type BI
  unfolding φApplication_def Action_Tag_def ToA_Construction_def Transformation_def
  by metis
  

subsection ‹Action›

text ‹Action provides a kind of meta calling mechanism.
  The expression of an action is nothing but a syntactical symbol.
  The symbol itself does not given any semantic information about what it does exactly.
  Its effect to the programming is interpreted by reasoning, or more specifically, by the
    configured reasoning rules binding on the action symbol.
  The rules perform the actual transformations, applications, or any other operations.
  And this performance defines the semantics of the action.

  Applying an action can be read as invoking certain automatic operation linked to the name of the
  action, to do some transformations or generate some code or do anything feasible.
  It makes the action calling very flexible.
  Semantic conversion made by reasoners written in ML can be involved, which gives
  sufficient space for many automatic operation.
›

(*TODO: polish below*)

text ‹The action symbol is encoded to be a fixed free variable or a constant of typaction.
  Therefore the pattern matching can be native and fast.
  Note an action can be parameterized like, typnat  bool  action parameterized
    by a nat and a boolean. Other parameters can come from the sequent.
›

text propA @tag Act tells antecedent propA is bound to the action Act, typically
  a procedure rule or an implication or a view shift rule.›

definition Do_Action :: action  prop  prop  prop
  where Do_Action action sequent result  (PROP sequent  PROP result)

text propPROP Do_Action action sequent result is the antecedent to be reasoned
  to return the construction result of the sequent by the action.›

declare [[φreason_default_pattern PROP Do_Action ?A ?S _  PROP Do_Action ?A ?S _ (100) ]]


subsubsection ‹Two Methods of Applying Action›

text ‹There are two way to activate the construction of an action.
  One is by application mechanism where user inputs a theorem of shape propPROP Call_Action action;
  another is by synthesis, where user inputs a cartouche of termaction.›

paragraph ‹First way, by Application›

definition Call_Action :: action  bool where Call_Action _  True

lemma Call_Action_I[intro!]: Call_Action Act unfolding Call_Action_def ..

lemma [φreason %φapplication]:
  PROP Do_Action action sequent result
 PROP φApplication (Trueprop (Call_Action action)) sequent result
  unfolding φApplication_def Do_Action_def .

paragraph ‹Second way, by Synthesis›

lemma [φreason 1400]:
  𝗋CALL Synthesis_Parse action action'
 PROP Do_Action action' sequent result
 𝗋Success
 PROP DoSynthesis action sequent result
  for action :: action
  unfolding DoSynthesis_def Do_Action_def .
(*
subsubsection ‹Classes of Actions›

class view_shift  (* The action can be a view shift. FIX ME: the semantics of them is very unclear *)
class implication (* The action can be an implication *)
class procedure   (* The action can be a procedure *)
class simplification begin
subclass implication .
end
class multi_args_fixed_first
    (* The action may has multiple arguments, but the first argument is fixed to be
       the first one in the sequent to be applied. The remain arguments can be out of
       order in the sequent.
       The action has to always have the shape of `?remain_args ❟ ?the_first_arg ⟼ ⋯`
        even when the ?remain_args is the Void. *)
class single_target (* The argument of the action consists of only the first φ-Type element. *)
class whole_target (* The action applies on the whole assertion. *)
class structural (* structural homomorphism, A ⟼ B ⟹ T(A) ⟼ T(B) *)
class structural_1_2 (* homomorphism of form A ⟼ B * C ⟹ T(A) ⟼ T(B) * T(C) *)
class structural_2_1 (* homomorphism of form A * B ⟼ C ⟹ T(A) * T(B) ⟼ T(C) *)

typedecl implication_single_target_structural
instance implication_single_target_structural :: implication ..
instance implication_single_target_structural :: single_target ..
instance implication_single_target_structural :: structural ..

typedecl simplification
instance simplification :: simplification .. *)

subsubsection ‹Rules of Executing Action›

paragraph ‹Fallback›

lemma [φreason 1]:
  FAIL TEXT(‹Don't know how to do› action ‹on› Sequent)
 PROP Do_Action action Sequent Sequent
  unfolding Do_Action_def Action_Tag_def Action_Tag_def .


subsection ‹Generic Element Access›

subsubsection ‹Get Element of Abstract Object›

type_synonym element_index_input = (VAL × VAL BI) list

definition Get_Abstract_Element :: 'x  ('val,'x) φ  element_index_input  'y  bool
  where Get_Abstract_Element x T path y  True
  ― ‹Purely syntactic›

declare [[
  φreason_default_pattern Get_Abstract_Element ?x ?T ?path _  Get_Abstract_Element ?x ?T ?path _ (100)
]]

lemma [φreason 1000]:
  Get_Abstract_Element x T [] x
  unfolding Get_Abstract_Element_def ..

subsection ‹Streamlined Parse for Element Index›

definition report_unprocessed_element_index :: element_index_input  action  bool
  where report_unprocessed_element_index path final_hook  True
  ― ‹Flow style processing of element index. A reasoning process can accept some leading part of the
      index and reject the remains to leave to other processors. ›

declare [[
  φreason_default_pattern report_unprocessed_element_index ?path _  report_unprocessed_element_index ?path _ (100),
  φpremise_attribute once? [φreason? %local] for report_unprocessed_element_index _ _  (%φattr)
]]

lemma report_unprocessed_element_index_I:
  report_unprocessed_element_index path any
  unfolding report_unprocessed_element_index_def ..

definition chk_element_index_all_solved :: element_index_input  bool
  where chk_element_index_all_solved path  True

subsubsection ‹ML›               

consts ℰℐℋ𝒪𝒪𝒦_none    :: action

ML_file ‹library/system/generic_element_access.ML›

φreasoner_ML chk_element_index_all_solved 1000 (chk_element_index_all_solved _) = fn (_, (ctxt,sequent)) => Seq.make (fn () =>
  let val (_,_,ant,_) =
        Phi_Help.strip_meta_hhf_c (fst (Thm.dest_implies (Thm.cprop_of sequent))) ctxt
      val idx = Thm.dest_arg (Thm.dest_arg ant)
   in if Generic_Element_Access.is_empty_input (Thm.term_of idx)
      then SOME ((ctxt, @{thm report_unprocessed_element_index_I} RS sequent),
                Seq.empty)
      else (
        warning (Pretty.string_of (Pretty.block [
            Pretty.str "Fail to access element ",
            Syntax.pretty_term ctxt (Thm.term_of idx)
        ])) ;
        NONE )
  end)

φreasoner_ML report_unprocessed_element_index 1000 (report_unprocessed_element_index _ _) = fn (_, (ctxt,sequent)) => Seq.make (fn () =>
  let val (_,_,ant,_) =
        Phi_Help.strip_meta_hhf_c (fst (Thm.dest_implies (Thm.cprop_of sequent))) ctxt
      val main = Thm.dest_arg ant
      val hook = Thm.dest_arg main
      val idx  = Thm.dest_arg (Thm.dest_fun main)
   in if Generic_Element_Access.is_empty_input (Thm.term_of idx)
         orelse Generic_Element_Access.is_enabled_report_unprocessed_element_index ctxt
      then SOME ((Generic_Element_Access.report_unprocessed_element_index (idx, hook) ctxt,
                 @{thm report_unprocessed_element_index_I} RS sequent),
                Seq.empty)
      else Generic_Element_Access.error_unprocessed_element_index ctxt idx
  end)


subsection ‹Generic Variable Access›

subsubsection ‹Annotation›

definition Value_of :: 'x  'v  element_index_input  'x ("_ <val-of> _ <path> _" [23,23,23] 22)
  where [iff, φprogramming_base_simps]: (x <val-of> v <path> path) = x
  ― ‹This tag annotates that x› is the value of v› at its element path path›.

    One usage is during synthesis of variable access.
    When user types in $var› meaning to synthesis the value of variable var›,
    the system reasons ?x <val-of> var ⦂ 𝗏𝖺𝗅 ?T› which is semantically identical to
    ?x ⦂ 𝗏𝖺𝗅 T› but is annotated that what we want is not arbitrary ?x› but, the value
    of the variable var›. With the syntactical annotation, the reasoning can be properly
    configured to synthesis the desired value.›

definition Set_Value :: 'x  'v  element_index_input  'x ("_ <set-to> _ <path> _" [51, 1000, 51] 50)
  where [iff, φprogramming_base_simps]: (y <set-to> x <path> path) = y
  ― ‹This tag is mainly used in synthesis, annotating the action of assigning the element path›
      of value container x› with value y›. ›

declare [[
  φreason_default_pattern
      𝗉𝗋𝗈𝖼 _  ?X  λret. _ <val-of> ?v <path> ?path  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 ?R   𝗍𝗁𝗋𝗈𝗐𝗌 _ @tag synthesis 
      𝗉𝗋𝗈𝖼 _  ?X  λret. _ <val-of> ?v <path> ?path  _ 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 ?R'  𝗍𝗁𝗋𝗈𝗐𝗌 _ @tag synthesis    (120)
]]

subsubsection ‹Syntax›

(*I will disable the synthesis mechanism for accessing element by index
  because we have no spare syntax to assign the operation.
  The "‣" will be used in address arithmetic.
  Moreover, the same function is already provided by programming syntax, without the need of synthesis.*)

nonterminal φidentifier (* and φidentifier_element *)

syntax
  "_identifier_" :: "φidentifier  logic" ("$\"_")
  "_identifier_id_" :: id  φidentifier ("_")
  "_identifier_num_" :: num_token  φidentifier ("_")
  "_identifier_1_" :: φidentifier ("1")
  "_identifier_logic_" :: logic  φidentifier ("'(_')")
(*  "_identifier_element_0_" :: ‹φidentifier ⇒ φidentifier_element› ("_")
  "_identifier_element_"   :: ‹φidentifier_element ⇒ φ_ag_idx_ ⇒ φidentifier_element› (infixl "‣" 910)
  "_φelement_step_" :: ‹logic ⇒ φ_ag_idx_ ⇒ logic› (infixl "‣" 910) *)
  "_get_φvar_" :: "φidentifier  logic" ("$_")
  "_set_φvar_" :: "φidentifier  logic  logic" ("$_ := _" [910, 51] 50)

consts φidentifier :: "unit  unit" ― ‹used only in syntax parsing›

subsubsection ‹Rule \& Implementation›

lemma "__value_access_0__":
  𝗉𝗋𝗈𝖼 F  R  Y  𝗍𝗁𝗋𝗈𝗐𝗌 E
 𝗉𝗋𝗈𝖼 F  Void 𝗋𝖾𝗆𝖺𝗂𝗇𝗌 R  Y  𝗍𝗁𝗋𝗈𝗐𝗌 E
  unfolding REMAINS_def
  by fastforce

φreasoner_group local_values = (%cutting, [%cutting, %cutting]) for _
  ‹Facts demonstrating values of local variables›


(*
lemma [φreason 1000]:
  ‹ φSemType (x ⦂ T) TY
⟹ φSemType (x <val-of> any ⦂ T) TY›
  unfolding Value_of_def . *)

section ‹Implementing the Interactive Environment›

text ‹The implementation consists of three steps:
 building the ML systems and libraries;
 defining the Isar commands;
 defining ‹φlang_parsers›.
›

text ‹φProcessor realizes specific facilities for programming in a statement,
  such as applying an application, setting a parameter or a label, invoking program synthesis,
  proving a proof obligation, simplifying or transforming the state sequent,
  and fixing an existentially quantified variable.
›

subsection ‹Convention of Operator Precedence›


φreasoner_group φlang_precedence = (100, [0,1000])
      ‹precedence of component parsers of Isar/φ-lang.
      The parser will not be applied until the operator stack is evaluated down to (of a precedence
      less than) the designated precedence.
      It can be seen as the precedence of the symbol that the parser processes›
  and φlang_top = (1000, [1000,1000]) in φlang_precedence
      ‹technically used. No operator should be of this precedence.›
  and φlang_expr = (10, [10, 999]) in φlang_precedence < φlang_top
      ‹operators of expression›
  and φlang_statement = (1, [1, 9]) in φlang_precedence < φlang_expr
      ‹connectives of statement›
  and φlang_push_val = (950, [950,950]) in φlang_expr
      ‹pushing local value to thestate sequent›
  and φlang_dot_opr = (930, [930,930]) in φlang_expr and < φlang_push_val
      ‹dot operator ‹‣››
  and φlang_deref = (910, [910,910]) in φlang_expr and < φlang_dot_opr
      ‹dereference operator›
  and φlang_app = (900, [900,900]) in φlang_expr and < φlang_dot_opr
      ‹precedence of lambda application›
  and φlang_update_opr = (50, [50,50]) in φlang_expr and < φlang_app
      ‹‹:=›, as an arithmetic operartor›
  and φlang_assignment = (5, [5,5]) in φlang_statement and < φlang_update_opr
      ‹‹←›, as a connective of statement›

φreasoner_group φparser_priority = (0, [0, 10000])
    ‹priority of component parsers of Isar/φ-lang, deciding which parser will be applied when multiple
    candidates are available anytime. Lower is of more priority.›
 and φparser_app = (500, [0, 10000]) in φparser_priority
    ‹parsers for application›
 and φparser_lpar = (50, [0,100]) in φparser_priority ‹›
 and φparser_rpar = (100, [100,100]) in φparser_priority ‹›
 and φparser_cartouch_all = (0, [0,100]) in φparser_priority
    ‹parsers accepting a cartouche›
 and φparser_synthesis = (100, [100,100]) in φparser_cartouch_all ‹›
 and φparser_cartouch = (0, [0, 99]) in φparser_cartouch_all and < φparser_synthesis ‹›
 and φparser_unique = (500,[500,500]) in φparser_priority
    ‹a default group for components of no ambiguity›
 and φparser_right_arrow = (500,[500,500]) in φparser_priority ‹›
 and φparser_left_arrow = (500,[500,500]) in φparser_priority ‹›
 and φparser_var_decl = (500,[400,600]) in φparser_priority ‹›


subsection ‹ML codes›

ML_file "library/instructions.ML"
ML_file "library/tools/parse.ML"

ML_file ‹library/system/post-app-handlers.ML›
ML_file "library/system/procedure.ML"
ML_file ‹library/system/sys0.ML›
ML_file ‹library/system/generic_variable_access.ML›
ML_file ‹library/system/sys.ML›
ML_file ‹library/system/opr_stack.ML›
ML_file ‹library/system/toplevel0.ML›
ML_file ‹library/system/opr_stack2.ML›
ML_file "library/system/processor.ML"

ML_file ‹library/system/generic_variable_access2.ML›
ML_file ‹library/system/obtain.ML›
(* ML_file "./codegen/compilation.ML" *)
ML_file ‹library/system/modifier.ML›
ML_file ‹library/system/toplevel.ML›
ML_file ‹library/tools/CoP_simp_supp.ML›
ML_file ‹library/system/generic_element_access2.ML›

subsubsection ‹Setups›

hide_fact "__value_access_0__"

setup Context.theory_map (
  Generic_Element_Access.register_hook (const_nameℰℐℋ𝒪𝒪𝒦_none, K (K I))
)

subsection ‹Isar Commands \& Attributes›

ML Theory.setup (Global_Theory.add_thms_dynamic (@{binding "φinstr"}, NuInstructions.list_definitions #> map snd))

attribute_setup φinstr = Scan.succeed (Thm.declaration_attribute NuInstructions.add)
  ‹Instructions of φ-system›

(*attribute_setup elim_premise_tag = ‹
Scan.succeed (Thm.rule_attribute [] (fn _ => fn th =>
      if can PLPR_Syntax.dest_premise_tag (Thm.concl_of th) then th RS @{thm Premise_D} else th))
›

attribute_setup elim_Do_tag = ‹
Scan.succeed (Thm.rule_attribute [] (fn _ => fn th =>
  case Thm.concl_of th
    of Const(const_name‹Do›, _) $ _ => th RS @{thm Do_D}
     | _ => th))
›

attribute_setup elim_Simplify_tag = ‹
Scan.succeed (Thm.rule_attribute [] (fn ctxt' =>
  let val ctxt = Context.proof_of ctxt'
   in Conv.fconv_rule (Phi_Conv.hhf_concl_conv (fn ctxt => fn ctm =>
        Phi_Conv.tag_conv (Conv.rewr_conv @{thm' Simplify_def}) ctm) ctxt)
  end))
›
*)

declare [[φpremise_attribute  [THEN Do_D] for 𝖽𝗈 PROP _          (%φattr_normalize),
          φpremise_attribute  [THEN Premise_D] for 𝗉𝗋𝖾𝗆𝗂𝗌𝖾 ?x     (%φattr_late_normalize),
          φpremise_attribute  [THEN Premise_D] for 𝖼𝗈𝗇𝖽𝗂𝗍𝗂𝗈𝗇[_] ?x (%φattr_late_normalize),
          φpremise_attribute once? [φreason? %local] for Semantic_Type _ _ 𝖽𝗈 Semantic_Type _ _ (%φattr),
          φpremise_attribute once? [φreason? %local] for Semantic_Zero_Val _ _ _ 𝖽𝗈 Semantic_Zero_Val _ _ _ (%φattr),
          φpremise_attribute  [THEN Simplify_D] for Simplify _ _ _ 𝖽𝗈 Simplify _ _ _   (%φattr_late_normalize),
          φpremise_attribute once? [φreason? %local] for Is_Functional ?S     (%φattr),
          φpremise_attribute once? [φreason? %local] for _ 𝗍𝗋𝖺𝗇𝗌𝖿𝗈𝗋𝗆𝗌 _ 𝗐𝗂𝗍𝗁 _  (%φattr)
]]


subsection ‹User Interface Processors›

text ‹Convention of priorities:
   Simplifications and Conversions for canonical forms < 1000
   Reasoning Antecedents = 1000
   General Application not bound on specific pattern or keyword : 9000~9999
›

subsubsection ‹Controls›

φlang_parser set_auto_level (10, %φlang_app) ["!!", "!!!"] (PROP ?P)
  (fn (oprs, (ctxt, sequent)) => Phi_Parse.auto_level_force >>
      (fn auto_level' => fn _ =>
          (oprs, (Config.put Phi_Reasoner.auto_level auto_level' ctxt, sequent))))
 ― ‹Note the declared auto-level is only valid during the current statement.
    In the next statement, the auto-level will be reset to the default fully-automated level.›


(*
φlang_parser repeat 12 (‹PROP ?P›) ‹let
  in fn (ctxt, sequent) =>
    Parse.not_eof -- ((Parse.$$$ "^" |-- Parse.number) || Parse.$$$ "^*") >> (fn (tok,n) => fn () =>
        (case Int.fromString n of SOME n => funpow n | _ => error ("should be a number: "^n))
          (Phi_Processor.process_by_input [tok]) (ctxt, sequent)
    )
  end› *)


subsubsection ‹Constructive›

lemma φcast_exception_UI:
  " PendingConstruction f blk H T E
 (a. 𝗎𝗌𝖾𝗋 E a 𝗌𝗁𝗂𝖿𝗍𝗌 E' a)
 PendingConstruction f blk H T E'"
  unfolding Argument_def
  using φapply_view_shift_pending_E .

(*immediately before the accept call*)
φlang_parser "throws" (%φparser_unique, 0) ["throws"] (𝗉𝖾𝗇𝖽𝗂𝗇𝗀 ?f 𝗈𝗇 ?blk [?H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?T 𝗍𝗁𝗋𝗈𝗐𝗌 ?E)
  fn (oprs, (ctxt, sequent)) => keywordthrows >> (fn _ => fn _ =>
      (oprs, (ctxt, sequent RS @{thm "φcast_exception_UI"})) )

hide_fact φcast_exception_UI

ML Generic_Variable_Access.lookup_bindings

(* Generic_Variable_Access.lookup_bindings *)

φlang_parser "apply" (%φparser_app, %φlang_app) ["", "apply_rule"] (PROP _)
fn (oprs,(ctxt,sequent)) =>
    Generic_Variable_Access.parser_no_lvar ctxt Phi_App_Rules.parser >> (fn xnames => fn cfg =>
  (oprs, (ctxt, sequent)
          |> Phi_Reasoners.wrap'' (Phi_Apply.apply1 (Phi_App_Rules.app_rules ctxt [xnames]))
  ))

φlang_parser delayed_apply (%φparser_app-200, %φlang_app) ["", "apply_rule"] (PROP _)
fn (opr_ctxt as (_,(ctxt,_))) =>
  (Phi_App_Rules.parser --| keyword() >> (fn xname => fn cfg =>
    let fun name_pos_of (Facts.Named (name_pos, _)) = name_pos
          | name_pos_of _ = ("", Position.none)
    in
      if Phi_Opr_Stack.synt_can_delay_apply' (Context.Proof ctxt) (fst xname)
      then Phi_Opr_Stack.begin_apply cfg (name_pos_of (fst xname), Phi_App_Rules.app_rules ctxt [xname]) opr_ctxt
      else raise Phi_CP_IDE.Bypass
    end)

φlang_parser apply_operator (%φparser_app-300, %φlang_top) [""] (PROP _)
fn (opr_ctxt as (_,(ctxt,_))) =>
  (Phi_App_Rules.symbol_position >> (fn (xname,pos) => fn cfg =>
    case Phi_Opr_Stack.lookup_operator (Proof_Context.theory_of ctxt) xname
      of NONE => raise Phi_CP_IDE.Bypass
       | SOME opr => (
          case Phi_Opr_Stack.lookup_meta_opr (Proof_Context.theory_of ctxt) xname
            of SOME meta =>
                Phi_Opr_Stack.push_meta_operator cfg (opr, (xname,pos), NONE, meta) opr_ctxt
             | NONE =>
                let val rules = Phi_App_Rules.app_rules ctxt [(Facts.Named ((xname,pos), NONE), [])]
                 in Phi_Opr_Stack.push_operator cfg (opr, (xname,pos), rules) opr_ctxt
                end)
  ))

φlang_parser open_parenthesis (%φparser_lpar, %φlang_push_val) ["("] (PROP _)
fn s => (Parse.position keyword() >> (fn (_, pos) => fn _ =>
    Phi_Opr_Stack.open_parenthesis (NONE, pos) s)

φlang_parser close_parenthensis (%φparser_rpar, %φlang_top) [")"] (PROP _)
fn s => keyword) >> (fn _ => fn cfg => Phi_Opr_Stack.close_parenthesis (cfg, NONE, false) s)

φlang_parser comma (%φparser_unique, %φlang_top) [","] (?P) fn s => 
  Parse.position keyword, -- Scan.option (Parse.short_ident --| keyword:)
>> (fn ((_,pos), arg_name) => fn cfg => Phi_Opr_Stack.comma cfg (arg_name, pos) s)

φlang_parser embedded_block (%φparser_lpar-20, %φlang_expr) ["("] (PROP ?P  PROP ?Q)
fn stat => (Parse.position keyword( >> (fn (_, pos) => fn _ =>
  stat |> Phi_Opr_Stack.begin_block pos
       |> apsnd (Phi_CP_IDE.proof_state_call (Phi_Toplevel.begin_block_cmd ([],[]) false)) ))

φlang_parser delimiter_of_statement (%φparser_unique, 0) [";"] (CurrentConstruction ?mode ?blk ?H ?S | 𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?s) 𝗂𝗌 ?S')
fn (s as (_, (ctxt, _))) => keyword; >> (fn _ => fn cfg =>
    s |> Phi_Opr_Stack.End_of_Statement.invoke (Context.Proof ctxt) cfg
      |> Phi_Opr_Stack.Begin_of_Statement.invoke (Context.Proof ctxt) cfg)

φlang_parser set_param (%φparser_cartouch, %φlang_expr) ["<cartouche>", ""] (𝗉𝖺𝗋𝖺𝗆 ?P  PROP _)
fn s => Parse.term >> (fn term => fn _ => apsnd (Phi_Sys.set_param_cmd term) s)

φlang_parser set_label (%φparser_cartouch, %φlang_expr) ["<cartouche>"] (𝗅𝖺𝖻𝖾𝗅 ?P  PROP _)
fn s => Parse.name >> (fn name => fn _ => apsnd (Phi_Sys.set_label name) s)

φlang_parser rule (%φparser_app, %φlang_expr) [] (PROP ?P  PROP ?Q)
  fn (oprs, (ctxt, sequent)) => Phi_App_Rules.parser >> (fn thm => fn _ =>
    let open Phi_Envir
        val apps = Phi_App_Rules.app_rules ctxt [thm]
        val sequent = perhaps (try (fn th => @{thm Argument_I} RS th)) sequent
     in (oprs, Phi_Reasoners.wrap'' (Phi_Apply.apply1 apps) (ctxt,sequent))
    end)

(* case Seq.pull (Thm.biresolution (SOME ctxt) false (map (pair false) apps) 1 sequent)
         of SOME (th, _) => (ctxt,th)
          | _ => raise THM ("RSN: no unifiers", 1, sequent::apps) *)

ML val phi_synthesis_parsing = Attrib.setup_config_bool bindingφ_synthesis_parsing (K false)

fun phi_synthesis_parser (oprs, (ctxt, sequent)) F (raw_term, pos) cfg = 
  let val ctxt_parser = Proof_Context.set_mode Proof_Context.mode_pattern ctxt
                        |> Config.put phi_synthesis_parsing true
                        |> Config.put Generic_Variable_Access.mode_synthesis true
      val binds = Variable.binds_of ctxt_parser
      val term = Syntax.parse_term ctxt_parser raw_term                               
                    |> Term.map_aterms (
                          fn X as Var (name, _) =>
                              (case Vartab.lookup binds name of SOME (_,Y) => Y | _ => X)
                           | X => X
                       ) (*patch to enable term binding*)
                    |> F ctxt
                    |> Syntax.check_term ctxt_parser
                    |> Thm.cterm_of ctxt

      val mode_subproc = Phi_Opr_Stack.precedence_of (#1 oprs) < 0 andalso
                            (case Thm.prop_of sequent
                               of Const (const_namePure.imp, _) $ _ $ _ => true
                                | _ => false)
   in if mode_subproc
   then (oprs, Phi_Reasoners.wrap'' (Phi_Sys.synthesis term) (ctxt, sequent))
   else Phi_Opr_Stack.push_meta_operator cfg
            ((@{priority %φlang_push_val}, @{priority loose %φlang_push_val},
                      (VAR_ARITY_IN_SEQUENT, VAR_ARITY_IN_SEQUENT)), ("<synthesis>", pos), NONE,
            (fn (_,_,_,vals) =>
                (apsnd ( Generic_Variable_Access.push_values vals
                      #> Phi_Reasoners.wrap'' (Phi_Sys.synthesis term)
                       )))) (oprs, (ctxt, sequent))
  end

φlang_parser synthesis (%φparser_synthesis, %φlang_push_val) ["<cartouche>", "<number>"] (PROP _)
  fn s =>
   Parse.position (Parse.group (fn () => "term") (Parse.inner_syntax (Parse.cartouche || Parse.number)))
>> phi_synthesis_parser s (K I)


(*access local value or variable or any generic variables*)
φlang_parser get_var (%φparser_unique, %φlang_push_val) ["$"] (PROP _)  fn (oprs,(ctxt,sequent)) => keyword$ |--
        Parse.position (Phi_CP_IDE.long_idt_to_triangle (Parse.short_ident || Parse.number))
  >> (fn (var,pos) => fn cfg =>
    let val get = Phi_Reasoners.wrap'' (Generic_Variable_Access.get_value var Generic_Element_Access.empty_input)
        val mode_subproc = Phi_Opr_Stack.precedence_of (#1 oprs) < 0 andalso
                          (case Thm.prop_of sequent
                             of Const (const_namePure.imp, _) $ _ $ _ => true
                              | _ => false)
    in if mode_subproc
    then (oprs, get (ctxt,sequent))
    else Phi_Opr_Stack.push_meta_operator cfg
            ((@{priority %φlang_push_val}, @{priority loose %φlang_push_val}, (0, 0)),
                ("$", pos), SOME (Phi_Opr_Stack.String_Param var),
                (fn _ => fn (oprs, s) => (oprs, get s)))
            (oprs,(ctxt,sequent))
    end)

φlang_parser assignment (%φparser_right_arrow, 0) ["→"] (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 ?blk [?H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?S) fn opr_ctxt => (keyword |-- Parse.list1 ( Scan.option keyword$ |-- Scan.option Parse.keyword
                                            --| Scan.option keyword$ -- Parse.binding))
>> (fn vars => fn cfg =>
  let open Generic_Element_Access
    val (vars', _ ) =
          fold_map (fn (NONE,b)    => (fn k' => ((k',(b,empty_input)),k'))
                     | (SOME k, b) => (fn _  => ((SOME k, (b,empty_input)), SOME k))) vars NONE
  in apsnd (Generic_Variable_Access.assignment_cmd vars') opr_ctxt
  end
)

φlang_parser left_assignment (%φparser_var_decl, 0) ["var", "val"] (𝖼𝗎𝗋𝗋𝖾𝗇𝗍 ?blk [?H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?S) fn opr_ctxt =>
    Parse.list1 ((keywordvar || keywordval) -- Parse.list1 Parse.binding) --
    Parse.position (keyword || keyword=)
>> (fn (vars,(_,pos)) => fn cfg =>
  let open Generic_Element_Access
      val vars' = maps (fn (k,bs) => map (pair (SOME k) o rpair empty_input) bs) vars
   in Phi_Opr_Stack.push_meta_operator cfg
          ((0,@{priority %φlang_assignment}, (0, length vars')),("←",pos),NONE,
            fn (_,_,_,vals) => (apsnd (
                Generic_Variable_Access.push_values vals
             #> Generic_Variable_Access.assignment_cmd vars'
            ))) opr_ctxt
  end
)

φlang_parser existential_elimination (%φparser_unique, %φlang_expr) ["∃"]
                                    ( CurrentConstruction ?mode ?blk ?H (ExBI ?T)
                                    | ToA_Construction ?s (ExBI ?S) )
  fn s => (keyword |-- Parse.list1 Parse.binding) >> (fn insts => fn _ =>
      apsnd (Phi_CP_IDE.proof_state_call (NuObtain.choose insts)) s)



subsubsection ‹Simplifiers \& Reasoners›

subsubsection ‹Post-Application Process›

setup Context.theory_map (

   (*automatically solve proof obligations, if no keyword‹certified› is appended*)

   Phi_CP_IDE.Post_App.add 50 (fn arg => fn (ctxt, sequent) =>
    case Thm.prop_of sequent
      of Const(const_namePure.imp, _) $ _ $ _ =>
   (case Thm.major_prem_of sequent
      of _ (*Trueprop*) $ (Const (const_namePremise, _) $ _ $ Const (const_nameTrue, _))
         => (ctxt, @{thm Premise_True} RS sequent)
       | _ (*Trueprop*) $ (Const (const_namePremise, _) $ mode $ prop) => (
        if (case mode of Const(const_namedefault, _) => true
                       | Const(const_nameMODE_COLLECT, _) => true
                       | _ => false) andalso
           Config.get ctxt Phi_Reasoner.auto_level >= 2 andalso
           not (Symtab.defined (#config arg) "no_oblg")   andalso
           not (can keywordcertified (#toks arg))
        then let val id = Option.map (Phi_ID.encode o Phi_ID.cons (#id arg)) (Phi_ID.get_if_is_named ctxt)
                 val sequent' = Phi_Reasoners.obligation_intro_Ex_conv ~1 ctxt sequent
              in raise Phi_CP_IDE.Post_App.ReEntry (arg, (ctxt,
                          Phi_Sledgehammer_Solver.auto id (Phi_Envir.freeze_dynamic_lemmas ctxt) sequent'))
              handle Phi_Reasoners.Automation_Fail err =>
                  error (Pretty.string_of (Pretty.chunks (err ())))
             end
        else (ctxt, sequent))
       | _ => (ctxt, sequent)
     ) | _ => (ctxt, sequent)
   )

   (* process φ-LPR antecedents *)

#> Phi_CP_IDE.Post_App.add 100 (fn arg => fn (ctxt, sequent0) =>
    case Thm.prop_of sequent0
      of Const(const_namePure.imp, _) $ _ $ _ =>
          let val sequent = case Thm.major_prem_of sequent0
                              of Const(const_nameDo, _) $ _ => @{thm Do_I} RS sequent0
                               | _ => sequent0
          in if Config.get ctxt Phi_Reasoner.auto_level >= 1
                andalso not (Phi_Sys_Reasoner.is_user_dependent_antecedent (Thm.major_prem_of sequent))
                andalso not (Phi_Sys_Reasoner.is_proof_obligation (Thm.major_prem_of sequent))
             then (
                Phi_Reasoner.info_print ctxt 2 (fn _ =>
                      "reasoning the leading antecedent of the state sequent." ^ Position.here ) ;
                Phi_Reasoner.reason1 (fn () => let open Pretty in string_of (
                                                 chunks [para "Fail to solve a φ-LPR antecedent",
                                                         Thm.pretty_thm ctxt sequent]
                                               ) end)
                                     NONE (SOME 1) ctxt sequent
                |> (fn sequent =>
                        raise Phi_CP_IDE.Post_App.ReEntry (arg, (ctxt, sequent)) ))
             else (ctxt, sequent0)
          end
       | _ => (ctxt, sequent0)
   )

   (*move any obtained pure facts, ‹_ ∧ _›*)
#> Phi_CP_IDE.Post_App.add 200 (K (Phi_Sys.move_lemmata Position.none))

   (*simplification*)
#> let val rewr_objects = Phi_Syntax.conv_all_typings (Conv.arg1_conv o Simplifier.rewrite)
    in Phi_CP_IDE.Post_App.add 300 (K (fn (ctxt, sequent) =>
    let fun conv_conds ctxt ctm = Phi_Conv.hhf_conv conv_conds
              (Phi_Conv.hhf_concl_conv (fn ctxt => Conv.try_conv (
               PLPR_Syntax.premise_tag_conv (fn Const(const_namedefault, _) => true
                                              | Const(const_nameMODE_GUARD, _) => true
                                              | _ => false) (Simplifier.rewrite ctxt))))
              ctxt ctm
        fun conv_sequent C ctxt =
              Conv.gconv_rule (Phi_Conv.hhf_conv conv_conds
                  (Phi_Conv.tag_conv o C) ctxt) 1
        val simplifier =
              case Thm.prop_of sequent
                of Const(const_nameTrueprop, _) $ _ =>
                      let val mode = Phi_Working_Mode.mode1 ctxt
                       in #IDECP_simp mode (ctxt, sequent)
                      end
                 | _ => (
              case Term.head_of (PLPR_Syntax.dest_tags (Thm.major_prem_of sequent))
                of Const(const_nameφProcedure, _) =>
                      SOME (conv_sequent (fn ctxt =>
                        Phi_Syntax.procedure_conv Conv.all_conv
                          (rewr_objects ctxt) (rewr_objects ctxt) (rewr_objects ctxt)))
                 | Const(const_nameView_Shift, _) =>
                      SOME (conv_sequent (fn ctxt =>
                        Phi_Syntax.view_shift_conv (rewr_objects ctxt) (rewr_objects ctxt) Conv.all_conv))
                 | Const(const_nameTransformation, _) =>
                      SOME (conv_sequent (fn ctxt =>
                        Phi_Syntax.view_shift_conv (rewr_objects ctxt) (rewr_objects ctxt) Conv.all_conv))
                 | _ => NONE)
    in case simplifier
    of NONE => (ctxt, sequent)
     | SOME rewr =>
        let val lev = Config.get ctxt Phi_Reasoner.auto_level
            val sctxt = if lev <= 0
                        then raise Phi_CP_IDE.Post_App.Return (ctxt, sequent)
                        else equip_Phi_Programming_Simp lev ctxt
            val sequent' = rewr sctxt sequent
                        |> Phi_Help.beta_eta_contract
        in (ctxt, sequent')
        end
end)) end

#> Phi_CP_IDE.Post_App.add 320 (fn arg => fn (ctxt, sequent) =>
    case Thm.prop_of sequent
      of prop as Const(const_nameTrueprop, _) $ _ =>
   (case Phi_Working_Mode.mode ctxt
      of SOME mode =>
            if #constr_is_ready mode prop
            then (case Phi_CoP_Simp.invoke_when_needed (ctxt,mode) sequent
                    of SOME sequent' => raise Phi_CP_IDE.Post_App.ReEntry (arg, (ctxt, sequent'))
                     | NONE => (ctxt, sequent))
            else (ctxt, sequent)
       | NONE => (ctxt, sequent))
       | _ => (ctxt, sequent))

#> Phi_CP_IDE.Post_App.add 400 (K (Phi_Sys.move_lemmata Position.none))

#> Phi_CP_IDE.Post_App.add 500 (fn arg => fn s =>
      if (case Thm.prop_of (snd s)
            of _ (*Trueprop*) $ (Const(const_namePendingConstruction, _) $ _ $ _ $ _ $ _ $ _) => true
             | _ => false) andalso
         not (Symtab.defined (#config arg) "no_accept_proc") andalso
         not (can keywordthrows (#toks arg))
      then raise Phi_CP_IDE.Post_App.ReEntry (arg, Phi_Sys.accept_proc s)
      else s)

   (*automatic elimination of existential quantifiers*)
#> Phi_CP_IDE.Post_App.add 600 (fn arg => fn (ctxt,sequent) =>
    if (case Thm.prop_of sequent of Const(const_nameTrueprop, _) $ _ => true
                                  | _ => false) andalso
       Config.get ctxt NuObtain.enable_auto andalso
       Config.get ctxt Phi_Reasoner.auto_level >= 2 andalso
       not (can keyword (#toks arg))
    then let val mode = Phi_Working_Mode.mode1 ctxt
      in case #spec_of mode (Thm.concl_of sequent)
           of Const (const_nameExBI, _) $ _ =>
                raise Phi_CP_IDE.Post_App.ReEntry (arg, Phi_CP_IDE.proof_state_call NuObtain.auto_choose (ctxt,sequent))
            | _ => (ctxt,sequent)
     end
    else (ctxt,sequent)
  )

   (*should be the end of the processing*)
#> Phi_CP_IDE.Post_App.add 999 (K (fn (ctxt, sequent) =>
      (Phi_Envir.update_programming_sequent' sequent ctxt, sequent)
   ))

)

(* TODO!
φlang_parser automatic_morphism 90 (‹CurrentConstruction ?mode ?blk ?H ?T› | ‹𝖺𝖻𝗌𝗍𝗋𝖺𝖼𝗍𝗂𝗈𝗇(?x) 𝗂𝗌 ?S›)
‹not_safe (fn stat => Scan.succeed (fn _ => Phi_Sys.apply_automatic_morphism stat
      handle Empty => raise Bypass NONE))›
*)

φlang_parser enter_proof (%φparser_unique, %φlang_expr) ["certified"]
                         (Premise _ _  PROP _ | Simplify _ _ _  PROP _ | ?Bool)
  fn stat => keywordcertified |-- Phi_Opr_Stack.end_of_input >> (fn _ => fn cfg => stat
   |> apsnd (fn s =>
      let val _ = if Thm.no_prems (#2 s) orelse
                     (case Thm.major_prem_of (#2 s)
                        of Const(const_nameTrueprop, _) $ (Const(const_namePremise, _) $ _ $ _)
                             => false
                         | _ => true)
                  then error "No Subgoal!"
                  else ()
       in s
       |> Phi_Reasoners.wrap'' (Phi_Reasoners.obligation_intro_Ex_conv ~1)
       |> Phi_CP_IDE.proof_state_call (snd o Phi_Toplevel.prove_prem (cfg,false) I)
      end)
   |> Phi_Opr_Stack.interrupt
 )


φlang_parser "holds_fact" (%φparser_unique, %φlang_expr) ["holds_fact"] (PROP ?P) let
  val for_fixes = Scan.optional (Parse.$$$ "for" |-- Parse.!!! Parse.params) [];
  val statement = Parse.and_list1 (
          Parse_Spec.opt_thm_name ":" -- Scan.repeat1 Parse.prop -- for_fixes);
in
  fn (oprs, (ctxt, sequent)) => Parse.position keywordholds_fact -- statement >> (
  fn ((_,pos), raw_statements) => fn _ =>
  let val id = Phi_ID.get ctxt

      (*We first generate names of the facts if not given*)
      fun gen_name (_, ids) = String.concatWith "_" ("φfact" :: rev_map string_of_int [] ids)
      val ctxt' = fold_index (fn (i,(((b', raw_attrs),bodys'),fixes)) => fn ctxt =>
        let val id' = Phi_ID.cons [i] id
            fun id'' j = if fst id' = "" then NONE else SOME (Phi_ID.encode (Phi_ID.cons [j] id'))
            val attrs = map (Attrib.check_src ctxt #> Attrib.attribute_cmd ctxt) raw_attrs

            val b = if Binding.is_empty b'
                    then Binding.make (gen_name id', pos)
                    else b'
            val ctxt' = Proof_Context.add_fixes_cmd fixes ctxt |> snd
                     |> Phi_Envir.freeze_dynamic_lemmas
            val thms = map (Syntax.parse_prop ctxt') bodys'
                     |> Syntax.check_props ctxt'
                     |> map_index (fn (j,term) => term
                          |> Thm.cterm_of ctxt'
                          |> Goal.init
                          |> (fn thm => Phi_Sledgehammer_Solver.auto (id'' j) ctxt'
                                            (@{thm Premise_D[where mode=default]} RS thm))
                          |> Goal.conclude
                          |> single
                          |> Variable.export ctxt' ctxt
                          |> rpair []
                      )
          in snd (Proof_Context.note_thms "" ((b,attrs), thms) ctxt) end
    ) raw_statements ctxt

   in (oprs, (ctxt', sequent))
  end
)
end

φlang_parser fold (%φparser_unique, %φlang_expr) ["fold"] (PROP ?P) fn (oprs, (ctxt, sequent)) => Phi_Parse.$$$ "fold" |-- Parse.list1 Parse.thm >> (fn thms => fn _ =>
    (oprs, (ctxt, Local_Defs.fold ctxt (Attrib.eval_thms ctxt thms) sequent))
)

φlang_parser unfold (%φparser_unique, %φlang_expr) ["unfold"] (PROP ?P) fn (oprs, (ctxt, sequent)) => Phi_Parse.$$$ "unfold" |-- Parse.list1 Parse.thm >> (fn thms => fn _ =>
    (oprs, (ctxt, Local_Defs.unfold ctxt (Attrib.eval_thms ctxt thms) sequent))
)

φlang_parser simplify (%φparser_unique, %φlang_expr) ["simplify"] (PROP ?P) fn (oprs, (ctxt, sequent)) => Phi_Parse.$$$ "simplify" |-- keyword( |-- Parse.list Parse.thm --| keyword)
>> (fn thms => fn _ =>
    (oprs, (ctxt, Simplifier.full_simplify (ctxt addsimps Attrib.eval_thms ctxt thms) sequent))
)


(* φlang_parser goal 1300 ‹𝖼𝗎𝗋𝗋𝖾𝗇𝗍 ?blk [?H] 𝗋𝖾𝗌𝗎𝗅𝗍𝗌 𝗂𝗇 ?T› ‹
  fn (ctxt, sequent) => Parse.$$$ "goal" >> (fn _ => fn _ =>
    let
      val goal = Proof_Context.get_thm ctxt "φthesis" |> Drule.dest_term
      val (_,_,desired_nu) = Phi_Syntax.dest_procedure_c goal
      val ty = Thm.typ_of_cterm desired_nu
      val prot = Const (const_name‹Implicit_Protector›, ty --> ty) |> Thm.cterm_of ctxt
      val ctxt = Config.put Phi_Reasoner.auto_level 1 ctxt
    in Phi_Sys.cast (Thm.apply prot desired_nu) (ctxt,sequent) end
)› 

*)



end