Theory Heuristic_Certificates

section ‹Heuristic Certificates›

theory Heuristic_Certificates
  imports K_Gates
begin

text ‹Definition 4 of the paper: heuristic certificates.  A heuristic maintains a
  PB circuit @{text H} (a gate list shared across all evaluated states) and, per
  evaluated state @{text s}, an output literal @{text "rhs"} and an estimate
  @{text "h s"}.  The three obligations (state, goal, inductivity lemma) are
  stated semantically over 0/1 models; by @{thm cpr_derives_iff_semantic} this is
  interchangeable with the paper's CPR-derivability formulation (a bridge for the
  state lemma is proved at the end of this theory).›

subsection ‹Renaming assignments along literal maps›

lemma eval_lit_map_literal:
  "eval_lit (map_literal f l) rho = eval_lit l (rho  f)"
  by (cases l) (simp_all add: eval_lit_def)

lemma lit_neg_map_literal:
  "lit_neg (map_literal f l) = map_literal f (lit_neg l)"
  by (cases l) (simp_all add: lit_neg_def)

lemma pb_sum_map_literal:
  "pb_sum (map (λ(a, l). (a, map_literal f l)) cs) rho = pb_sum cs (rho  f)"
  by (induction cs) (auto simp: eval_lit_map_literal o_def)

lemma models_Union_iff:
  "models (xS. F x) rho  (xS. models (F x) rho)"
  unfolding models_def by blast

lemma models_reification_lift:
  "models (reification (map_literal f r) (map (λ(a, l). (a, map_literal f l)) cs) A) rho
    models (reification r cs A) (rho  f)"
proof -
  have pos_sum: "pb_sum (map (λ(a, l). (a, map_literal f l)) cs) rho = pb_sum cs (rho  f)"
    by (rule pb_sum_map_literal)
  have fst_eq: "map (fst  (λ(a, l). (a, map_literal f l))) cs = map fst cs"
    by (induction cs) auto
  have neg_sum: "pb_sum (map ((λ(a, l). (a, lit_neg l))  (λ(a, l). (a, map_literal f l))) cs) rho
      = pb_sum (map (λ(a, l). (a, lit_neg l)) cs) (rho  f)"
    by (induction cs) (auto simp: lit_neg_map_literal eval_lit_map_literal o_def)
  have fwd: "satisfies (reif_fwd (map_literal f r) (map (λ(a, l). (a, map_literal f l)) cs) A) rho
       satisfies (reif_fwd r cs A) (rho  f)"
    by (simp add: reif_fwd_def satisfies_def pos_sum
        lit_neg_map_literal eval_lit_map_literal)
  have bwd: "satisfies (reif_bwd (map_literal f r) (map (λ(a, l). (a, map_literal f l)) cs) A) rho
       satisfies (reif_bwd r cs A) (rho  f)"
    by (simp add: reif_bwd_def satisfies_def Let_def fst_eq neg_sum eval_lit_map_literal)
  show ?thesis
    by (simp add: reification_def models_def fwd bwd)
qed

lemma models_circuit_constraints_lift:
  "models (circuit_constraints (lift_circuit f C)) rho
    models (circuit_constraints C) (rho  f)"
proof -
  obtain pairs out where C: "C = (pairs, out)" by (cases C)
  have set_lift: "set (fst (lift_circuit f C))
      = (λ(r, cs, A). (map_literal f r, map (λ(a, l). (a, map_literal f l)) cs, A)) ` set pairs"
    by (simp add: C lift_circuit_def)
  have "models (circuit_constraints (lift_circuit f C)) rho
       ((r, cs, A)  set pairs.
          models (reification (map_literal f r) (map (λ(a, l). (a, map_literal f l)) cs) A) rho)"
    unfolding circuit_constraints_def set_lift
    by (fastforce simp: models_Union_iff split_beta)
  also have "...  ((r, cs, A)  set pairs. models (reification r cs A) (rho  f))"
    using models_reification_lift by (fastforce simp: split_beta)
  also have "...  models (circuit_constraints C) (rho  f)"
    unfolding C circuit_constraints_def
    by (fastforce simp: models_Union_iff split_beta)
  finally show ?thesis .
qed

lemma rho01_comp:
  "(x. rho x = 0  rho x = 1)  (x. (rho  f) x = 0  (rho  f) x = 1)"
  by simp

subsection ‹Heuristic certificates (Definition 4)›

record ('u) heuristic_cert =
  hc_gates :: "('u pvar literal × (nat × 'u pvar literal) list × nat) list"
  hc_out   :: "'u state  'u pvar literal"
  hc_h     :: "'u state  nat"

definition hc_constraints :: "('u) heuristic_cert  'u pconstraint set" where
  "hc_constraints HC  (r, cs, A)  set (hc_gates HC). reification r cs A"

lemma hc_constraints_eq_circuit:
  "hc_constraints HC = circuit_constraints (hc_gates HC, out)"
  by (simp add: hc_constraints_def circuit_constraints_def)

text ‹State lemma: if the state variables encode exactly @{text s} on the task
  variables and the cost bits witness @{text "clip B (B - h s)"}, the output gate
  for @{text s} is forced.  (Paper: @{text "(rs ∧ cost≥max{0,B−h(s)}) → rhs"}.)›

definition hc_state_lemma ::
  "'u strips_task  nat  ('u) heuristic_cert  'u state  bool" where
  "hc_state_lemma Πe B HC s 
    rho. (x. rho x = 0  rho x = 1) 
      models (hc_constraints HC) rho 
      (v  vars Πe. rho (StateVar v) = (if v  s then 1 else 0)) 
      bits_val (bits_needed B) CostBit rho  clip B (int B - int (hc_h HC s)) 
      eval_lit (hc_out HC s) rho = 1"

lemma hc_state_lemmaD:
  assumes "hc_state_lemma Πe B HC s"
    and "x. rho x = 0  rho x = 1"
    and "models (hc_constraints HC) rho"
    and "v  vars Πe. rho (StateVar v) = (if v  s then 1 else 0)"
    and "bits_val (bits_needed B) CostBit rho  clip B (int B - int (hc_h HC s))"
  shows "eval_lit (hc_out HC s) rho = 1"
  using assms unfolding hc_state_lemma_def by blast

text ‹Goal lemma: a true output gate together with a satisfied goal forces the
  cost bits to reach @{text B}.  (Paper: @{text "(rG ∧ rhs) → cost≥B"}.)›

definition hc_goal_lemma ::
  "'u strips_task  nat  ('u) heuristic_cert  'u state  bool" where
  "hc_goal_lemma Πe B HC s 
    rho. (x. rho x = 0  rho x = 1) 
      models (hc_constraints HC) rho 
      (v  goal Πe. rho (StateVar v) = 1) 
      eval_lit (hc_out HC s) rho = 1 
      bits_val (bits_needed B) CostBit rho  B"

lemma hc_goal_lemmaD:
  assumes "hc_goal_lemma Πe B HC s"
    and "x. rho x = 0  rho x = 1"
    and "models (hc_constraints HC) rho"
    and "v  goal Πe. rho (StateVar v) = 1"
    and "eval_lit (hc_out HC s) rho = 1"
  shows "bits_val (bits_needed B) CostBit rho  B"
  using assms unfolding hc_goal_lemma_def by blast

text ‹Inductivity lemma: across one encoded transition, a true (unprimed) output
  gate forces the primed copy.  (Paper: @{text "(rhs ∧ rT) → rhs'"} from
  @{text "Ctrans ∪ H ∪ H' ∪ C ∪ CK"}.)›

definition hc_ind_lemma ::
  "'u::linorder strips_task  nat  'u action list  ('u) heuristic_cert  'u state  bool" where
  "hc_ind_lemma Πe B as HC s 
    rho. (x. rho x = 0  rho x = 1) 
      models (circuit_constraints (orig_circuit (hc_gates HC, hc_out HC s))) rho 
      models (circuit_constraints (primed_circuit (hc_gates HC, hc_out HC s))) rho 
      models (encode_transition as (vars Πe) B) rho 
      models (encode_cost_ge B) rho 
      rho ReifT = 1 
      eval_lit (map_literal (map_pvar Original) (hc_out HC s)) rho = 1 
      eval_lit (map_literal primed_pvar_map (hc_out HC s)) rho = 1"

lemma hc_ind_lemmaD:
  assumes "hc_ind_lemma Πe B as HC s"
    and "x. rho x = 0  rho x = 1"
    and "models (circuit_constraints (orig_circuit (hc_gates HC, hc_out HC s))) rho"
    and "models (circuit_constraints (primed_circuit (hc_gates HC, hc_out HC s))) rho"
    and "models (encode_transition as (vars Πe) B) rho"
    and "models (encode_cost_ge B) rho"
    and "rho ReifT = 1"
    and "eval_lit (map_literal (map_pvar Original) (hc_out HC s)) rho = 1"
  shows "eval_lit (map_literal primed_pvar_map (hc_out HC s)) rho = 1"
  using assms unfolding hc_ind_lemma_def by blast

definition hc_valid ::
  "'u::linorder strips_task  nat  'u action list  ('u) heuristic_cert  'u state set  bool" where
  "hc_valid Πe B as HC S 
    s  S. hc_state_lemma Πe B HC s  hc_goal_lemma Πe B HC s  hc_ind_lemma Πe B as HC s"

subsection ‹The state lemma in primed variables›

text ‹The paper requires the heuristic to ``log a proof for the state lemma in
  terms of the primed variables''.  Formally this is a consequence of the
  unprimed state lemma, by precomposing a model of the primed circuit copy with
  the renaming @{const primed_pvar_map}.›

lemma hc_state_lemma_primed:
  fixes Πe :: "'u::linorder strips_task"
  assumes sl: "hc_state_lemma Πe B HC s"
    and rho01: "x. rho x = 0  rho x = 1"
    and m: "models (circuit_constraints (primed_circuit (hc_gates HC, out))) rho"
    and sv: "v  vars Πe. rho (StateVar (Primed v)) = (if v  s then 1 else 0)"
    and cb: "bits_val (bits_needed B) PrimedCostBit rho  clip B (int B - int (hc_h HC s))"
  shows "eval_lit (map_literal primed_pvar_map (hc_out HC s)) rho = 1"
proof -
  let ?rho' = "rho  primed_pvar_map"
  have rho'01: "x. ?rho' x = 0  ?rho' x = 1"
    by (rule rho01_comp[OF rho01])
  have m': "models (hc_constraints HC) ?rho'"
    using m models_circuit_constraints_lift[of primed_pvar_map "(hc_gates HC, out)" rho]
    by (simp add: primed_circuit_def hc_constraints_eq_circuit[of HC out])
  have sv': "v  vars Πe. ?rho' (StateVar v) = (if v  s then 1 else 0)"
    using sv by simp
  have cb': "bits_val (bits_needed B) CostBit ?rho'  clip B (int B - int (hc_h HC s))"
    using cb by (simp add: bits_val_def)
  have "eval_lit (hc_out HC s) ?rho' = 1"
    by (rule hc_state_lemmaD[OF sl rho'01 m' sv' cb'])
  then show ?thesis by (simp add: eval_lit_map_literal)
qed

text ‹The analogous fact for the unprimed copy embedded by @{const orig_circuit}.›

lemma hc_state_lemma_orig:
  fixes Πe :: "'u::linorder strips_task"
  assumes sl: "hc_state_lemma Πe B HC s"
    and rho01: "x. rho x = 0  rho x = 1"
    and m: "models (circuit_constraints (orig_circuit (hc_gates HC, out))) rho"
    and sv: "v  vars Πe. rho (StateVar (Original v)) = (if v  s then 1 else 0)"
    and cb: "bits_val (bits_needed B) CostBit rho  clip B (int B - int (hc_h HC s))"
  shows "eval_lit (map_literal (map_pvar Original) (hc_out HC s)) rho = 1"
proof -
  let ?rho' = "rho  map_pvar Original"
  have rho'01: "x. ?rho' x = 0  ?rho' x = 1"
    by (rule rho01_comp[OF rho01])
  have m': "models (hc_constraints HC) ?rho'"
    using m models_circuit_constraints_lift[of "map_pvar Original" "(hc_gates HC, out)" rho]
    by (simp add: orig_circuit_def hc_constraints_eq_circuit[of HC out])
  have sv': "v  vars Πe. ?rho' (StateVar v) = (if v  s then 1 else 0)"
    using sv by simp
  have cb': "bits_val (bits_needed B) CostBit ?rho'  clip B (int B - int (hc_h HC s))"
    using cb by (simp add: bits_val_def)
  have "eval_lit (hc_out HC s) ?rho' = 1"
    by (rule hc_state_lemmaD[OF sl rho'01 m' sv' cb'])
  then show ?thesis by (simp add: eval_lit_map_literal)
qed

subsection ‹Faithfulness bridge: the state lemma as a CPR derivation›

text ‹The paper states Definition 4 via CPR proofs.  The semantic conditions above
  are interchangeable with that formulation; we make this explicit for the state
  lemma (the other two obligations are analogous).  The state description
  @{text "Cs"} of the paper becomes a set of unit clauses, and the clipped cost
  premise its bit-level constraint.›

definition state_unit_clauses :: "'u strips_task  'u state  'u pconstraint set" where
  "state_unit_clauses Πe s 
     (λv. unit_clause (Pos (StateVar v))) ` (vars Πe  s)
    (λv. unit_clause (Neg (StateVar v))) ` (vars Πe - s)"

lemma unit_clause_pos_sat:
  assumes rho01: "x. rho x = 0  rho x = 1"
  shows "satisfies (unit_clause (Pos w)) rho  rho w = 1"
proof -
  have "rho w  1" by (rule rho01_le_one[OF rho01])
  then show ?thesis
    by (auto simp: unit_clause_def satisfies_def eval_lit_def)
qed

lemma unit_clause_neg_sat:
  assumes rho01: "x. rho x = 0  rho x = 1"
  shows "satisfies (unit_clause (Neg w)) rho  rho w = 0"
  using rho01[rule_format, of w]
  by (auto simp: unit_clause_def satisfies_def eval_lit_def)

lemma state_unit_clauses_sat:
  assumes rho01: "x. rho x = 0  rho x = 1"
  shows "models (state_unit_clauses Πe s) rho
        (v  vars Πe. rho (StateVar v) = (if v  s then 1 else 0))"
proof
  assume m: "models (state_unit_clauses Πe s) rho"
  show "v  vars Πe. rho (StateVar v) = (if v  s then 1 else 0)"
  proof
    fix v assume vV: "v  vars Πe"
    show "rho (StateVar v) = (if v  s then 1 else 0)"
    proof (cases "v  s")
      case True
      then have "unit_clause (Pos (StateVar v))  state_unit_clauses Πe s"
        using vV by (auto simp: state_unit_clauses_def)
      then have "satisfies (unit_clause (Pos (StateVar v))) rho"
        using m by (auto simp: models_def)
      then show ?thesis using True unit_clause_pos_sat[OF rho01] by simp
    next
      case False
      then have "unit_clause (Neg (StateVar v))  state_unit_clauses Πe s"
        using vV by (auto simp: state_unit_clauses_def)
      then have "satisfies (unit_clause (Neg (StateVar v))) rho"
        using m by (auto simp: models_def)
      then show ?thesis using False unit_clause_neg_sat[OF rho01] by simp
    qed
  qed
next
  assume enc: "v  vars Πe. rho (StateVar v) = (if v  s then 1 else 0)"
  show "models (state_unit_clauses Πe s) rho"
    unfolding state_unit_clauses_def models_def
    using enc unit_clause_pos_sat[OF rho01] unit_clause_neg_sat[OF rho01]
    by auto
qed

theorem hc_state_lemma_cpr:
  fixes Πe :: "'u::linorder strips_task"
  assumes sl: "hc_state_lemma Πe B HC s"
  shows "cpr_derives
    (hc_constraints HC  state_unit_clauses Πe s
      {clip_cost_constraint B (int B - int (hc_h HC s))})
    (unit_clause (hc_out HC s))"
proof (rule semantic_to_cpr)
  show "snd (unit_clause (hc_out HC s))  (1::nat)"
    by (simp add: unit_clause_def)
  show "rho. (x. rho x = 0  rho x = 1) 
      models (hc_constraints HC  state_unit_clauses Πe s
         {clip_cost_constraint B (int B - int (hc_h HC s))}) rho 
      satisfies (unit_clause (hc_out HC s)) rho"
  proof (intro allI impI)
    fix rho :: "'u pvar  nat"
    assume rho01: "x. rho x = 0  rho x = 1"
      and m: "models (hc_constraints HC  state_unit_clauses Πe s
         {clip_cost_constraint B (int B - int (hc_h HC s))}) rho"
    have m1: "models (hc_constraints HC) rho"
      and m2: "models (state_unit_clauses Πe s) rho"
      and m3: "satisfies (clip_cost_constraint B (int B - int (hc_h HC s))) rho"
      using m by (auto simp: models_def)
    have sv: "v  vars Πe. rho (StateVar v) = (if v  s then 1 else 0)"
      using state_unit_clauses_sat[OF rho01] m2 by blast
    have cb: "bits_val (bits_needed B) CostBit rho  clip B (int B - int (hc_h HC s))"
      using clip_cost_constraint_sat[OF rho01] m3 by blast
    have "eval_lit (hc_out HC s) rho = 1"
      by (rule hc_state_lemmaD[OF sl rho01 m1 sv cb])
    then show "satisfies (unit_clause (hc_out HC s)) rho"
      by (simp add: unit_clause_def satisfies_def)
  qed
qed

subsection ‹Generic conjunction and disjunction gates›

text ‹The circuits of the paper's case study are built almost exclusively from two
  gate forms over unit-coefficient literal lists: conjunction gates
  @{text "r ⇔ Σ ℓᵢ ≥ n"} (all of the @{text n} literals true) and disjunction
  gates @{text "r ⇔ Σ ℓᵢ ≥ 1"} (some literal true).›

lemma sum_list_units_all_one:
  fixes f :: "'a  nat"
  assumes "(lls. f l)  length ls" and "lset ls. f l  1"
  shows "lset ls. f l = 1"
  using assms
proof (induction ls)
  case Nil
  then show ?case by simp
next
  case (Cons x ls)
  have x_le: "f x  1" and ls_le: "lset ls. f l  1"
    using Cons.prems(2) by auto
  have ls_sum_le: "(lls. f l)  length ls"
    using ls_le by (induction ls) fastforce+
  have x1: "f x = 1" and rest: "(lls. f l)  length ls"
    using Cons.prems(1) x_le ls_sum_le by auto
  show ?case using x1 Cons.IH[OF rest ls_le] by simp
qed

lemma conj_gate_forces:
  assumes rho01: "x. rho x = 0  rho x = 1"
    and m: "models (reification r (map (λl. (1, l)) ls) (length ls)) rho"
  shows "eval_lit r rho = 1  (lset ls. eval_lit l rho = 1)"
proof -
  have sum_eq: "pb_sum (map (λl. (1, l)) ls) rho = (lls. eval_lit l rho)"
    by (induction ls) auto
  have le1: "lset ls. eval_lit l rho  1"
    by (intro ballI eval_lit_le_one[OF rho01])
  have iff1: "eval_lit r rho = 1  (lls. eval_lit l rho)  length ls"
    using reification_forces[OF rho01 m] unfolding sum_eq .
  show ?thesis
  proof
    assume "eval_lit r rho = 1"
    then have "(lls. eval_lit l rho)  length ls" using iff1 by simp
    then show "lset ls. eval_lit l rho = 1"
      by (rule sum_list_units_all_one[OF _ le1])
  next
    assume all1: "lset ls. eval_lit l rho = 1"
    have "(lls. eval_lit l rho) = length ls"
      using all1 by (induction ls) auto
    then show "eval_lit r rho = 1" using iff1 by simp
  qed
qed

lemma disj_gate_forces:
  assumes rho01: "x. rho x = 0  rho x = 1"
    and m: "models (reification r (map (λl. (1, l)) ls) 1) rho"
  shows "eval_lit r rho = 1  (lset ls. eval_lit l rho = 1)"
proof -
  have iff1: "eval_lit r rho = 1  pb_sum (map (λl. (1, l)) ls) rho  1"
    by (rule reification_forces[OF rho01 m])
  show ?thesis
  proof
    assume "eval_lit r rho = 1"
    then have "pb_sum (map (λl. (1, l)) ls) rho  1" using iff1 by simp
    then have "(a, l)  set (map (λl. (1, l)) ls). a * eval_lit l rho  1"
      by (rule pb_sum_pos_ex)
    then obtain a l where "(a, l)  set (map (λl. (1, l)) ls)"
      and "a * eval_lit l rho  1" by auto
    then have "l  set ls" and "eval_lit l rho  1" by auto
    then show "lset ls. eval_lit l rho = 1"
      using eval_lit_le_one[OF rho01] by (metis le_antisym)
  next
    assume "lset ls. eval_lit l rho = 1"
    then obtain l where l_in: "l  set ls" and l1: "eval_lit l rho = 1" by blast
    have "pb_sum (map (λl. (1, l)) ls) rho  1"
      using l_in l1
    proof (induction ls)
      case Nil
      then show ?case by simp
    next
      case (Cons q ls)
      then show ?case by (cases "l = q") auto
    qed
    then show "eval_lit r rho = 1" using iff1 by simp
  qed
qed

end