如何通过求值简化归纳谓词?

时间:2019-03-03 16:43:08

标签: isabelle

我定义了一个非常简单的面向对象模型。该模型定义了一组类和一组关联。

nonterminal fmaplets and fmaplet

syntax
  "_fmaplet"  :: "['a, 'a] ⇒ fmaplet"              ("_ /↦⇩f/ _")
  "_fmaplets" :: "['a, 'a] ⇒ fmaplet"              ("_ /[↦⇩f]/ _")
  ""          :: "fmaplet ⇒ fmaplets"              ("_")
  "_FMaplets" :: "[fmaplet, fmaplets] ⇒ fmaplets"  ("_,/ _")
  "_FMapUpd"  :: "['a ⇀ 'b, fmaplets] ⇒ 'a ⇀ 'b" ("_/'(_')" [900, 0] 900)
  "_FMap"     :: "fmaplets ⇒ 'a ⇀ 'b"             ("(1[_])")

syntax (ASCII)
  "_fmaplet"  :: "['a, 'a] ⇒ fmaplet"              ("_ /|->f/ _")
  "_fmaplets" :: "['a, 'a] ⇒ fmaplet"              ("_ /[|->f]/ _")

translations
  "_FMapUpd m (_FMaplets xy ms)"      ⇌ "_FMapUpd (_FMapUpd m xy) ms"
  "_FMapUpd m (_fmaplet  x y)"        ⇌ "CONST fmupd x y m"
  "_FMap ms"                          ⇌ "_FMapUpd (CONST fmempty) ms"
  "_FMap (_FMaplets ms1 ms2)"         ↽ "_FMapUpd (_FMap ms1) ms2"
  "_FMaplets ms1 (_FMaplets ms2 ms3)" ↽ "_FMaplets (_FMaplets ms1 ms2) ms3"

datatype classes1 =
  Object | Person | Employee | Customer | Project | Task | Sprint

abbreviation "associations ≡ [
  STR ''ProjectManager'' ↦⇩f [
    STR ''projects'' ↦⇩f (Project, 0::nat, 100::nat),
    STR ''manager'' ↦⇩f (Employee, 1, 1)],
  STR ''ProjectMember'' ↦⇩f [
    STR ''member_of'' ↦⇩f (Project, 0, 100),
    STR ''members'' ↦⇩f (Employee, 1, 20)],
  STR ''ManagerEmployee'' ↦⇩f [
    STR ''line_manager'' ↦⇩f (Employee, 0, 1),
    STR ''project_manager'' ↦⇩f (Employee, 0, 100),
    STR ''employees'' ↦⇩f (Employee, 3, 7)],
  STR ''ProjectCustomer'' ↦⇩f [
    STR ''projects'' ↦⇩f (Project, 0, 100),
    STR ''customer'' ↦⇩f (Customer, 1, 1)],
  STR ''ProjectTask'' ↦⇩f [
    STR ''project'' ↦⇩f (Project, 1, 1),
    STR ''tasks'' ↦⇩f (Task, 0, 100)],
  STR ''SprintTaskAssignee'' ↦⇩f [
    STR ''sprint'' ↦⇩f (Sprint, 0, 10),
    STR ''tasks'' ↦⇩f (Task, 0, 5),
    STR ''assignee'' ↦⇩f (Employee, 0, 1)]]"

我还定义了一个class_roles谓词,该谓词将一个类与一组可以从该类导航的关联结尾相关联:

lemma fmember_code_predI [code_pred_intro]:
  "x |∈| xs" if "Predicate_Compile.contains (fset xs) x"
  using that by (simp add: Predicate_Compile.contains_def fmember.rep_eq)

code_pred fmember
  by (simp add: Predicate_Compile.contains_def fmember.rep_eq)

definition "assoc_end_class ≡ fst"

inductive assoc_refer_class where
  "role |∈| fmdom ends ⟹
   fmlookup ends role = Some end ⟹
   assoc_end_class end =  ⟹
   assoc_refer_class ends  role"

code_pred [show_modes] assoc_refer_class .

inductive class_roles where
  "assoc |∈| fmdom assocs ⟹
   fmlookup assocs assoc = Some ends ⟹
   assoc_refer_class ends  from ⟹
   role |∈| fmdom ends ⟹
   fmlookup ends role = Some end ⟹
   role ≠ from ⟹
   class_roles assocs  assoc from role"

code_pred [show_modes] class_roles .

values "{(x, y, z, a). class_roles associations x y z a}"

此谓词可以非常快速地进行评估(请参见上面的最后一行)。

我需要证明每个类的所有关联结束都是唯一的。为简单起见,我尝试为Employee类证明这一点:

lemma fmupd_to_rhs:
  "fmupd k x xm = y ⟷ y = fmupd k x xm"
  by auto

lemma class_roles_unique:
  "class_roles associations Employee assoc1 from role ⟹
   class_roles associations Employee assoc2 from role ⟹ assoc1 = assoc2"
  apply (erule class_roles.cases; erule class_roles.cases;
     erule assoc_refer_class.cases; erule assoc_refer_class.cases)
  unfolding fmupd_to_rhs
  apply (simp)
  apply (elim disjE)
  apply auto[1]
  apply auto[1]
  apply auto[1]
  (* And so on... Proving of each case is very slow *)

问题在于它非常慢。是否可以使用class_roles生成的引理简化code_pred谓词?还是可以建议一种更好的方法来证明这一引理?

1 个答案:

答案 0 :(得分:2)

code_pred命令为class_roles生成方程式,每个推断模式一个方程式,values使用它们。定理class_roles.equation将它们全部显示出来。如果要使用它们来证明您的引理,则必须首先转换目标或引理语句,以使生成的class_role_...常量之一出现。手动执行此操作非常麻烦。

如果让谓词编译器为您完成此转换,您将获得更好的自动化。由于引理包含普遍量化的变量(assoc1assoc2fromrole),因此我建议您将引理语句的否定定义为归纳谓词,否定将通用量词转换为存在量,其在假设中由自由变量建模。然后,您可以使用证明方法eval来完成繁重的工作:

inductive foo where
  "foo" if 
  "class_roles associations Employee assoc1 from role"
  "class_roles associations Employee assoc2 from role"
  "assoc1 ≠ assoc2"

code_pred foo .

lemma class_roles_unique:
  assumes "class_roles associations Employee assoc1 from role"
    and "class_roles associations Employee assoc2 from role"
  shows "assoc1 = assoc2"
proof -
  have "¬ foo" by eval
  with assms show ?thesis by(simp add: foo.simps)
qed

请注意,eval在PolyML中使用代码生成和评估,因此它计算结果而不是证明结果。也就是说,评估不由Isabelle的内核检查。相关的证明方法code_simp遍历内核,但是在本示例中它无法立即使用,因为Isabelle2018中缺少String.asciis_of_literals的代码设置。

以下引理提供了文字字符串所缺少的代码方程式,但是code_simp对于文字字符串非常慢(normalization有点快,但也不能由Isabelle的内核检查)。

definition dup_bit :: "bool ⇒ integer ⇒ integer" where
 "dup_bit b i = i + i + (if b then 1 else 0)"

lemma dup_bit_code [code]:
  "dup_bit True 0 = 1"
  "dup_bit False 0 = 0"
  "dup_bit True (Code_Numeral.Pos n) = Code_Numeral.Pos (num.Bit1 n)"
  "dup_bit False (Code_Numeral.Pos n) = Code_Numeral.Pos (num.Bit0 n)"
  "dup_bit True (Code_Numeral.Neg n) = - Code_Numeral.sub (num.Bit0 n) Num.One"
  "dup_bit False (Code_Numeral.Neg n) = Code_Numeral.Neg (num.Bit0 n)"
  by(simp_all add: dup_bit_def Code_Numeral.sub_def nat_of_num_add num_eq_iff)
    (metis diff_numeral_special(1) numeral_Bit0 numeral_plus_numeral sub_num_simps(2))

fun integer_of_bits :: "bool list ⇒ integer" where
  "integer_of_bits [] = 0"
| "integer_of_bits (b # bs) = dup_bit b (integer_of_bits bs)"

lemma asciis_of_literal_code [code]: 
  "String.asciis_of_literal (STR '''') = []"
  "String.asciis_of_literal (String.Literal b0 b1 b2 b3 b4 b5 b6 s) =
     integer_of_bits [b0, b1, b2, b3, b4, b5, b6] # String.asciis_of_literal s"
  including literal.lifting by(transfer; simp add: dup_bit_def; fail)+