2 Author: Martin Coen, Cambridge University Computer Laboratory |
2 Author: Martin Coen, Cambridge University Computer Laboratory |
3 Author: Konrad Slind, TUM & Cambridge University Computer Laboratory |
3 Author: Konrad Slind, TUM & Cambridge University Computer Laboratory |
4 Author: Alexander Krauss, TUM |
4 Author: Alexander Krauss, TUM |
5 *) |
5 *) |
6 |
6 |
7 section {* Substitution and Unification *} |
7 section \<open>Substitution and Unification\<close> |
8 |
8 |
9 theory Unification |
9 theory Unification |
10 imports Main |
10 imports Main |
11 begin |
11 begin |
12 |
12 |
13 text {* |
13 text \<open> |
14 Implements Manna \& Waldinger's formalization, with Paulson's |
14 Implements Manna \& Waldinger's formalization, with Paulson's |
15 simplifications, and some new simplifications by Slind and Krauss. |
15 simplifications, and some new simplifications by Slind and Krauss. |
16 |
16 |
17 Z Manna \& R Waldinger, Deductive Synthesis of the Unification |
17 Z Manna \& R Waldinger, Deductive Synthesis of the Unification |
18 Algorithm. SCP 1 (1981), 5-48 |
18 Algorithm. SCP 1 (1981), 5-48 |
23 K Slind, Reasoning about Terminating Functional Programs, |
23 K Slind, Reasoning about Terminating Functional Programs, |
24 Ph.D. thesis, TUM, 1999, Sect. 5.8 |
24 Ph.D. thesis, TUM, 1999, Sect. 5.8 |
25 |
25 |
26 A Krauss, Partial and Nested Recursive Function Definitions in |
26 A Krauss, Partial and Nested Recursive Function Definitions in |
27 Higher-Order Logic, JAR 44(4):303-336, 2010. Sect. 6.3 |
27 Higher-Order Logic, JAR 44(4):303-336, 2010. Sect. 6.3 |
28 *} |
28 \<close> |
29 |
29 |
30 |
30 |
31 subsection {* Terms *} |
31 subsection \<open>Terms\<close> |
32 |
32 |
33 text {* Binary trees with leaves that are constants or variables. *} |
33 text \<open>Binary trees with leaves that are constants or variables.\<close> |
34 |
34 |
35 datatype 'a trm = |
35 datatype 'a trm = |
36 Var 'a |
36 Var 'a |
37 | Const 'a |
37 | Const 'a |
38 | Comb "'a trm" "'a trm" (infix "\<cdot>" 60) |
38 | Comb "'a trm" "'a trm" (infix "\<cdot>" 60) |
141 |
141 |
142 lemma var_same[simp]: "[(v, t)] \<doteq> [] \<longleftrightarrow> t = Var v" |
142 lemma var_same[simp]: "[(v, t)] \<doteq> [] \<longleftrightarrow> t = Var v" |
143 by (metis assoc.simps(2) subst.simps(1) subst_eq_def var_self) |
143 by (metis assoc.simps(2) subst.simps(1) subst_eq_def var_self) |
144 |
144 |
145 |
145 |
146 subsection {* Unifiers and Most General Unifiers *} |
146 subsection \<open>Unifiers and Most General Unifiers\<close> |
147 |
147 |
148 definition Unifier :: "'a subst \<Rightarrow> 'a trm \<Rightarrow> 'a trm \<Rightarrow> bool" |
148 definition Unifier :: "'a subst \<Rightarrow> 'a trm \<Rightarrow> 'a trm \<Rightarrow> bool" |
149 where "Unifier \<sigma> t u \<longleftrightarrow> (t \<lhd> \<sigma> = u \<lhd> \<sigma>)" |
149 where "Unifier \<sigma> t u \<longleftrightarrow> (t \<lhd> \<sigma> = u \<lhd> \<sigma>)" |
150 |
150 |
151 definition MGU :: "'a subst \<Rightarrow> 'a trm \<Rightarrow> 'a trm \<Rightarrow> bool" where |
151 definition MGU :: "'a subst \<Rightarrow> 'a trm \<Rightarrow> 'a trm \<Rightarrow> bool" where |
181 |
181 |
182 lemma MGU_Const: "MGU [] (Const c) (Const d) \<longleftrightarrow> c = d" |
182 lemma MGU_Const: "MGU [] (Const c) (Const d) \<longleftrightarrow> c = d" |
183 by (auto simp: MGU_def Unifier_def) |
183 by (auto simp: MGU_def Unifier_def) |
184 |
184 |
185 |
185 |
186 subsection {* The unification algorithm *} |
186 subsection \<open>The unification algorithm\<close> |
187 |
187 |
188 function unify :: "'a trm \<Rightarrow> 'a trm \<Rightarrow> 'a subst option" |
188 function unify :: "'a trm \<Rightarrow> 'a trm \<Rightarrow> 'a subst option" |
189 where |
189 where |
190 "unify (Const c) (M \<cdot> N) = None" |
190 "unify (Const c) (M \<cdot> N) = None" |
191 | "unify (M \<cdot> N) (Const c) = None" |
191 | "unify (M \<cdot> N) (Const c) = None" |
202 Some \<theta> \<Rightarrow> (case unify (N \<lhd> \<theta>) (N' \<lhd> \<theta>) |
202 Some \<theta> \<Rightarrow> (case unify (N \<lhd> \<theta>) (N' \<lhd> \<theta>) |
203 of None \<Rightarrow> None | |
203 of None \<Rightarrow> None | |
204 Some \<sigma> \<Rightarrow> Some (\<theta> \<lozenge> \<sigma>)))" |
204 Some \<sigma> \<Rightarrow> Some (\<theta> \<lozenge> \<sigma>)))" |
205 by pat_completeness auto |
205 by pat_completeness auto |
206 |
206 |
207 subsection {* Properties used in termination proof *} |
207 subsection \<open>Properties used in termination proof\<close> |
208 |
208 |
209 text {* Elimination of variables by a substitution: *} |
209 text \<open>Elimination of variables by a substitution:\<close> |
210 |
210 |
211 definition |
211 definition |
212 "elim \<sigma> v \<equiv> \<forall>t. v \<notin> vars_of (t \<lhd> \<sigma>)" |
212 "elim \<sigma> v \<equiv> \<forall>t. v \<notin> vars_of (t \<lhd> \<sigma>)" |
213 |
213 |
214 lemma elim_intro[intro]: "(\<And>t. v \<notin> vars_of (t \<lhd> \<sigma>)) \<Longrightarrow> elim \<sigma> v" |
214 lemma elim_intro[intro]: "(\<And>t. v \<notin> vars_of (t \<lhd> \<sigma>)) \<Longrightarrow> elim \<sigma> v" |
222 |
222 |
223 lemma occs_elim: "\<not> Var v \<prec> t |
223 lemma occs_elim: "\<not> Var v \<prec> t |
224 \<Longrightarrow> elim [(v,t)] v \<or> [(v,t)] \<doteq> []" |
224 \<Longrightarrow> elim [(v,t)] v \<or> [(v,t)] \<doteq> []" |
225 by (metis elim_intro remove_var var_same vars_iff_occseq) |
225 by (metis elim_intro remove_var var_same vars_iff_occseq) |
226 |
226 |
227 text {* The result of a unification never introduces new variables: *} |
227 text \<open>The result of a unification never introduces new variables:\<close> |
228 |
228 |
229 declare unify.psimps[simp] |
229 declare unify.psimps[simp] |
230 |
230 |
231 lemma unify_vars: |
231 lemma unify_vars: |
232 assumes "unify_dom (M, N)" |
232 assumes "unify_dom (M, N)" |
286 qed auto |
286 qed auto |
287 qed |
287 qed |
288 qed (auto split: split_if_asm) |
288 qed (auto split: split_if_asm) |
289 |
289 |
290 |
290 |
291 text {* The result of a unification is either the identity |
291 text \<open>The result of a unification is either the identity |
292 substitution or it eliminates a variable from one of the terms: *} |
292 substitution or it eliminates a variable from one of the terms:\<close> |
293 |
293 |
294 lemma unify_eliminates: |
294 lemma unify_eliminates: |
295 assumes "unify_dom (M, N)" |
295 assumes "unify_dom (M, N)" |
296 assumes "unify M N = Some \<sigma>" |
296 assumes "unify M N = Some \<sigma>" |
297 shows "(\<exists>v\<in>vars_of M \<union> vars_of N. elim \<sigma> v) \<or> \<sigma> \<doteq> []" |
297 shows "(\<exists>v\<in>vars_of M \<union> vars_of N. elim \<sigma> v) \<or> \<sigma> \<doteq> []" |
330 and \<sigma>: "\<sigma> = \<theta>1 \<lozenge> \<theta>2" |
330 and \<sigma>: "\<sigma> = \<theta>1 \<lozenge> \<theta>2" |
331 and ih1: "?P M M' \<theta>1" |
331 and ih1: "?P M M' \<theta>1" |
332 and ih2: "?P (N\<lhd>\<theta>1) (N'\<lhd>\<theta>1) \<theta>2" |
332 and ih2: "?P (N\<lhd>\<theta>1) (N'\<lhd>\<theta>1) \<theta>2" |
333 by (auto split:option.split_asm) |
333 by (auto split:option.split_asm) |
334 |
334 |
335 from `unify_dom (M \<cdot> N, M' \<cdot> N')` |
335 from \<open>unify_dom (M \<cdot> N, M' \<cdot> N')\<close> |
336 have "unify_dom (M, M')" |
336 have "unify_dom (M, M')" |
337 by (rule accp_downward) (rule unify_rel.intros) |
337 by (rule accp_downward) (rule unify_rel.intros) |
338 hence no_new_vars: |
338 hence no_new_vars: |
339 "\<And>t. vars_of (t \<lhd> \<theta>1) \<subseteq> vars_of M \<union> vars_of M' \<union> vars_of t" |
339 "\<And>t. vars_of (t \<lhd> \<theta>1) \<subseteq> vars_of M \<union> vars_of M' \<union> vars_of t" |
340 by (rule unify_vars) (rule `unify M M' = Some \<theta>1`) |
340 by (rule unify_vars) (rule \<open>unify M M' = Some \<theta>1\<close>) |
341 |
341 |
342 from ih2 show ?case |
342 from ih2 show ?case |
343 proof |
343 proof |
344 assume "\<exists>v\<in>vars_of (N \<lhd> \<theta>1) \<union> vars_of (N' \<lhd> \<theta>1). elim \<theta>2 v" |
344 assume "\<exists>v\<in>vars_of (N \<lhd> \<theta>1) \<union> vars_of (N' \<lhd> \<theta>1). elim \<theta>2 v" |
345 then obtain v |
345 then obtain v |
356 finally have "\<sigma> \<doteq> \<theta>1" . |
356 finally have "\<sigma> \<doteq> \<theta>1" . |
357 |
357 |
358 from ih1 show ?thesis |
358 from ih1 show ?thesis |
359 proof |
359 proof |
360 assume "\<exists>v\<in>vars_of M \<union> vars_of M'. elim \<theta>1 v" |
360 assume "\<exists>v\<in>vars_of M \<union> vars_of M'. elim \<theta>1 v" |
361 with elim_eq[OF `\<sigma> \<doteq> \<theta>1`] |
361 with elim_eq[OF \<open>\<sigma> \<doteq> \<theta>1\<close>] |
362 show ?thesis by auto |
362 show ?thesis by auto |
363 next |
363 next |
364 note `\<sigma> \<doteq> \<theta>1` |
364 note \<open>\<sigma> \<doteq> \<theta>1\<close> |
365 also assume "\<theta>1 \<doteq> []" |
365 also assume "\<theta>1 \<doteq> []" |
366 finally show ?thesis .. |
366 finally show ?thesis .. |
367 qed |
367 qed |
368 qed |
368 qed |
369 qed |
369 qed |
370 |
370 |
371 declare unify.psimps[simp del] |
371 declare unify.psimps[simp del] |
372 |
372 |
373 subsection {* Termination proof *} |
373 subsection \<open>Termination proof\<close> |
374 |
374 |
375 termination unify |
375 termination unify |
376 proof |
376 proof |
377 let ?R = "measures [\<lambda>(M,N). card (vars_of M \<union> vars_of N), |
377 let ?R = "measures [\<lambda>(M,N). card (vars_of M \<union> vars_of N), |
378 \<lambda>(M, N). size M]" |
378 \<lambda>(M, N). size M]" |
387 "unify M M' = Some \<theta>" |
387 "unify M M' = Some \<theta>" |
388 |
388 |
389 from unify_eliminates[OF inner] |
389 from unify_eliminates[OF inner] |
390 show "((N \<lhd> \<theta>, N' \<lhd> \<theta>), (M \<cdot> N, M' \<cdot> N')) \<in>?R" |
390 show "((N \<lhd> \<theta>, N' \<lhd> \<theta>), (M \<cdot> N, M' \<cdot> N')) \<in>?R" |
391 proof |
391 proof |
392 -- {* Either a variable is eliminated \ldots *} |
392 -- \<open>Either a variable is eliminated \ldots\<close> |
393 assume "(\<exists>v\<in>vars_of M \<union> vars_of M'. elim \<theta> v)" |
393 assume "(\<exists>v\<in>vars_of M \<union> vars_of M'. elim \<theta> v)" |
394 then obtain v |
394 then obtain v |
395 where "elim \<theta> v" |
395 where "elim \<theta> v" |
396 and "v\<in>vars_of M \<union> vars_of M'" by auto |
396 and "v\<in>vars_of M \<union> vars_of M'" by auto |
397 with unify_vars[OF inner] |
397 with unify_vars[OF inner] |
400 by auto |
400 by auto |
401 |
401 |
402 thus ?thesis |
402 thus ?thesis |
403 by (auto intro!: measures_less intro: psubset_card_mono) |
403 by (auto intro!: measures_less intro: psubset_card_mono) |
404 next |
404 next |
405 -- {* Or the substitution is empty *} |
405 -- \<open>Or the substitution is empty\<close> |
406 assume "\<theta> \<doteq> []" |
406 assume "\<theta> \<doteq> []" |
407 hence "N \<lhd> \<theta> = N" |
407 hence "N \<lhd> \<theta> = N" |
408 and "N' \<lhd> \<theta> = N'" by auto |
408 and "N' \<lhd> \<theta> = N'" by auto |
409 thus ?thesis |
409 thus ?thesis |
410 by (auto intro!: measures_less intro: psubset_card_mono) |
410 by (auto intro!: measures_less intro: psubset_card_mono) |
411 qed |
411 qed |
412 qed |
412 qed |
413 |
413 |
414 |
414 |
415 subsection {* Unification returns a Most General Unifier *} |
415 subsection \<open>Unification returns a Most General Unifier\<close> |
416 |
416 |
417 lemma unify_computes_MGU: |
417 lemma unify_computes_MGU: |
418 "unify M N = Some \<sigma> \<Longrightarrow> MGU \<sigma> M N" |
418 "unify M N = Some \<sigma> \<Longrightarrow> MGU \<sigma> M N" |
419 proof (induct M N arbitrary: \<sigma> rule: unify.induct) |
419 proof (induct M N arbitrary: \<sigma> rule: unify.induct) |
420 case (7 M N M' N' \<sigma>) -- "The interesting case" |
420 case (7 M N M' N' \<sigma>) -- "The interesting case" |
459 thus "\<exists>\<gamma>. \<sigma>' \<doteq> \<sigma> \<lozenge> \<gamma>" .. |
459 thus "\<exists>\<gamma>. \<sigma>' \<doteq> \<sigma> \<lozenge> \<gamma>" .. |
460 qed |
460 qed |
461 qed (auto simp: MGU_Const intro: MGU_Var MGU_Var[symmetric] split: split_if_asm) |
461 qed (auto simp: MGU_Const intro: MGU_Var MGU_Var[symmetric] split: split_if_asm) |
462 |
462 |
463 |
463 |
464 subsection {* Unification returns Idempotent Substitution *} |
464 subsection \<open>Unification returns Idempotent Substitution\<close> |
465 |
465 |
466 definition Idem :: "'a subst \<Rightarrow> bool" |
466 definition Idem :: "'a subst \<Rightarrow> bool" |
467 where "Idem s \<longleftrightarrow> (s \<lozenge> s) \<doteq> s" |
467 where "Idem s \<longleftrightarrow> (s \<lozenge> s) \<doteq> s" |
468 |
468 |
469 lemma Idem_Nil [iff]: "Idem []" |
469 lemma Idem_Nil [iff]: "Idem []" |
507 by (auto split: option.split_asm) |
507 by (auto split: option.split_asm) |
508 |
508 |
509 from \<theta>2 have "Unifier \<theta>2 (M' \<lhd> \<theta>1) (N' \<lhd> \<theta>1)" |
509 from \<theta>2 have "Unifier \<theta>2 (M' \<lhd> \<theta>1) (N' \<lhd> \<theta>1)" |
510 by (rule unify_computes_MGU[THEN MGU_is_Unifier]) |
510 by (rule unify_computes_MGU[THEN MGU_is_Unifier]) |
511 |
511 |
512 with `Idem \<theta>1` |
512 with \<open>Idem \<theta>1\<close> |
513 show "Idem \<sigma>" unfolding \<sigma> |
513 show "Idem \<sigma>" unfolding \<sigma> |
514 proof (rule Idem_comp) |
514 proof (rule Idem_comp) |
515 fix \<sigma> assume "Unifier \<sigma> (M' \<lhd> \<theta>1) (N' \<lhd> \<theta>1)" |
515 fix \<sigma> assume "Unifier \<sigma> (M' \<lhd> \<theta>1) (N' \<lhd> \<theta>1)" |
516 with \<theta>2 obtain \<gamma> where \<sigma>: "\<sigma> \<doteq> \<theta>2 \<lozenge> \<gamma>" |
516 with \<theta>2 obtain \<gamma> where \<sigma>: "\<sigma> \<doteq> \<theta>2 \<lozenge> \<gamma>" |
517 using unify_computes_MGU MGU_def by blast |
517 using unify_computes_MGU MGU_def by blast |
518 |
518 |
519 have "\<theta>2 \<lozenge> \<sigma> \<doteq> \<theta>2 \<lozenge> (\<theta>2 \<lozenge> \<gamma>)" by (rule subst_cong) (auto simp: \<sigma>) |
519 have "\<theta>2 \<lozenge> \<sigma> \<doteq> \<theta>2 \<lozenge> (\<theta>2 \<lozenge> \<gamma>)" by (rule subst_cong) (auto simp: \<sigma>) |
520 also have "... \<doteq> (\<theta>2 \<lozenge> \<theta>2) \<lozenge> \<gamma>" by (rule comp_assoc[symmetric]) |
520 also have "... \<doteq> (\<theta>2 \<lozenge> \<theta>2) \<lozenge> \<gamma>" by (rule comp_assoc[symmetric]) |
521 also have "... \<doteq> \<theta>2 \<lozenge> \<gamma>" by (rule subst_cong) (auto simp: `Idem \<theta>2`[unfolded Idem_def]) |
521 also have "... \<doteq> \<theta>2 \<lozenge> \<gamma>" by (rule subst_cong) (auto simp: \<open>Idem \<theta>2\<close>[unfolded Idem_def]) |
522 also have "... \<doteq> \<sigma>" by (rule \<sigma>[symmetric]) |
522 also have "... \<doteq> \<sigma>" by (rule \<sigma>[symmetric]) |
523 finally show "\<theta>2 \<lozenge> \<sigma> \<doteq> \<sigma>" . |
523 finally show "\<theta>2 \<lozenge> \<sigma> \<doteq> \<sigma>" . |
524 qed |
524 qed |
525 qed (auto intro!: Var_Idem split: option.splits if_splits) |
525 qed (auto intro!: Var_Idem split: option.splits if_splits) |
526 |
526 |