Theory Pattern_Completeness

section ‹Pattern-Completeness and Related Properties›

text ‹We use the core decision procedure for pattern completeness 
  and connect it to other properties like pattern completeness of programs (where the lhss are given), 
  or (strong) quasi-reducibility.›

theory Pattern_Completeness
  imports 
    Pattern_Completeness_List
    Show.Shows_Literal
    Certification_Monads.Check_Monad
begin


text ‹A pattern completeness decision procedure for a set of lhss›

definition basic_terms :: "('f,'s)ssig  ('f,'s)ssig  ('v  's)  ('f,'v)term set" ("ℬ'(_,_,_')") where
  "ℬ(C,D,V) = { Fun f ts | f ss s ts . f : ss  s in D  ts :l ss in 𝒯(C,V)}" 

definition matches :: "('f,'v)term  ('f,'v)term  bool" (infix "matches" 50) where
  "l matches t = ( σ. t = l  σ)"

definition pat_complete_lhss :: "('f,'s)ssig  ('f,'s)ssig  ('f,'v)term set  bool" where
  "pat_complete_lhss C D L = ( t  ℬ(C,D,). l  L. l matches t)" 


definition decide_pat_complete_lhss :: 
  "(('f × 's list) × 's)list  (('f × 's list) × 's)list  ('f,'v)term list  showsl + bool" where
  "decide_pat_complete_lhss C D lhss = do {
    check (distinct (map fst C)) (showsl_lit (STR ''constructor information contains duplicate''));
    check (distinct (map fst D)) (showsl_lit (STR ''defined symbol information contains duplicate''));
    let S = sorts_of_ssig_list C;
    check_allm (λ ((f,ss),_). check_allm (λ s. check (s  set S) 
      (showsl_lit (STR ''a defined symbol has argument sort that is not known in constructors''))) ss) D;
    (case (decide_nonempty_sorts S C) of None  return () | Some s  error (showsl_lit (STR ''some sort is empty'')));
    let pats = [Fun f (map Var (zip [0..<length ss] ss)). ((f,ss),s)  D];
    let P = [[[(pat,lhs)]. lhs  lhss]. pat  pats];
    return (decide_pat_complete C P)
  }" 

theorem decide_pat_complete_lhss: 
  assumes "decide_pat_complete_lhss C D (lhss :: ('f,'v)term list) = return b" 
  shows "b = pat_complete_lhss (map_of C) (map_of D) (set lhss)" 
proof -
  let ?EMPTY = "pattern_completeness_context.EMPTY" 
  let ?cg_subst = "pattern_completeness_context.cg_subst" 
  let ?C = "map_of C"
  let ?D = "map_of D" 
  define S where "S = sorts_of_ssig_list C" 
  define pats where "pats = map (λ ((f,ss),s). Fun f (map Var (zip [0..<length ss] ss))) D" 
  define P where "P = map (λ pat. map (λ lhs. [(pat,lhs)]) lhss) pats" 
  let ?match_lhs = "λt. l  set lhss. l matches t" 
  note ass = assms(1)[unfolded decide_pat_complete_lhss_def, folded S_def, 
      unfolded Let_def, folded pats_def, folded P_def, simplified]
  from ass have dec: "decide_nonempty_sorts S C = None" (is "?e = _") by (cases ?e, auto) 
  note ass = ass[unfolded dec, simplified]
  from ass have b: "b = decide_pat_complete C P" and dist: "distinct (map fst C)" "distinct (map fst D)" by auto
  have "b = decide_pat_complete C P" by fact
  also have " = pats_complete (set S) ?C (pat_list ` set P)" 
  proof (rule decide_pat_complete[OF refl dist(1) dec[unfolded S_def]], unfold S_def[symmetric])
    {
      fix i si f ss s
      assume mem: "((f, ss), s)  set D" and isi: "(i, si)  set (zip [0..<length ss] ss)" 
      from isi have si: "si  set ss" by (metis in_set_zipE)
      from mem si ass
      have "si  set S" by auto
    }
    thus "snd `  (vars ` fst ` set (concat (concat P)))  set S" unfolding P_def pats_def by force
  qed simp
  also have "pat_list ` set P = { { {(pat,lhs)} | lhs. lhs  set lhss} | pat. pat  set pats}" 
    unfolding pat_list_def P_def by (auto simp: image_comp)
  also have "pats_complete (set S) ?C  
     Ball { pat  σ | pat σ. pat  set pats  ?cg_subst (set S) ?C σ} ?match_lhs" (is "_ = Ball ?L _")
    unfolding pattern_completeness_context.pat_complete_def 
      pattern_completeness_context.match_complete_wrt_def matches_def 
    by auto (smt (verit, best) case_prod_conv mem_Collect_eq singletonI, blast)
  also have "?L = ℬ(?C,?D,)" (is "_ = ?R")
  proof 
    {
      fix pat and σ :: "('f,_,'v)gsubst" 
      assume pat: "pat  set pats" and subst: "?cg_subst (set S) ?C σ"
      from pat[unfolded pats_def] obtain f ss s where pat: "pat = Fun f (map Var (zip [0..<length ss] ss))" 
        and inDs: "((f,ss),s)  set D" by auto
      from dist(2) inDs have f: "f : ss  s in ?D" unfolding hastype_in_ssig_def by simp
      {
        fix i
        assume i: "i < length ss" 
        hence "ss ! i  set ss" by auto
        with inDs ass have "ss ! i  set S" by auto
        with subst have "σ (i, ss ! i) : ss ! i in 𝒯(?C,)" unfolding pattern_completeness_context.cg_subst_def 
            pattern_completeness_context.EMPTY_def by auto
      } note ssigma = this
      define ts where "ts = (map (λ i. σ (i, ss ! i)) [0..<length ss])" 
      have ts: "ts :l ss in 𝒯(?C,)" unfolding list_all2_conv_all_nth ts_def using ssigma by auto
      have pat: "pat  σ = Fun f ts" 
        unfolding pat ts_def by (auto intro: nth_equalityI)
      from pat f ts have "pat  σ  ?R" unfolding basic_terms_def by auto
    }
    thus "?L  ?R" by blast
    {
      fix f ss s and ts :: "('f,'v)term list" 
      assume f: "f : ss  s in ?D" and ts: "ts :l ss in 𝒯(?C,)" 
      from ts have len: "length ts = length ss" by (metis list_all2_lengthD)
      define pat where "pat = Fun f (map Var (zip [0..<length ss] ss))"
      from f have "((f,ss),s)  set D" unfolding hastype_in_ssig_def by (metis map_of_SomeD)
      hence pat: "pat  set pats" unfolding pat_def pats_def by force
      define σ where "σ x = (case x of (i,s)  if i < length ss  s = ss ! i then ts ! i else 
        (SOME t. t : s in 𝒯(?C,?EMPTY)))" for x
      have id: "Fun f ts = pat  σ" unfolding pat_def using len
        by (auto intro!: nth_equalityI simp: σ_def)
      have ssigma: "?cg_subst (set S) ?C σ" 
        unfolding pattern_completeness_context.cg_subst_def
      proof (intro allI impI)
        fix x :: "nat × _" 
        assume "snd x  set S" 
        then obtain i s where x: "x = (i,s)" and s: "s  set S" by (cases x, auto)
        show "σ x : snd x in 𝒯(?C,?EMPTY)" 
        proof (cases "i < length ss  s = ss ! i")
          case True
          hence id: "σ x = ts ! i" unfolding x σ_def by auto
          from ts True show ?thesis unfolding id unfolding x snd_conv pattern_completeness_context.EMPTY_def 
            by (simp add: list_all2_conv_all_nth)
        next
          case False
          hence id: "σ x = (SOME t. t : s in 𝒯(?C,?EMPTY))" unfolding x σ_def by auto
          from decide_nonempty_sorts(1)[OF dist(1) refl dec] s
          have " t. t : s in 𝒯(?C,?EMPTY)" unfolding pattern_completeness_context.EMPTY_def by auto
          from someI_ex[OF this] have "σ x : s in 𝒯(?C,?EMPTY)" unfolding id .
          thus ?thesis unfolding x by auto
        qed
      qed
      from pat id ssigma
      have "Fun f ts  ?L" by auto
    }
    thus "?R  ?L" unfolding basic_terms_def by auto
  qed
  finally show ?thesis unfolding pat_complete_lhss_def by blast
qed

text ‹Definition of strong quasi-reducibility and a corresponding decision procedure›

definition strong_quasi_reducible :: "('f,'s)ssig  ('f,'s)ssig  ('f,'v)term set  bool" where
  "strong_quasi_reducible C D L =
  ( t  ℬ(C,D,).  ti  set (t # args t). l  L. l matches ti)" 


definition term_and_args :: "'f  ('f,'v)term list  ('f,'v)term list" where
  "term_and_args f ts = Fun f ts # ts"  

definition decide_strong_quasi_reducible :: 
  "(('f × 's list) × 's)list  (('f × 's list) × 's)list  ('f,'v)term list  showsl + bool" where
  "decide_strong_quasi_reducible C D lhss = do {
    check (distinct (map fst C)) (showsl_lit (STR ''constructor information contains duplicate''));
    check (distinct (map fst D)) (showsl_lit (STR ''defined symbol information contains duplicate''));
    let S = sorts_of_ssig_list C;
    check_allm (λ ((f,ss),_). check_allm (λ s. check (s  set S) 
      (showsl_lit (STR ''defined symbol f has argument sort s that is not known in constructors''))) ss) D;
    (case (decide_nonempty_sorts S C) of None  return () | Some s  error (showsl_lit (STR ''sort s is empty'')));
    let pats = map (λ ((f,ss),s). term_and_args f (map Var (zip [0..<length ss] ss))) D;
    let P = map (List.maps (λ pat. map (λ lhs. [(pat,lhs)]) lhss)) pats;
    return (decide_pat_complete C P)
  }" 

lemma decide_strong_quasi_reducible: 
  assumes "decide_strong_quasi_reducible C D (lhss :: ('f,'v)term list) = return b" 
  shows "b = strong_quasi_reducible (map_of C) (map_of D) (set lhss)" 
proof -
  let ?EMPTY = "pattern_completeness_context.EMPTY" 
  let ?cg_subst = "pattern_completeness_context.cg_subst" 
  let ?C = "map_of C"
  let ?D = "map_of D" 
  define S where "S = sorts_of_ssig_list C" 
  define pats where "pats = map (λ ((f,ss),s). term_and_args f (map Var (zip [0..<length ss] ss))) D" 
  define P where "P = map (List.maps (λ pat. map (λ lhs. [(pat,lhs)]) lhss)) pats" 
  let ?match_lhs = "λt. l  set lhss. l matches t" 
  note ass = assms(1)[unfolded decide_strong_quasi_reducible_def, folded S_def, folded pats_def, 
      unfolded Let_def, folded P_def]
  from ass have dec: "decide_nonempty_sorts S C = None" (is "?e = _") by (cases ?e, auto) 
  note ass = ass[unfolded dec, simplified]
  from ass have b: "b = decide_pat_complete C P" and dist: "distinct (map fst C)" "distinct (map fst D)" by auto
  have "b = decide_pat_complete C P" by fact
  also have " = pats_complete (set S) ?C (pat_list ` set P)" 
  proof (rule decide_pat_complete[OF refl dist(1) dec[unfolded S_def]], unfold S_def[symmetric])
    {
      fix f ss s i si
      assume mem: "((f, ss), s)  set D" and isi: "(i, si)  set (zip [0..<length ss] ss)"
      from isi have si: "si  set ss" by (metis in_set_zipE)
      from mem si ass
      have "si  set S" by auto
    }
    thus "snd `  (vars ` fst ` set (concat (concat P)))  set S" unfolding P_def pats_def term_and_args_def List.maps_def
      by fastforce
  qed simp
  also have "pat_list ` set P = { { {(pat,lhs)} | lhs pat. pat  set patL  lhs  set lhss} | patL. patL  set pats}" 
    unfolding pat_list_def P_def List.maps_def by (auto simp: image_comp) force+
  also have "pats_complete (set S) ?C  
     ( patsL σ. patsL  set pats  ?cg_subst (set S) ?C σ  ( pat  set patsL. ?match_lhs (pat  σ)))" (is "_  ?L")
    unfolding pattern_completeness_context.pat_complete_def 
      pattern_completeness_context.match_complete_wrt_def matches_def 
    by auto 
      (smt (verit, best) case_prod_conv mem_Collect_eq singletonI, 
        metis (mono_tags, lifting) case_prod_conv singleton_iff)
  also have "?L 
     ( f ss s (ts :: ('f,'v)term list). f : ss  s in ?D  ts :l ss in 𝒯(?C,)  
           ( ti  set (term_and_args f ts). ?match_lhs ti))" (is "_ = ?R")
  proof (standard; intro allI impI)  
    fix patL and σ :: "('f,_,'v)gsubst" 
    assume patL: "patL  set pats" and subst: "?cg_subst (set S) ?C σ" and R: ?R
    from patL[unfolded pats_def] obtain f ss s where patL: "patL = term_and_args f (map Var (zip [0..<length ss] ss))" 
      and inDs: "((f,ss),s)  set D" by auto
    from dist(2) inDs have f: "f : ss  s in ?D" unfolding hastype_in_ssig_def by simp
    {
      fix i
      assume i: "i < length ss" 
      hence "ss ! i  set ss" by auto
      with inDs ass have "ss ! i  set S" by auto
      with subst have "σ (i, ss ! i) : ss ! i in 𝒯(?C,)" 
        unfolding pattern_completeness_context.cg_subst_def pattern_completeness_context.EMPTY_def by auto
    } note ssigma = this
    define ts where "ts = (map (λ i. σ (i, ss ! i)) [0..<length ss])" 
    have ts: "ts :l ss in 𝒯(?C,)" unfolding list_all2_conv_all_nth ts_def using ssigma by auto
    from R[rule_format, OF f ts] obtain ti where ti: "ti  set (term_and_args f ts)" and match: "?match_lhs ti" by auto
    have "map (λ pat. pat  σ) patL = term_and_args f ts" unfolding patL term_and_args_def ts_def
      by (auto intro: nth_equalityI)
    from ti[folded this] match
    show "patset patL. ?match_lhs (pat  σ)" by auto
  next
    fix f ss s and ts :: "('f,'v)term list" 
    assume f: "f : ss  s in ?D" and ts: "ts :l ss in 𝒯(?C,)" and L: ?L
    from ts have len: "length ts = length ss" by (metis list_all2_lengthD)
    define patL where "patL = term_and_args f (map Var (zip [0..<length ss] ss))" 
    from f have "((f,ss),s)  set D" unfolding hastype_in_ssig_def by (metis map_of_SomeD)
    hence patL: "patL  set pats" unfolding patL_def pats_def by force
    define σ where "σ x = (case x of (i,s)  if i < length ss  s = ss ! i then ts ! i else 
      (SOME t. t : s in 𝒯(?C,?EMPTY)))" for x
    have ssigma: "?cg_subst (set S) ?C σ" 
      unfolding pattern_completeness_context.cg_subst_def
    proof (intro allI impI)
      fix x :: "nat × _" 
      assume "snd x  set S" 
      then obtain i s where x: "x = (i,s)" and s: "s  set S" by (cases x, auto)
      show "σ x : snd x in 𝒯(?C,?EMPTY)" 
      proof (cases "i < length ss  s = ss ! i")
        case True
        hence id: "σ x = ts ! i" unfolding x σ_def by auto
        from ts True show ?thesis unfolding id unfolding x snd_conv pattern_completeness_context.EMPTY_def 
          by (simp add: list_all2_conv_all_nth)
      next
        case False
        hence id: "σ x = (SOME t. t : s in 𝒯(?C,?EMPTY))" unfolding x σ_def by auto
        from decide_nonempty_sorts(1)[OF dist(1) refl dec] s
        have " t. t : s in 𝒯(?C,?EMPTY)" unfolding pattern_completeness_context.EMPTY_def by auto
        from someI_ex[OF this] have "σ x : s in 𝒯(?C,?EMPTY)" unfolding id .
        thus ?thesis unfolding x by auto
      qed
    qed
    from L[rule_format, OF patL ssigma]
    obtain pat where pat: "pat  set patL" and match: "?match_lhs (pat  σ)" by auto
    have id: "map (λ pat. pat  σ) patL = term_and_args f ts" unfolding patL_def term_and_args_def using len
      by (auto intro!: nth_equalityI simp: σ_def)      
    show "ti  set (term_and_args f ts). ?match_lhs ti" unfolding id[symmetric] using pat match by auto
  qed
  also have " = (t. t  ℬ(?C,?D,)  ( ti  set (t # args t). ?match_lhs ti))" 
    unfolding basic_terms_def term_and_args_def by force
  finally show ?thesis unfolding strong_quasi_reducible_def by blast
qed

subsection ‹Connecting Pattern-Completeness, Strong Quasi-Reducibility and Quasi-Reducibility›

definition quasi_reducible :: "('f,'s)ssig  ('f,'s)ssig  ('f,'v)term set  bool" where
  "quasi_reducible C D L = ( t  ℬ(C,D,).  tp  t. l  L. l matches tp)" 

lemma pat_complete_imp_strong_quasi_reducible:
  "pat_complete_lhss C D L  strong_quasi_reducible C D L" 
  unfolding pat_complete_lhss_def strong_quasi_reducible_def by force

lemma arg_imp_subt: "s  set (args t)  t  s" 
  by (cases t, auto)

lemma strong_quasi_reducible_imp_quasi_reducible:
  "strong_quasi_reducible C D L  quasi_reducible C D L" 
  unfolding strong_quasi_reducible_def quasi_reducible_def 
  by (force dest: arg_imp_subt)

text ‹If no root symbol of a left-hand sides is a constructor, then pattern completeness and 
  quasi-reducibility coincide.›
lemma quasi_reducible_iff_pat_complete: fixes L :: "('f,'v)term set" 
  assumes " l f ls τs τ. l  L  l = Fun f ls  ¬ f : τs  τ in C" 
  shows "pat_complete_lhss C D L  quasi_reducible C D L" 
proof (standard, rule strong_quasi_reducible_imp_quasi_reducible[OF pat_complete_imp_strong_quasi_reducible])
  assume q: "quasi_reducible C D L" 
  show "pat_complete_lhss C D L" 
    unfolding pat_complete_lhss_def
  proof 
    fix t :: "('f,'v)term" 
    assume t: "t  ℬ(C,D,)" 
    from q[unfolded quasi_reducible_def, rule_format, OF this]
    obtain tp where tp: "t  tp" and match: "l  L. l matches tp" by auto
    show "l  L. l matches t" 
    proof (cases "t = tp")
      case True
      thus ?thesis using match by auto
    next
      case False
      from t[unfolded basic_terms_def] obtain f ts ss where t: "t = Fun f ts" and ts: "ts :l ss in 𝒯(C,)" by auto
      from t False tp obtain ti where ti: "ti  set ts" and subt: "ti  tp"
        by (meson Fun_supteq)
      from subt obtain CC where ctxt: "ti = CC  tp " by auto
      from ti ts obtain s where "ti : s in 𝒯(C,)" unfolding list_all2_conv_all_nth set_conv_nth by auto
      from hastype_context_decompose[OF this[unfolded ctxt]] obtain s where tp: "tp : s in 𝒯(C,)" by blast
      from match[unfolded matches_def] obtain l σ where l: "l  L" and match: "tp = l  σ" by auto
      show ?thesis
      proof (cases l)
        case (Var x)
        with l show ?thesis unfolding matches_def by (auto intro!: bexI[of _ l])
      next
        case (Fun f ls)
        from tp[unfolded match this, simplified] obtain ss where "f : ss  s in C" 
          by (meson Fun_hastype hastype_def hastype_in_ssig_def)
        with assms[OF l Fun, of ss s] show ?thesis by auto
      qed
    qed
  qed
qed

end