我定义了一个非常简单的面向对象模型。该模型定义了一组类和一组关联。
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
谓词?还是可以建议一种更好的方法来证明这一引理?
答案 0 :(得分:2)
code_pred
命令为class_roles
生成方程式,每个推断模式一个方程式,values
使用它们。定理class_roles.equation
将它们全部显示出来。如果要使用它们来证明您的引理,则必须首先转换目标或引理语句,以使生成的class_role_...
常量之一出现。手动执行此操作非常麻烦。
如果让谓词编译器为您完成此转换,您将获得更好的自动化。由于引理包含普遍量化的变量(assoc1
,assoc2
,from
和role
),因此我建议您将引理语句的否定定义为归纳谓词,否定将通用量词转换为存在量,其在假设中由自由变量建模。然后,您可以使用证明方法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)+