Performance 伊莎贝尔/霍尔:由';simp&x27;当';价值';是瞬间的

Performance 伊莎贝尔/霍尔:由';simp&x27;当';价值';是瞬间的,performance,isabelle,Performance,Isabelle,我是伊莎贝尔/霍尔的新手,仍在学习prog prov练习。同时,我正在练习将这些证明技巧应用于组合词的问题。在“价值”和“引理”之间,我观察到一种非常不同的行为(在效率方面) 能否解释两个命令之间的不同评估/搜索策略 有没有一种方法可以在“引理”的证明中使用“值”的速度 当然,我这样问是因为我还没有在文档中找到答案(到目前为止)。在手册中记录和解释这种效率差异的是什么 这里有一个最小的源代码来重现这个问题 theory SlowLemma imports Main begin (* Alpha

我是伊莎贝尔/霍尔的新手,仍在学习prog prov练习。同时,我正在练习将这些证明技巧应用于组合词的问题。在“价值”和“引理”之间,我观察到一种非常不同的行为(在效率方面)

能否解释两个命令之间的不同评估/搜索策略

有没有一种方法可以在“引理”的证明中使用“值”的速度

当然,我这样问是因为我还没有在文档中找到答案(到目前为止)。在手册中记录和解释这种效率差异的是什么

这里有一个最小的源代码来重现这个问题

theory SlowLemma
imports Main
begin

(* Alphabet for Motzkin words. *)
datatype alphabet = up | lv | dn

(* Keep the [...] notation for lists. *)
no_notation Cons (infixr "#" 65) and append (infixr "@" 65)

primrec count :: "'a ⇒ 'a list ⇒ nat" where
"count _ Nil = 0" |
"count s (Cons h q) = (if h = s then Suc (count s q) else count s q)"

(* prefix n l simply returns undefined if n > length l. *)
fun prefix :: "'a list ⇒ nat ⇒ 'a list" where
"prefix _ 0 = []" |
"prefix (Cons h q) (Suc n) = Cons h (prefix q n)"

definition M_ex_7 :: "alphabet list" where
"M_ex_7 ≡ [lv, lv, up, up, lv, dn, dn]"
definition M_ex_19 :: "alphabet list" where
"M_ex_19 ≡ [lv, lv, up, up, lv, up, lv, dn, lv, dn, lv, up, dn, dn, lv, up, dn, lv, lv]"

fun height :: "alphabet list ⇒ int" where
"height w = (int (count up w + count up w)) - (int (count dn w + count dn w))"

primrec is_pre_M :: "alphabet list ⇒ nat ⇒ bool" where
"is_pre_M _ (0 :: nat) = True"
| "is_pre_M w (Suc n) = (let w' = prefix w (Suc n) in is_pre_M w' n ∧ height w' ≥ 0)"

fun is_M :: "alphabet list ⇒ bool" where
"is_M w = (is_pre_M w (length w) ∧ height w = 0)"

(* These two calls to value are fast. *)
value "is_M M_ex_7"
value "is_M M_ex_19"

(* This first lemma goes fast. *)
lemma is_M_M_ex_7: "is_M M_ex_7"
by (simp add: M_ex_7_def)

(* This second lemma takes five minutes. *)
lemma is_M_M_ex_19: "is_M M_ex_19"
by (simp add: M_ex_19_def)

end

simp
是一种经过证明内核的证明方法,即每一步都必须经过证明。对于较长的重写链,这可能相当昂贵

另一方面,
value
在可能的情况下使用。所有使用的常量都转换为ML代码,然后执行。您必须相信结果,也就是说,它没有通过内核,可能是错误的

作为证明方法,
value
的等价物是
eval
。因此,加快证明速度的一个简单方法是:

lemma is_M_M_ex_19: "is_M M_ex_19"
by eval
Isabelle社区对是否应使用此选项的意见不同。有人说它类似于<代码>公理化< <代码>(因为你必须信任它),其他人认为如果通过内核是非常慢的,这是一个合理的方式。虽然大家都同意,但您必须非常小心代码生成器的自定义设置(您还没有完成,所以应该可以)

中间立场是:
code\u simp
方法将设置
simp
仅使用
eval
将使用的方程。这意味着:
simp
的规则集要小得多,但仍要通过内核。在您的情况下,它实际上与eval的
速度相同,因此我强烈建议您这样做:

lemma is_M_M_ex_19: "is_M M_ex_19"
by code_simp
在您的例子中,
code\u simp
simp
快得多的原因是因为simproc在嵌套的
let
表达式数量上具有指数运行时间。因此,另一种解决方案是使用
simp add:Let_def
来展开
Let
表达式



编辑以反映Andreas Lochbihler的评论。
code\u-simp

simp
之间的差异是由于simproc
let\u-simp
,其运行时间在
let
的嵌套深度上是指数级的。如果您将
Let_def
添加到简化器的simpset中,
simp
也可以在短时间内证明
。我忽略了展开
Let
构造的需要。另一个解决方案(这更能解释我的现象)是将我最初定义的第二种情况
is_pre_M
替换为
“is_pre_M w(Suc n)=(is_pre_M(前缀w(Suc n))n∧ 高度(前缀w(Suc n))≥ “0)”
@AndreasLochbihler我已根据您的评论更新了我的答案。