Theory Routed_Exec_Refinement

theory Routed_Exec_Refinement
  imports
    DG_Local_State_Exec_Refinement
begin

section ‹Routed execution, once for every domain and context policy›

text ‹
  locale‹dg_domain_exec› already reduces a domain's obligation to the routed
  spine to three primitive commute facts. What it deliberately does not carry is the
  ∗‹routing› layer: the equation system a routed analysis actually solves, and the
  executable-to-abstract transport of its post-solution. Each domain, at each context
  policy, re-derived that layer, and because const‹routed_call_program› mentions no domain
  constant, those derivations differ only in the domain carrier, the routing function
  and a name prefix.

  This locale is that layer, stated once. It adds the seed-key pair the routed
  generator needs --- kept as parameters rather than a fixed datatype, so a domain
  keeps its own key type and this locale stays independent of how that type is
  eventually shared --- together with the executable and abstract routing functions
  and their agreement, and derives the commute and transport facts every routed
  instance needs. A context-insensitive instance passes const‹route_unit› on both
  sides, where agreement is free; a call-string instance passes its own routing
  function on each side and discharges the agreement from that function's own laws.

  Deliberately absent: the equation-system, solved-table and result ⬚‹definition›s
  themselves. They must stay concrete per-domain constants because they carry ‹[code]›
  equations, and locale‹dg_domain_exec›'s own ‹empty_pred_exact› is not
  dischargeable without fixing a concrete global set, so no locale carrying it can be
  interpreted globally. The domain keeps its definitions; what it stops re-proving is
  everything below.

  Also deliberately absent: the solver. The generated equation system is
  solver-independent, and ‹TD_side_upd_rule› already supplies
  ‹partial_post_solution› for every update rule on the menu, so a solver choice
  is an argument at the use site, never a parameter of the domain capability.
›


subsection ‹The buffered generator at any component›

text ‹
  The buffered generator a domain actually solves, reconciled with the unbuffered one
  the framework is stated over, for every component run as a specification. Both
  reshaping hooks are the identity: the buffered generator only asks a hook to hoist
  what it publishes at the buffered key ‹buffer_key›, and a component publishes nothing
  there, since its edge transfers, its entry and its return all read and write the
  local unknown only. Its queries do not change that: its channel is a pure function
  of the local value, so an asking transfer is still a local one.
›

theorem pp_dg_spec_of:
  assumes S: "S = dg_spec_of c"
    and ne: "⋀p ctx. seed p ctx ≠ buffer_key"
    and pp: "part_post_solution
     (routed_node_rhs_buffered intra_predecessor_addr_list call_site_list (λ_. buffer_key) route_st
        (λctx' src a. dg_spec_edge_program S a src (λ_. buffer_key))
        (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot))
        (routed_entry_seed_programs seed)
        g bot0 d0 g0)
     x0 sigma_st vars"
  shows "part_post_solution
     (routed_node_rhs intra_predecessor_addr_list call_site_list (λ_. buffer_key) route_st
        (λctx' src a. dg_spec_edge_program S a src (λ_. buffer_key))
        (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot))
        (routed_entry_seed_programs seed)
        g bot0 d0 g0)
     x0 sigma_st vars"
proof -
  have wf: "dg_spec_wf S" by (simp add: S)
  have intra_free: "sides_of_program (dg_spec_edge_program S a src (λ_. buffer_key)) τ z = bot"
    for a src τ z
    by (simp add: S dg_spec_edge_program_def)
  have cmb_free: "sides_of_program
      (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot) route' ctx' ca cc ex)
      τ (Inr buffer_key) = bot" for route' ctx' ca cc ex τ
    by (rule routed_call_program_side_free_at_buffer_key[OF wf])
       (auto simp: S local_transfer_def local_combine_transfer_def ne
         dest!: enter_runs_local_pub_bot)
  show ?thesis
  proof (rule part_post_solution_routed_node_rhs_buffered
      [where cmb_c =
        "routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot)"
         and it_c = "λctx' src a. dg_spec_edge_program S a src (λ_. buffer_key)"])
    show "⋀c' w. ∀p ∈ set (routed_contribution_programs intra_predecessor_addr_list
             call_site_list route_st (λctx' src a. dg_spec_edge_program S a src (λ_. buffer_key))
             (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot))
             (routed_entry_seed_programs seed) g c' w). sp_wf p"
      by (rule routed_contribution_programs_wf)
         (auto intro: sp_wf_dg_spec_edge_program[OF wf] sp_wf_routed_call_program[OF wf])
    then show "⋀c' w. ∀p ∈ set (routed_contribution_programs intra_predecessor_addr_list
             call_site_list route_st (λctx' src a. dg_spec_edge_program S a src (λ_. buffer_key))
             (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot))
             (routed_entry_seed_programs seed) g c' w). sp_wf p" .
    show "⋀c' src a τ. dg_local (sides_of_program (dg_spec_edge_program S a src (λ_. buffer_key)) τ
             (Inr ((λ_. buffer_key) c'))) = bot"
      by (simp add: intra_free bot_dg_state_def)
    show "⋀c' src a τ. dg_global (traverse_program (dg_spec_edge_program S a src (λ_. buffer_key)) τ)
           = dg_global (sides_of_program (dg_spec_edge_program S a src (λ_. buffer_key)) τ
               (Inr ((λ_. buffer_key) c')))"
      by (simp add: S dg_spec_edge_program_def bot_dg_state_def)
    show "⋀c' src a τ. sides_of_program (dg_spec_edge_program S a src (λ_. buffer_key)) τ
             (Inr ((λ_. buffer_key) c')) = bot"
      by (rule intra_free)
    show "⋀c' ca cc ex τ. dg_local (sides_of_program
             (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot) route_st c' ca cc ex)
             τ (Inr ((λ_. buffer_key) c'))) = bot"
      by (simp add: cmb_free bot_dg_state_def)
    show "⋀c' ca cc ex τ. dg_global (traverse_program
             (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot) route_st c' ca cc ex) τ)
           = dg_global (sides_of_program
               (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot) route_st c' ca cc ex)
               τ (Inr ((λ_. buffer_key) c')))"
      by (simp add: routed_call_program_global_free[OF wf] cmb_free bot_dg_state_def)
    show "⋀c' ca cc ex τ. sides_of_program
             (routed_call_program S (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot) route_st c' ca cc ex)
             τ (Inr ((λ_. buffer_key) c')) = bot"
      by (rule cmb_free)
    show "⋀c' w τ z x. x ∈ set (routed_entry_seed_programs seed route_st c' w)
           ⟹ sides_of_program x τ z = bot"
      by (rule routed_entry_seed_programs_free)
    show "⋀c' w τ x. x ∈ set (routed_entry_seed_programs seed route_st c' w)
           ⟹ dg_global (traverse_program x τ) = bot"
      by (rule routed_entry_seed_programs_local_only)
  qed (simp_all add: pp)
qed

text ‹
  ‹routed_domain_exec› adds call routing to ‹dg_domain_exec›: seed keys
  never collide with the analysis global, and routing and callee resolution on
  the executable state agree with their abstract versions after readback.
›

locale routed_domain_exec =
  dg_domain_exec 𝒢 empty_pred tf_st enter_st sk asn sp br bd rt en ev
  for 𝒢 :: "vname ⇒ bool"
    and empty_pred :: "'a::numeric_domain default_st ⇒ bool"
    and tf_st :: "edge_action ⇒ 'a default_st ⇒ 'a default_st"
    and enter_st :: "call_info ⇒ 'a default_st ⇒ 'a default_st"
    and sk :: "'a abs_state ⇒ 'a abs_state"
    and asn :: "vname ⇒ exp ⇒ 'a abs_state ⇒ 'a abs_state"
    and sp :: "special_call ⇒ vname ⇒ 'a abs_state ⇒ 'a abs_state"
    and br :: "exp ⇒ bool ⇒ 'a abs_state ⇒ 'a abs_state"
    and bd :: "pname ⇒ 'a abs_state ⇒ 'a abs_state"
    and rt :: "exp option ⇒ pname ⇒ 'a abs_state ⇒ 'a abs_state"
    and en :: "call_info ⇒ 'a abs_state ⇒ 'a abs_state"
    and ev :: "analysis_event ⇒ 'a abs_state ⇒ 'a abs_state" +
  fixes buffer_key :: 'k
    and seed :: "pp ⇒ 'c ⇒ 'k"
    and route_st :: "pp ⇒ 'c ⇒ 'a default_st lifted ⇒ call_action ⇒ 'c"
    and route_abs :: "pp ⇒ 'c ⇒ 'a abs_state lifted ⇒ call_action ⇒ 'c"
    and resolve_st :: "cfg ⇒ pp ⇒ pp ⇒ call_action ⇒ 'a default_st lifted ⇒ pname list"
    and resolve_abs :: "cfg ⇒ pp ⇒ pp ⇒ call_action ⇒ 'a abs_state lifted ⇒ pname list"
  assumes seed_ne_buffer_key [simp]: "⋀p ctx. seed p ctx ≠ buffer_key"
      and route_agree: "⋀u c' d ca. route_st u c' d ca
                          = route_abs u c' (readback 𝒢 d) ca"
      and resolve_agree: "⋀g w cc ca d. resolve_st g w cc ca d
                          = resolve_abs g w cc ca (readback 𝒢 d)"
begin

text ‹The routed combine tree commutes with the executable-to-abstract reader. ‹spec_st›
  and ‹spec_abs› come from locale‹dg_domain_exec›; nothing here mentions a domain
  constant beyond them, so one proof serves every instance. The caller continuation needs
  no hypothesis: const‹dg_spec_combine_transfer› already runs it inside the combine
  sub-tree.›

lemma dg_prog_st_commute_routed_call_program:
  "dg_reader_commute_gen.dg_prog_st_commute
     (map_lift (default_st_to_fun 𝒢)) (map_lift (default_st_to_fun 𝒢)) env
     (routed_call_program spec_st (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot) route_st ctx ca cc ex)
     (routed_call_program spec_abs (λ_. buffer_key) seed (resolve_abs g) (λd. d = Bot)
        route_abs ctx ca cc ex)"
  by (rule dg_reader_commute_gen.dg_prog_st_commute_routed_call_program
        [where Floc = "map_lift (default_st_to_fun 𝒢)"
           and Fglob = "map_lift (default_st_to_fun 𝒢)"])
     (rule dg_reader_commute_gen_lifted_for seed_ne_buffer_key
           dg_spec_wf_exec_dg_spec
           dg_spec_wf_lifted_state_dg_spec
           Henter_lifted_for Hcomb_lifted_for
           route_agree map_lift_eq_Bot_iff resolve_agree)+

text ‹The routed extra-goal list commutes elementwise, for the same reason.›

text ‹
  The buffered generator a domain actually solves, reconciled with the unbuffered one
  the framework is stated over --- at the executable spec, before publication.

  Both reshaping hooks are the identity here. The buffered generator only ever asks a
  hook to hoist what it publishes at the buffered key ‹buffer_key›; this spec is local-only,
  so its intra tree and its routed combine publish nothing there, and each tree is
  already its own contribution analogue. That is a property of the trees --- read off
  ‹routed_call_program_side_free_at_buffer_key› and the local-only compile-down facts --- not of any
  analysis family: a spec whose transfers do publish at ‹buffer_key› would have to supply
  reshaped hooks instead, with the same generic bridge unchanged. The routed seed
  survives untouched, because a seed key is never ‹buffer_key› and the bridge requires
  off-key sides to be preserved, not removed.

  An instance that interprets the spine at ‹spec_st› hands this post-solution to
  locale‹dg_context_activation› directly.
›

abbreviation intra_st :: "'c ⇒ pp × 'c + 'k ⇒ edge_action
   ⇒ (pp × 'c, 'k, ('a default_st lifted, 'a default_st lifted) dg_state,
        ('a default_st lifted, 'a default_st lifted) dg_state) strategy_program"
where
  "intra_st ctx' src a ≡ dg_spec_edge_program spec_st a src (λ_. buffer_key)"

abbreviation cmb_st :: "cfg ⇒ (pp ⇒ 'c ⇒ 'a default_st lifted ⇒ call_action ⇒ 'c)
   ⇒ 'c ⇒ call_action ⇒ pp ⇒ pp
   ⇒ (pp × 'c, 'k, ('a default_st lifted, 'a default_st lifted) dg_state,
        ('a default_st lifted, 'a default_st lifted) dg_state) strategy_program"
where
  "cmb_st g ≡ routed_call_program spec_st (λ_. buffer_key) seed (resolve_st g) (λd. d = Bot)"

theorem pp_st:
  assumes pp: "part_post_solution
     (routed_node_rhs_buffered intra_predecessor_addr_list call_site_list (λ_. buffer_key) route_st
        intra_st (cmb_st g)
        (routed_entry_seed_programs seed)
        g bot0 d0 g0)
     x0 sigma_st vars"
  shows "part_post_solution
     (routed_node_rhs intra_predecessor_addr_list call_site_list (λ_. buffer_key) route_st
        intra_st (cmb_st g)
        (routed_entry_seed_programs seed)
        g bot0 d0 g0)
     x0 sigma_st vars"
  by (rule pp_dg_spec_of[where S = spec_st])
     (rule exec_dg_spec_def, rule seed_ne_buffer_key, rule pp)

end

end