diff --git a/thys/Lambda_Free_RPOs/Lambda_Free_Term.thy b/thys/Lambda_Free_RPOs/Lambda_Free_Term.thy --- a/thys/Lambda_Free_RPOs/Lambda_Free_Term.thy +++ b/thys/Lambda_Free_RPOs/Lambda_Free_Term.thy @@ -1,597 +1,599 @@ (* Title: Lambda-Free Higher-Order Terms Author: Jasmin Blanchette , 2016 Maintainer: Jasmin Blanchette *) section \Lambda-Free Higher-Order Terms\ theory Lambda_Free_Term imports Lambda_Free_Util abbrevs ">s" = ">\<^sub>s" and ">h" = ">\<^sub>h\<^sub>d" and "\\h" = "\\\<^sub>h\<^sub>d" begin text \ This theory defines \\\-free higher-order terms and related locales. \ subsection \Precedence on Symbols\ locale gt_sym = fixes gt_sym :: "'s \ 's \ bool" (infix ">\<^sub>s" 50) assumes gt_sym_irrefl: "\ f >\<^sub>s f" and gt_sym_trans: "h >\<^sub>s g \ g >\<^sub>s f \ h >\<^sub>s f" and gt_sym_total: "f >\<^sub>s g \ g >\<^sub>s f \ g = f" and gt_sym_wf: "wfP (\f g. g >\<^sub>s f)" begin lemma gt_sym_antisym: "f >\<^sub>s g \ \ g >\<^sub>s f" by (metis gt_sym_irrefl gt_sym_trans) end + subsection \Heads\ datatype (plugins del: size) (syms_hd: 's, vars_hd: 'v) hd = is_Var: Var (var: 'v) | Sym (sym: 's) abbreviation is_Sym :: "('s, 'v) hd \ bool" where "is_Sym \ \ \ is_Var \" lemma finite_vars_hd[simp]: "finite (vars_hd \)" by (cases \) auto lemma finite_syms_hd[simp]: "finite (syms_hd \)" by (cases \) auto subsection \Terms\ consts head0 :: 'a datatype (syms: 's, vars: 'v) tm = is_Hd: Hd (head: "('s, 'v) hd") | App ("fun": "('s, 'v) tm") (arg: "('s, 'v) tm") where "head (App s _) = head0 s" | "fun (Hd \) = Hd \" | "arg (Hd \) = Hd \" overloading head0 \ "head0 :: ('s, 'v) tm \ ('s, 'v) hd" begin primrec head0 :: "('s, 'v) tm \ ('s, 'v) hd" where "head0 (Hd \) = \" | "head0 (App s _) = head0 s" end lemma head_App[simp]: "head (App s t) = head s" by (cases s) auto declare tm.sel(2)[simp del] lemma head_fun[simp]: "head (fun s) = head s" by (cases s) auto abbreviation ground :: "('s, 'v) tm \ bool" where "ground t \ vars t = {}" abbreviation is_App :: "('s, 'v) tm \ bool" where "is_App s \ \ is_Hd s" lemma size_fun_lt: "is_App s \ size (fun s) < size s" and size_arg_lt: "is_App s \ size (arg s) < size s" by (cases s; simp)+ lemma finite_vars[simp]: "finite (vars s)" and finite_syms[simp]: "finite (syms s)" by (induct s) auto lemma vars_head_subseteq: "vars_hd (head s) \ vars s" and syms_head_subseteq: "syms_hd (head s) \ syms s" by (induct s) auto fun args :: "('s, 'v) tm \ ('s, 'v) tm list" where "args (Hd _) = []" | "args (App s t) = args s @ [t]" lemma set_args_fun: "set (args (fun s)) \ set (args s)" by (cases s) auto lemma arg_in_args: "is_App s \ arg s \ set (args s)" by (cases s rule: tm.exhaust) auto lemma vars_args_subseteq: "si \ set (args s) \ vars si \ vars s" and syms_args_subseteq: "si \ set (args s) \ syms si \ syms s" by (induct s) auto lemma args_Nil_iff_is_Hd: "args s = [] \ is_Hd s" by (cases s) auto abbreviation num_args :: "('s, 'v) tm \ nat" where "num_args s \ length (args s)" lemma size_ge_num_args: "size s \ num_args s" by (induct s) auto lemma Hd_head_id: "num_args s = 0 \ Hd (head s) = s" by (metis args.cases args.simps(2) length_0_conv snoc_eq_iff_butlast tm.collapse(1) tm.disc(1)) lemma one_arg_imp_Hd: "num_args s = 1 \ s = App t u \ t = Hd (head t)" by (simp add: Hd_head_id) lemma size_in_args: "s \ set (args t) \ size s < size t" by (induct t) auto primrec apps :: "('s, 'v) tm \ ('s, 'v) tm list \ ('s, 'v) tm" where "apps s [] = s" | "apps s (t # ts) = apps (App s t) ts" lemma vars_apps[simp]: "vars (apps s ss) = vars s \ (\s \ set ss. vars s)" and syms_apps[simp]: "syms (apps s ss) = syms s \ (\s \ set ss. syms s)" and head_apps[simp]: "head (apps s ss) = head s" and args_apps[simp]: "args (apps s ss) = args s @ ss" and is_App_apps[simp]: "is_App (apps s ss) \ args (apps s ss) \ []" and fun_apps_Nil[simp]: "fun (apps s []) = fun s" and fun_apps_Cons[simp]: "fun (apps (App s sa) ss) = apps s (butlast (sa # ss))" and arg_apps_Nil[simp]: "arg (apps s []) = arg s" and arg_apps_Cons[simp]: "arg (apps (App s sa) ss) = last (sa # ss)" by (induct ss arbitrary: s sa) (auto simp: args_Nil_iff_is_Hd) lemma apps_append[simp]: "apps s (ss @ ts) = apps (apps s ss) ts" by (induct ss arbitrary: s ts) auto lemma App_apps: "App (apps s ts) t = apps s (ts @ [t])" by simp lemma tm_inject_apps[iff, induct_simp]: "apps (Hd \) ss = apps (Hd \) ts \ \ = \ \ ss = ts" by (metis args_apps head_apps same_append_eq tm.sel(1)) lemma tm_collapse_apps[simp]: "apps (Hd (head s)) (args s) = s" by (induct s) auto lemma tm_expand_apps: "head s = head t \ args s = args t \ s = t" by (metis tm_collapse_apps) lemma tm_exhaust_apps_sel[case_names apps]: "(s = apps (Hd (head s)) (args s) \ P) \ P" by (atomize_elim, induct s) auto lemma tm_exhaust_apps[case_names apps]: "(\\ ss. s = apps (Hd \) ss \ P) \ P" by (metis tm_collapse_apps) lemma tm_induct_apps[case_names apps]: assumes "\\ ss. (\s. s \ set ss \ P s) \ P (apps (Hd \) ss)" shows "P s" using assms by (induct s taking: size rule: measure_induct_rule) (metis size_in_args tm_collapse_apps) lemma ground_fun: "ground s \ ground (fun s)" and ground_arg: "ground s \ ground (arg s)" by (induct s) auto lemma ground_head: "ground s \ is_Sym (head s)" by (cases s rule: tm_exhaust_apps) (auto simp: is_Var_def) lemma ground_args: "t \ set (args s) \ ground s \ ground t" by (induct s rule: tm_induct_apps) auto primrec vars_mset :: "('s, 'v) tm \ 'v multiset" where "vars_mset (Hd \) = mset_set (vars_hd \)" | "vars_mset (App s t) = vars_mset s + vars_mset t" lemma set_vars_mset[simp]: "set_mset (vars_mset t) = vars t" by (induct t) auto lemma vars_mset_empty_iff[iff]: "vars_mset s = {#} \ ground s" by (induct s) (auto simp: mset_set_empty_iff) lemma vars_mset_fun[intro]: "vars_mset (fun t) \# vars_mset t" by (cases t) auto lemma vars_mset_arg[intro]: "vars_mset (arg t) \# vars_mset t" by (cases t) auto subsection \hsize\ -text \The hsize of a term is the number of heads (Syms or Vars) in a term.\ +text \The hsize of a term is the number of heads (Syms or Vars) in the term.\ primrec hsize :: "('s, 'v) tm \ nat" where "hsize (Hd \) = 1" | "hsize (App s t) = hsize s + hsize t" lemma hsize_size: "hsize t * 2 = size t + 1" by (induct t) auto lemma hsize_pos[simp]: "hsize t > 0" by (induction t; simp) lemma hsize_fun_lt: "is_App s \ hsize (fun s) < hsize s" by (cases s; simp) lemma hsize_arg_lt: "is_App s \ hsize (arg s) < hsize s" by (cases s; simp) lemma hsize_ge_num_args: "hsize s \ hsize s" by (induct s) auto lemma hsize_in_args: "s \ set (args t) \ hsize s < hsize t" by (induct t) auto lemma hsize_apps: "hsize (apps t ts) = hsize t + sum_list (map hsize ts)" by (induct ts arbitrary:t; simp) lemma hsize_args: "1 + sum_list (map hsize (args t)) = hsize t" by (metis hsize.simps(1) hsize_apps tm_collapse_apps) + subsection \Substitutions\ primrec subst :: "('v \ ('s, 'v) tm) \ ('s, 'v) tm \ ('s, 'v) tm" where "subst \ (Hd \) = (case \ of Var x \ \ x | Sym f \ Hd (Sym f))" | "subst \ (App s t) = App (subst \ s) (subst \ t)" lemma subst_apps[simp]: "subst \ (apps s ts) = apps (subst \ s) (map (subst \) ts)" by (induct ts arbitrary: s) auto lemma head_subst[simp]: "head (subst \ s) = head (subst \ (Hd (head s)))" by (cases s rule: tm_exhaust_apps) (auto split: hd.split) lemma args_subst[simp]: "args (subst \ s) = (case head s of Var x \ args (\ x) | Sym f \ []) @ map (subst \) (args s)" by (cases s rule: tm_exhaust_apps) (auto split: hd.split) lemma ground_imp_subst_iden: "ground s \ subst \ s = s" by (induct s) (auto split: hd.split) lemma vars_mset_subst[simp]: "vars_mset (subst \ s) = (\# {#vars_mset (\ x). x \# vars_mset s#})" proof (induct s) case (Hd \) show ?case by (cases \) auto qed auto lemma vars_mset_subst_subseteq: "vars_mset t \# vars_mset s \ vars_mset (subst \ t) \# vars_mset (subst \ s)" unfolding vars_mset_subst by (metis (no_types) add_diff_cancel_right' diff_subset_eq_self image_mset_union sum_mset.union subset_mset.add_diff_inverse) lemma vars_subst_subseteq: "vars t \ vars s \ vars (subst \ t) \ vars (subst \ s)" unfolding set_vars_mset[symmetric] vars_mset_subst by auto subsection \Subterms\ inductive sub :: "('s, 'v) tm \ ('s, 'v) tm \ bool" where sub_refl: "sub s s" | sub_fun: "sub s t \ sub s (App u t)" | sub_arg: "sub s t \ sub s (App t u)" inductive_cases sub_HdE[simplified, elim]: "sub s (Hd \)" inductive_cases sub_AppE[simplified, elim]: "sub s (App t u)" inductive_cases sub_Hd_HdE[simplified, elim]: "sub (Hd \) (Hd \)" inductive_cases sub_Hd_AppE[simplified, elim]: "sub (Hd \) (App t u)" lemma in_vars_imp_sub: "x \ vars s \ sub (Hd (Var x)) s" by induct (auto intro: sub.intros elim: hd.set_cases(2)) lemma sub_args: "s \ set (args t) \ sub s t" by (induct t) (auto intro: sub.intros) lemma sub_size: "sub s t \ size s \ size t" by induct auto lemma sub_subst: "sub s t \ sub (subst \ s) (subst \ t)" proof (induct t) case (Hd \) thus ?case by (cases \; blast intro: sub.intros) qed (auto intro: sub.intros del: sub_AppE elim!: sub_AppE) abbreviation proper_sub :: "('s, 'v) tm \ ('s, 'v) tm \ bool" where "proper_sub s t \ sub s t \ s \ t" lemma proper_sub_Hd[simp]: "\ proper_sub s (Hd \)" using sub.cases by blast lemma proper_sub_subst: assumes psub: "proper_sub s t" shows "proper_sub (subst \ s) (subst \ t)" proof (cases t) case Hd thus ?thesis using psub by simp next case t: (App t1 t2) have "sub s t1 \ sub s t2" using t psub by blast hence "sub (subst \ s) (subst \ t1) \ sub (subst \ s) (subst \ t2)" using sub_subst by blast thus ?thesis unfolding t by (auto intro: sub.intros dest: sub_size) qed subsection \Maximum Arities\ locale arity = fixes arity_sym :: "'s \ enat" and arity_var :: "'v \ enat" begin primrec arity_hd :: "('s, 'v) hd \ enat" where "arity_hd (Var x) = arity_var x" | "arity_hd (Sym f) = arity_sym f" definition arity :: "('s, 'v) tm \ enat" where "arity s = arity_hd (head s) - num_args s" lemma arity_simps[simp]: "arity (Hd \) = arity_hd \" "arity (App s t) = arity s - 1" by (auto simp: arity_def enat_diff_diff_eq add.commute eSuc_enat plus_1_eSuc(1)) lemma arity_apps[simp]: "arity (apps s ts) = arity s - length ts" proof (induct ts arbitrary: s) case (Cons t ts) thus ?case by (case_tac "arity s"; simp add: one_enat_def) qed simp inductive wary :: "('s, 'v) tm \ bool" where wary_Hd[intro]: "wary (Hd \)" | wary_App[intro]: "wary s \ wary t \ num_args s < arity_hd (head s) \ wary (App s t)" inductive_cases wary_HdE: "wary (Hd \)" inductive_cases wary_AppE: "wary (App s t)" inductive_cases wary_binaryE[simplified]: "wary (App (App s t) u)" lemma wary_fun[intro]: "wary t \ wary (fun t)" by (cases t) (auto elim: wary.cases) lemma wary_arg[intro]: "wary t \ wary (arg t)" by (cases t) (auto elim: wary.cases) lemma wary_args: "s \ set (args t) \ wary t \ wary s" by (induct t arbitrary: s, simp) (metis Un_iff args.simps(2) wary.cases insert_iff length_pos_if_in_set less_numeral_extra(3) list.set(2) list.size(3) set_append tm.distinct(1) tm.inject(2)) lemma wary_sub: "sub s t \ wary t \ wary s" by (induct rule: sub.induct) (auto elim: wary.cases) lemma wary_inf_ary: "(\\. arity_hd \ = \) \ wary s" by induct auto lemma wary_num_args_le_arity_head: "wary s \ num_args s \ arity_hd (head s)" by (induct rule: wary.induct) (auto simp: zero_enat_def[symmetric] Suc_ile_eq) lemma wary_apps: "wary s \ (\sa. sa \ set ss \ wary sa) \ length ss \ arity s \ wary (apps s ss)" proof (induct ss arbitrary: s) case (Cons sa ss) note ih = this(1) and wary_s = this(2) and wary_ss = this(3) and nargs_s_sa_ss = this(4) show ?case unfolding apps.simps proof (rule ih) have "wary sa" using wary_ss by simp moreover have " enat (num_args s) < arity_hd (head s)" by (metis (mono_tags) One_nat_def add.comm_neutral arity_def diff_add_zero enat_ord_simps(1) idiff_enat_enat less_one list.size(4) nargs_s_sa_ss not_add_less2 order.not_eq_order_implies_strict wary_num_args_le_arity_head wary_s) ultimately show "wary (App s sa)" by (rule wary_App[OF wary_s]) next show "\sa. sa \ set ss \ wary sa" using wary_ss by simp next show "length ss \ arity (App s sa)" proof (cases "arity s") case enat thus ?thesis using nargs_s_sa_ss by (simp add: one_enat_def) qed simp qed qed simp lemma wary_cases_apps[consumes 1, case_names apps]: assumes wary_t: "wary t" and apps: "\\ ss. t = apps (Hd \) ss \ (\sa. sa \ set ss \ wary sa) \ length ss \ arity_hd \ \ P" shows P using apps proof (atomize_elim, cases t rule: tm_exhaust_apps) case t: (apps \ ss) show "\\ ss. t = apps (Hd \) ss \ (\sa. sa \ set ss \ wary sa) \ enat (length ss) \ arity_hd \" by (rule exI[of _ \], rule exI[of _ ss]) (auto simp: t wary_args[OF _ wary_t] wary_num_args_le_arity_head[OF wary_t, unfolded t, simplified]) qed lemma arity_hd_head: "wary s \ arity_hd (head s) = arity s + num_args s" by (simp add: arity_def enat_sub_add_same wary_num_args_le_arity_head) lemma arity_head_ge: "arity_hd (head s) \ arity s" by (induct s) (auto intro: enat_le_imp_minus_le) inductive wary_fo :: "('s, 'v) tm \ bool" where wary_foI[intro]: "is_Hd s \ is_Sym (head s) \ length (args s) = arity_hd (head s) \ (\t \ set (args s). wary_fo t) \ wary_fo s" lemma wary_fo_args: "s \ set (args t) \ wary_fo t \ wary_fo s" by (induct t arbitrary: s rule: tm_induct_apps, simp) (metis args.simps(1) args_apps self_append_conv2 wary_fo.cases) lemma wary_fo_arg: "wary_fo (App s t) \ wary_fo t" by (erule wary_fo.cases) auto end subsection \Potential Heads of Ground Instances of Variables\ locale ground_heads = gt_sym "(>\<^sub>s)" + arity arity_sym arity_var for gt_sym :: "'s \ 's \ bool" (infix ">\<^sub>s" 50) and arity_sym :: "'s \ enat" and arity_var :: "'v \ enat" + fixes ground_heads_var :: "'v \ 's set" assumes ground_heads_var_arity: "f \ ground_heads_var x \ arity_sym f \ arity_var x" and ground_heads_var_nonempty: "ground_heads_var x \ {}" begin primrec ground_heads :: "('s, 'v) hd \ 's set" where "ground_heads (Var x) = ground_heads_var x" | "ground_heads (Sym f) = {f}" lemma ground_heads_arity: "f \ ground_heads \ \ arity_sym f \ arity_hd \" by (cases \) (auto simp: ground_heads_var_arity) lemma ground_heads_nonempty[simp]: "ground_heads \ \ {}" by (cases \) (auto simp: ground_heads_var_nonempty) lemma sym_in_ground_heads: "is_Sym \ \ sym \ \ ground_heads \" by (metis ground_heads.simps(2) hd.collapse(2) hd.set_sel(1) hd.simps(16)) lemma ground_hd_in_ground_heads: "ground s \ sym (head s) \ ground_heads (head s)" by (simp add: ground_head sym_in_ground_heads) lemma some_ground_head_arity: "arity_sym (SOME f. f \ ground_heads (Var x)) \ arity_var x" by (simp add: ground_heads_var_arity ground_heads_var_nonempty some_in_eq) definition wary_subst :: "('v \ ('s, 'v) tm) \ bool" where "wary_subst \ \ (\x. wary (\ x) \ arity (\ x) \ arity_var x \ ground_heads (head (\ x)) \ ground_heads_var x)" definition strict_wary_subst :: "('v \ ('s, 'v) tm) \ bool" where "strict_wary_subst \ \ (\x. wary (\ x) \ arity (\ x) \ {arity_var x, \} \ ground_heads (head (\ x)) \ ground_heads_var x)" lemma strict_imp_wary_subst: "strict_wary_subst \ \ wary_subst \" unfolding strict_wary_subst_def wary_subst_def using eq_iff by force lemma wary_subst_wary: assumes wary_\: "wary_subst \" and wary_s: "wary s" shows "wary (subst \ s)" using wary_s proof (induct s rule: tm.induct) case (App s t) note wary_st = this(3) from wary_st have wary_s: "wary s" by (rule wary_AppE) from wary_st have wary_t: "wary t" by (rule wary_AppE) from wary_st have nargs_s_lt: "num_args s < arity_hd (head s)" by (rule wary_AppE) note wary_\s = App(1)[OF wary_s] note wary_\t = App(2)[OF wary_t] note wary_\x = wary_\[unfolded wary_subst_def, rule_format, THEN conjunct1] note ary_\x = wary_\[unfolded wary_subst_def, rule_format, THEN conjunct2] have "num_args (\ x) + num_args s < arity_hd (head (\ x))" if hd_s: "head s = Var x" for x proof - have ary_hd_s: "arity_hd (head s) = arity_var x" using hd_s arity_hd.simps(1) by presburger hence "num_args s \ arity (\ x)" by (metis (no_types) wary_num_args_le_arity_head ary_\x dual_order.trans wary_s) hence "num_args s + num_args (\ x) \ arity_hd (head (\ x))" by (metis (no_types) arity_hd_head[OF wary_\x] add_right_mono plus_enat_simps(1)) thus ?thesis using ary_hd_s by (metis (no_types) add.commute add_diff_cancel_left' ary_\x arity_def idiff_enat_enat leD nargs_s_lt order.not_eq_order_implies_strict) qed hence nargs_\s: "num_args (subst \ s) < arity_hd (head (subst \ s))" using nargs_s_lt by (auto split: hd.split) show ?case by simp (rule wary_App[OF wary_\s wary_\t nargs_\s]) qed (auto simp: wary_\[unfolded wary_subst_def] split: hd.split) lemmas strict_wary_subst_wary = wary_subst_wary[OF strict_imp_wary_subst] lemma wary_subst_ground_heads: assumes wary_\: "wary_subst \" shows "ground_heads (head (subst \ s)) \ ground_heads (head s)" proof (induct s rule: tm_induct_apps) case (apps \ ss) show ?case proof (cases \) case x: (Var x) thus ?thesis using wary_\ wary_subst_def x by auto qed auto qed lemmas strict_wary_subst_ground_heads = wary_subst_ground_heads[OF strict_imp_wary_subst] definition grounding_\ :: "'v \ ('s, 'v) tm" where "grounding_\ x = (let s = Hd (Sym (SOME f. f \ ground_heads_var x)) in apps s (replicate (the_enat (arity s - arity_var x)) s))" lemma ground_grounding_\: "ground (subst grounding_\ s)" by (induct s) (auto simp: Let_def grounding_\_def elim: hd.set_cases(2) split: hd.split) lemma strict_wary_grounding_\: "strict_wary_subst grounding_\" unfolding strict_wary_subst_def proof (intro allI conjI) fix x define f where "f = (SOME f. f \ ground_heads_var x)" define s :: "('s, 'v) tm" where "s = Hd (Sym f)" have wary_s: "wary s" unfolding s_def by (rule wary_Hd) have ary_s_ge_x: "arity s \ arity_var x" unfolding s_def f_def using some_ground_head_arity by simp have gr\_x: "grounding_\ x = apps s (replicate (the_enat (arity s - arity_var x)) s)" unfolding grounding_\_def Let_def f_def[symmetric] s_def[symmetric] by (rule refl) show "wary (grounding_\ x)" unfolding gr\_x by (auto intro!: wary_s wary_apps[OF wary_s] enat_the_enat_minus_le) show "arity (grounding_\ x) \ {arity_var x, \}" unfolding gr\_x using ary_s_ge_x by (cases "arity s"; cases "arity_var x"; simp) show "ground_heads (head (grounding_\ x)) \ ground_heads_var x" unfolding gr\_x s_def f_def by (simp add: some_in_eq ground_heads_var_nonempty) qed lemmas wary_grounding_\ = strict_wary_grounding_\[THEN strict_imp_wary_subst] definition gt_hd :: "('s, 'v) hd \ ('s, 'v) hd \ bool" (infix ">\<^sub>h\<^sub>d" 50) where "\ >\<^sub>h\<^sub>d \ \ (\g \ ground_heads \. \f \ ground_heads \. g >\<^sub>s f)" definition comp_hd :: "('s, 'v) hd \ ('s, 'v) hd \ bool" (infix "\\\<^sub>h\<^sub>d" 50) where "\ \\\<^sub>h\<^sub>d \ \ \ = \ \ \ >\<^sub>h\<^sub>d \ \ \ >\<^sub>h\<^sub>d \" lemma gt_hd_irrefl: "\ \ >\<^sub>h\<^sub>d \" unfolding gt_hd_def using gt_sym_irrefl by (meson ex_in_conv ground_heads_nonempty) lemma gt_hd_trans: "\ >\<^sub>h\<^sub>d \ \ \ >\<^sub>h\<^sub>d \ \ \ >\<^sub>h\<^sub>d \" unfolding gt_hd_def using gt_sym_trans by (meson ex_in_conv ground_heads_nonempty) lemma gt_sym_imp_hd: "g >\<^sub>s f \ Sym g >\<^sub>h\<^sub>d Sym f" unfolding gt_hd_def by simp lemma not_comp_hd_imp_Var: "\ \ \\\<^sub>h\<^sub>d \ \ is_Var \ \ is_Var \" using gt_sym_total by (cases \; cases \; auto simp: comp_hd_def gt_hd_def) end end