我为什么要用“我的”呢;数字“自然”;或;数字符号“simps”;当在Isabelle中证明一个简单的可计算的自然等式时

我为什么要用“我的”呢;数字“自然”;或;数字符号“simps”;当在Isabelle中证明一个简单的可计算的自然等式时,isabelle,Isabelle,采用阶乘函数的标准定义: primrec factorial :: "nat ⇒ nat" where "factorial 0 = 1" | "factorial (Suc n) = (Suc n) * (factorial n)" 如果我们要求值“factorial 3”,伊莎贝尔可以预料地给我们6。然而,如果我们试图将其作为引理,它将失败: lemma "factorial (3::nat) = (6:

采用阶乘函数的标准定义:

primrec factorial :: "nat ⇒ nat"
  where
    "factorial 0 = 1"
  | "factorial (Suc n) = (Suc n) * (factorial n)"
如果我们要求
值“factorial 3”
,伊莎贝尔可以预料地给我们
6
。然而,如果我们试图将其作为引理,它将失败:

lemma "factorial (3::nat) = (6::nat)"
  by simp
(* Failed to apply initial proof method *)
simp
auto
,甚至
arith
都找不到解决方案。但是,如果我们添加
numeric\u nat
numeric.simps
simp
可以解决这个问题:

lemma "factorial (3::nat) = (6::nat)"
  by (simp add: numeral_nat)

lemma "factorial (3::nat) = (6::nat)"
  by (simp add: numeral.simps)
有趣的是,在这两个证明中,Isabelle都给出了警告“
忽略重复重写规则”
,这意味着它应该已经知道这些。此外,Isabelle证明
“3*2*1=6”
,这让我更加困惑于这些引理是如何被使用的


因此,如果这是一个如此简单且易于计算的等式-如此之多以至于Isabelle可以用
value
命令计算它-而且这些规则显然已经存在,为什么Isabelle不能在没有它们的情况下解出引理呢?

numeric\u nat
包含7个引理:

thm numeral_nat
(*
  Numeral1 = Suc 0
  numeral (num.Bit0 ?n) = Suc (numeral (Num.BitM ?n))
  numeral (num.Bit1 ?n) = Suc (numeral (num.Bit0 ?n))
  Num.BitM num.One = num.One
  Num.BitM (num.Bit0 ?n) = num.Bit1 (Num.BitM ?n)
  Num.BitM (num.Bit1 ?n) = num.Bit1 (num.Bit0 ?n)
  1 = Suc 0
*)
simp
投诉了其中的4个:

Ignoring duplicate rewrite rule:
Num.BitM num.One ≡ num.One 
Ignoring duplicate rewrite rule:
Num.BitM (num.Bit0 ?n1) ≡ num.Bit1 (Num.BitM ?n1) 
Ignoring duplicate rewrite rule:
Num.BitM (num.Bit1 ?n1) ≡ num.Bit1 (num.Bit0 ?n1) 
Ignoring duplicate rewrite rule:
1 ≡ Suc 0
因此,有了
7-4=3
新的定理。跟踪(参见
simp\u trace
)表明
numeric\u nat(2,3)
是有用的引理

惯用的方法是(
numeric\u eq\u Suc
通常是一个糟糕的simp规则):

您可能想知道为什么从
3
扩展到
Suc(Suc(Suc 0))
实际上是必要的,因为定义是
factorial(Suc n)=……
。伊莎贝尔的答案是:只适用于
1
。这对于大多数递归函数来说已经足够了,并且避免了目标的膨胀。试一试

lemma "factorial (6::nat) = A" 
  apply (simp add: numeral_nat(2,3))
看到一个被放大的进球

现在,
value
的工作原理非常不同。它有三种模式:

  • value
    value[code]
    eval
    策略)生成标准ML代码并执行。您信任代码方程式和编译器
  • value[nbe]
    normalization
    策略)是通过评估实现的规范化(也使用代码生成)。“需要信任的代码堆栈相当多”()
  • value[simp]
    code\u simp
    策略)使用简化器。完全可信

  • 即使在最后一种情况下,也会使用特定的参数和定理调用简化器,而不是像您那样使用默认的参数和定理。这就是区别。

    回答得很好!但是仍然有一个问题:为什么首先需要这些引理呢?。如果
    factorial3
    最终减少到
    3*2*1
    (对吗?),为什么
    simp
    可以证明
    3*2*1=6
    没有它们,而不是
    factorial3=6
    ?定义是
    factorial(Suc n)=……
    。所以问题就变成了:你想什么时候把一个数字转换成Suc(Suc…(0)…)?伊莎贝尔的答案是:只为1。这对于大多数递归函数来说已经足够了,并且避免了目标的膨胀。尝试
    lemma“factorial(6::nat)=A”apply(simp add:numeric_nat(2,3))
    来查看一个放大的目标。这很有意义。。。而且值得回答!把它加进去,我会欣然接受(我会自己添加一个建议的编辑,但不幸的是编辑队列已满)
    lemma "factorial (6::nat) = A" 
      apply (simp add: numeral_nat(2,3))