Theory Locale_Instances

section ‹Locale Instances›

theory Locale_Instances
  imports Hmax_Certificates Efficient_PDB
begin

text ‹Consistency witnesses for all locales of the development.  A locale whose
  assumptions are contradictory makes every theorem proved inside it vacuous;
  the interpretations below rule this out by exhibiting one concrete model for
  each of @{locale pdb_heuristic}, @{locale hmax_heuristic},
  @{locale efficient_pdb} and @{locale astar_run}.

  The witness is the smallest non-degenerate planning task: one variable
  @{text "0"}, initially false, required by the goal, and one action that adds
  it at cost 1.  The optimal plan is the single-action plan of cost 1, and we
  use the bound @{text "B = 1"}.  All interesting locale assumptions
  (the PDB distance conditions @{text d_goal}/@{text d_triangle}, the hmax
  table conditions, the A* expansion-closure condition) are discharged
  non-vacuously.

  The A* interpretation is additionally instantiated with the ‹interpreted›
  PDB certificate at the embedded variable type @{typ "nat + nat"} (gate names
  @{text "Inr (2*j+1)"}), i.e. the locales compose exactly as the paper's
  PDB-into-A* case study intends.  As a final sanity check the composition
  yields the concrete theorem @{text "optimal_plan demo_task [demo_act]"}.›

subsection ‹The demo task›

definition demo_act :: "nat action" where
  "demo_act =  pre = {}, add = {0}, del = {}, cost = 1 "

definition demo_task :: "nat strips_task" where
  "demo_task =  vars = {0}, acts = {demo_act}, init = {}, goal = {0} "

lemma demo_pow: "set [{}, {0::nat}] = Pow {0}"
  by (auto dest: subset_singletonD)

subsection ‹Interpretation of @{locale pdb_heuristic}

interpretation demo_pdb: pdb_heuristic demo_task 1 "{0::nat}"
  "λsa. if 0  sa then 0 else 1" "[{}, {0}]" "[demo_act]" id
proof unfold_locales
  show "finite (vars demo_task)" by (simp add: demo_task_def)
  show "{0::nat}  vars demo_task" by (simp add: demo_task_def)
  show "set [{}, {0::nat}] = Pow {0}" by (rule demo_pow)
  show "distinct [{}, {0::nat}]" by simp
  show "a  set [demo_act].
      pre a  vars demo_task  add a  vars demo_task  del a  vars demo_task"
    by (simp add: demo_act_def demo_task_def)
  show "a  set [demo_act]. add a  del a = {}"
    by (simp add: demo_act_def)
  show "sa. sa  {0::nat}  goal demo_task  {0}  sa 
      (if 0  sa then 0 else 1) = (0::nat)"
    by (auto simp: demo_task_def)
  show "sa a. sa  {0::nat}  a  set [demo_act]  pre a  {0}  sa 
      (if 0  sa then 0 else 1)
         (if 0  (sa - del a)  (add a  {0}) then 0 else 1) + cost a"
    by (auto simp: demo_act_def)
  show "inj (id :: nat  nat)" by simp
qed

text ‹The interpreted facts are available, e.g. the validity of the PDB
  certificate for the demo table:›

lemma "hc_valid demo_task 1 [demo_act] demo_pdb.pdb_cert S"
  by (rule demo_pdb.pdb_hc_valid)

subsection ‹Interpretation of @{locale hmax_heuristic}

text ‹The evaluated state is the initial state @{term "{} :: nat state"}; its
  hmax value is 1 (the single goal variable costs 1 to achieve), and the
  clipped max value of every variable is 1.›

interpretation demo_hmax: hmax_heuristic demo_task 1 "{} :: nat state" 1
  "λv. 1" "[0]" "[demo_act]" id
proof unfold_locales
  show "finite (vars demo_task)" by (simp add: demo_task_def)
  show "goal demo_task  vars demo_task" by (simp add: demo_task_def)
  show "{}  vars demo_task" by simp
  show "set [0] = vars demo_task" by (simp add: demo_task_def)
  show "distinct [0::nat]" by simp
  show "a  set [demo_act].
      pre a  vars demo_task  add a  vars demo_task  del a  vars demo_task"
    by (simp add: demo_act_def demo_task_def)
  show "a  set [demo_act]. add a  del a = {}"
    by (simp add: demo_act_def)
  show "v. v  ({} :: nat state)  (1::nat) = 0" by simp
  show "goal demo_task  {}  v  goal demo_task. (1::nat) = 1"
    by (simp add: demo_task_def)
  show "goal demo_task = {}  (1::nat) = 0" by (simp add: demo_task_def)
  show "a v. a  set [demo_act]  v  add a  pre a  {} 
      p  pre a. (1::nat)  1 + cost a"
    by (simp add: demo_act_def)
  show "a v. a  set [demo_act]  v  add a  pre a = {} 
      (1::nat)  cost a"
    by (simp add: demo_act_def)
  show "inj (id :: nat  nat)" by simp
qed

lemma "hc_valid demo_task 1 [demo_act] demo_hmax.hmax_cert {{}}"
  by (rule demo_hmax.hmax_hc_valid)

subsection ‹Interpretation of @{locale efficient_pdb}

text ‹In the demo task every abstract state reaches the abstract goal, so the
  finiteness predicate is constantly true and the table coincides with the
  plain PDB table.›

interpretation demo_epdb: efficient_pdb demo_task 1 "{0::nat}"
  "λsa. if 0  sa then 0 else 1" "λsa. True" "[{}, {0}]" "[demo_act]" id
proof unfold_locales
  show "finite (vars demo_task)" by (simp add: demo_task_def)
  show "{0::nat}  vars demo_task" by (simp add: demo_task_def)
  show "set [{}, {0::nat}] = {sa. sa  {0}  True}"
    using demo_pow by auto
  show "distinct [{}, {0::nat}]" by simp
  show "a  set [demo_act].
      pre a  vars demo_task  add a  vars demo_task  del a  vars demo_task"
    by (simp add: demo_act_def demo_task_def)
  show "a  set [demo_act]. add a  del a = {}"
    by (simp add: demo_act_def)
  show "sa. sa  {0::nat}  goal demo_task  {0}  sa 
      True  (if 0  sa then 0 else 1) = (0::nat)"
    by (auto simp: demo_task_def)
  show "sa a. sa  {0::nat}  a  set [demo_act]  pre a  {0}  sa 
      True  True  (if 0  sa then 0 else 1)
         (if 0  (sa - del a)  (add a  {0}) then 0 else 1) + cost a"
    by (auto simp: demo_act_def)
  show "inj (id :: nat  nat)" by simp
qed

lemma "hc_valid demo_task 1 [demo_act] demo_epdb.epdb_cert S"
  by (rule demo_epdb.epdb_hc_valid)

subsection ‹Interpretation of @{locale pdb_heuristic} at the embedded type›

text ‹For the A* interpretation the heuristic certificate must live at the
  extended variable type @{typ "nat + nat"} with the odd gate names
  @{text "Inr (2*j+1)"} that @{locale astar_run} reserves for the heuristic.›

lemma demo_taskE_simps:
  "vars (embed_task demo_task :: (nat + nat) strips_task) = {Inl 0}"
  "goal (embed_task demo_task :: (nat + nat) strips_task) = {Inl 0}"
  "init (embed_task demo_task :: (nat + nat) strips_task) = {}"
  "acts (embed_task demo_task :: (nat + nat) strips_task) = {embed_act demo_act}"
  by (simp_all add: embed_task_def demo_task_def)

lemma demo_actE_simps:
  "pre (embed_act demo_act :: (nat + nat) action) = {}"
  "add (embed_act demo_act :: (nat + nat) action) = {Inl 0}"
  "del (embed_act demo_act :: (nat + nat) action) = {}"
  "cost (embed_act demo_act :: (nat + nat) action) = 1"
  by (simp_all add: embed_act_def demo_act_def)

lemma demo_powE: "set [{}, {Inl 0} :: (nat + nat) state] = Pow {Inl 0}"
  by (auto dest: subset_singletonD)

interpretation demoE_pdb: pdb_heuristic
  "embed_task demo_task :: (nat + nat) strips_task" 1 "{Inl 0}"
  "λsa. if Inl 0  sa then 0 else 1" "[{}, {Inl 0}]" "[embed_act demo_act]"
  "λj. Inr (2 * j + 1)"
proof unfold_locales
  show "finite (vars (embed_task demo_task :: (nat + nat) strips_task))"
    by (simp add: demo_taskE_simps)
  show "{Inl 0}  vars (embed_task demo_task :: (nat + nat) strips_task)"
    by (simp add: demo_taskE_simps)
  show "set [{}, {Inl 0} :: (nat + nat) state] = Pow {Inl 0}"
    by (rule demo_powE)
  show "distinct [{}, {Inl 0} :: (nat + nat) state]" by simp
  show "a  set [embed_act demo_act :: (nat + nat) action].
      pre a  vars (embed_task demo_task)
       add a  vars (embed_task demo_task)
       del a  vars (embed_task demo_task)"
    by (simp add: demo_actE_simps demo_taskE_simps)
  show "a  set [embed_act demo_act :: (nat + nat) action]. add a  del a = {}"
    by (simp add: demo_actE_simps)
  show "sa. sa  {Inl 0} 
      goal (embed_task demo_task :: (nat + nat) strips_task)  {Inl 0}  sa 
      (if Inl 0  sa then 0 else 1) = (0::nat)"
    by (auto simp: demo_taskE_simps)
  show "sa a. sa  {Inl 0}  a  set [embed_act demo_act :: (nat + nat) action] 
      pre a  {Inl 0}  sa 
      (if Inl 0  sa then 0 else 1)
         (if Inl 0  (sa - del a)  (add a  {Inl 0}) then 0 else 1) + cost a"
    by (auto simp: demo_actE_simps)
  show "inj (λj. Inr (2 * j + 1) :: nat + nat)"
    by (auto simp: inj_def)
qed

subsection ‹Interpretation of @{locale astar_run}

text ‹The A* snapshot after expanding the initial state: the closed list holds
  @{term "({}, 0)"}, the open list holds the goal state @{term "{0::nat}"}, and
  the heuristic certificate is the interpreted embedded PDB certificate.›

interpretation demo_astar: astar_run demo_task 1 "[({}, 0)]" "[{0::nat}]"
  demoE_pdb.pdb_cert "[embed_act demo_act]"
proof unfold_locales
  show "finite (vars demo_task)" by (simp add: demo_task_def)
  show "init demo_task  vars demo_task" by (simp add: demo_task_def)
  show "goal demo_task  vars demo_task" by (simp add: demo_task_def)
  show "finite (acts demo_task)" by (simp add: demo_task_def)
  show "a  acts demo_task. add a  del a = {}"
    by (simp add: demo_task_def demo_act_def)
  show "a  acts demo_task.
      pre a  vars demo_task  add a  vars demo_task  del a  vars demo_task"
    by (simp add: demo_task_def demo_act_def)
  show "set [embed_act demo_act] = acts (embed_task demo_task)"
    by (simp add: embed_task_def demo_task_def)
  show "(1::nat)  1" by simp
  show "(init demo_task, 0)  set [({}, 0)]" by (simp add: demo_task_def)
  show "(s, g)  set [({}, 0)]. s  vars demo_task" by (simp add: demo_task_def)
  show "s  set [{0::nat}]. s  vars demo_task" by (simp add: demo_task_def)
  show "(s, g)  set [({}, 0::nat)]. is_goal_state demo_task s  g  1"
    by (simp add: is_goal_state_def demo_task_def)
  show "(s, g)  set [({}, 0::nat)]. a  acts demo_task. applicable a s 
      (is_goal_state demo_task s  g  1)
     (g'. (successor a s, g')  set [({}, 0)]  g'  g + cost a)
     (successor a s  set [{0::nat}] 
       int (g + cost a)  int 1 - int (hc_h demoE_pdb.pdb_cert (Inl ` successor a s)))"
  proof -
    have succ: "successor demo_act {} = {0}"
      by (simp add: successor_def demo_act_def)
    have h0: "hc_h demoE_pdb.pdb_cert {Inl (0::nat)} = 0"
      unfolding demoE_pdb.pdb_cert_def by simp
    have cost_a: "cost demo_act = 1"
      by (simp add: demo_act_def)
    have third: "successor demo_act {}  set [{0::nat}] 
        int (0 + cost demo_act)
           int 1 - int (hc_h demoE_pdb.pdb_cert (Inl ` successor demo_act {}))"
      by (simp add: succ h0 cost_a)
    have inner: "a  acts demo_task. applicable a {} 
        (is_goal_state demo_task {}  (0::nat)  1)
       (g'. (successor a {}, g')  set [({}, 0)]  g'  0 + cost a)
       (successor a {}  set [{0::nat}] 
         int (0 + cost a)  int 1 - int (hc_h demoE_pdb.pdb_cert (Inl ` successor a {})))"
    proof
      fix a assume "a  acts demo_task"
      then have a_eq: "a = demo_act" by (simp add: demo_task_def)
      show "applicable a {} 
          (is_goal_state demo_task {}  (0::nat)  1)
         (g'. (successor a {}, g')  set [({}, 0)]  g'  0 + cost a)
         (successor a {}  set [{0::nat}] 
           int (0 + cost a)  int 1 - int (hc_h demoE_pdb.pdb_cert (Inl ` successor a {})))"
        unfolding a_eq using third by blast
    qed
    show ?thesis using inner by simp
  qed
  show "hc_valid (embed_task demo_task) 1 [embed_act demo_act] demoE_pdb.pdb_cert
      ((λs. Inl ` s) ` set [{0::nat}])"
    by (rule demoE_pdb.pdb_hc_valid)
  show "(r, cs, A)  set (hc_gates demoE_pdb.pdb_cert).
      j. r = Pos (ReifCert (Inr (2 * j + 1)))"
    using demoE_pdb.pdb_names by auto
  show "distinct (map (λ(r, cs, A). pvar_of_lit r) (hc_gates demoE_pdb.pdb_cert))"
    by (rule demoE_pdb.pdb_distinct)
  show "i < length (hc_gates demoE_pdb.pdb_cert).
      case hc_gates demoE_pdb.pdb_cert ! i of (r, cs, A) 
        (x  pvar_of_lit ` snd ` set cs.
          (v. x = StateVar v)  (j. x = CostBit j)
           x  pvar_of_lit ` fst ` set (take i (hc_gates demoE_pdb.pdb_cert)))"
    by (rule demoE_pdb.pdb_wf)
  show "s  set [{0::nat}].
      hc_out demoE_pdb.pdb_cert (Inl ` s)  fst ` set (hc_gates demoE_pdb.pdb_cert)"
    using demoE_pdb.pdb_out_in by simp
qed

subsection ‹End-to-end sanity check›

text ‹The composed interpretations yield a concrete, non-vacuous consequence:
  the single-action plan is optimal for the demo task.›

lemma demo_plan: "is_plan_for demo_task [demo_act]"
proof -
  have succ: "successor demo_act {} = {0}"
    by (simp add: successor_def demo_act_def)
  have p0: "path (acts demo_task) (successor demo_act {}) {0} []"
    unfolding succ by (rule path.path_nil)
  have appl: "applicable demo_act {}"
    by (simp add: applicable_def demo_act_def)
  have mem: "demo_act  acts demo_task"
    by (simp add: demo_task_def)
  have "path (acts demo_task) {} {0} [demo_act]"
    by (rule path.path_cons[OF appl p0 mem])
  then show ?thesis
    unfolding is_plan_for_def is_goal_state_def
    by (intro exI[of _ "{0}"]) (simp add: demo_task_def)
qed

lemma demo_cost: "plan_cost [demo_act] = 1"
  by (simp add: plan_cost_def demo_act_def)

theorem demo_optimal: "optimal_plan demo_task [demo_act]"
  by (rule demo_astar.astar_optimal[OF demo_plan demo_cost])

text ‹And the lower bound directly: every plan for the demo task costs at
  least 1.›

theorem demo_lower_bound: "is_plan_for demo_task π  plan_cost π  1"
  by (rule demo_astar.astar_lower_bound)

end