Coq 无法在 Z 上计算有根据的函数,但它可以在 nat 上运行

2024-01-04

我正在(为我自己)写一篇关于如何在 Coq 中进行有根据的递归的解释。 (参见 Coq'Art 书,第 15.2 章)。首先我做了一个基于的示例函数nat效果很好,但后来我又做了一次Z,当我使用Compute来评估它,它并没有一直降低到Z价值。为什么?

这是我的示例(我将文本放在注释中,以便可以将整个内容复制粘贴到编辑器中):


(* 有根据的递归测试 *)

(* TL;DR: 为了进行有根据的递归, 首先创建“功能”,然后 使用创建递归函数 Acc_iter,可访问关系的迭代器 *)

(* 作为示例,计算从 1 到 n 的级数之和, 像这样的草图:

修复 f n := (如果 n = 0 则 0 否则 n + f (n-1))

现在,让我们not对 n 使用结构递归。

相反,我们对 n 使用有根据的递归, 使用小于 ('lt') 的关系是 有根据的。函数 f 终止是因为 递归调用是在结构上进行的 较小的项(在递减的 Acc 链中)。 *)

(* 首先我们为 nat 做这件事 *)

Require Import Arith.Arith.
Require Import Program.Utils. (* for 'dec' *)
Require Import Wellfounded.

(* 从证明关系是有充分根据的, 我们可以得到一个特定元素的证明 在其域内是可访问的。

这里的Check命令不是必须的,只是为了 文档,亲爱的读者。 *)

Check well_founded : forall A : Type, (A -> A -> Prop) -> Prop.
Check lt_wf : well_founded lt.
Check (lt_wf 4711 : Acc lt 4711).

(* 首先为 f 定义一个“函数”F。它是一个函数 将“递归调用”的函数 F_rec 作为参数。 因为我们需要知道第二个分支中的 n 0 我们使用 'dec' 将布尔 if 条件转换为 总和。我们将有关它的信息发送到分支机构。

我们把大部分内容写得精炼,留下一些漏洞 稍后再补充战术。 *)

Definition F (n:nat) (F_rec : (forall y : nat, y < n -> nat)): nat.
  refine ( if dec (n =? 0) then 0 else n + (F_rec (n-1) _ ) ).

  (* now we need to show that n-1 < n, which is true for nat if n<>0 *)
  destruct n; now auto with *.
Defined.

(* 迭代器可以使用函数来调用 f 根据需要多次。

旁注:我们可以创建一个迭代器来获取最大值 递归深度 d 作为 nat 参数,并在 d 上递归,但是 那么必须提供 d,以及一个“默认值” 如果 d 达到零并且必须终止则返回 早期的。

有根据的递归的巧妙之处在于 迭代器可以在有根据的证明上递归 并且不需要任何其他结构或默认值 以保证它会终止。 *)

(* Acc_iter 的类型非常多 *)

Check Acc_iter :
      forall (A : Type) (R : A -> A -> Prop) (P : A -> Type),
       (forall x : A, (forall y : A, R y x -> P y) -> P x) -> forall x : A, Acc R x -> P x.

(* P 存在是因为返回类型可能取决于参数,
但在我们的例子中,f:nat->nat,并且 R = lt,所以我们有 *)

Check Acc_iter (R:=lt) (fun _:nat=>nat) :
  (forall n : nat, (forall y : nat, y < n -> nat) -> nat) ->
   forall n : nat, Acc lt n -> nat.

(* 这里第一个参数是迭代器采用的函数, 第二个参数 n 是 f 的输入,第三个参数是 n 可访问的证明。 迭代器返回应用于 n 的 f 值。

Acc_iter 的一些参数是隐式的,有些是可以推断的。 因此我们可以简单地定义 f 如下: *)

Definition f n := Acc_iter _ F (lt_wf n).

(*它就像一个魅力*)

Compute (f 50). (* This prints 1275 *)
Check eq_refl : f 50 = 1275.

(* 现在让我们为 Z 做这件事。这里我们不能使用 lt, 或 lt_wf 因为它们用于 nat。对于Z我们 可以使用 Zle 和 (Zwf c) 来获取下限。 它需要一个下界,在该下界下我们知道函数 将始终终止以保证终止。 这里我们使用 (Zwf 0) 来表示我们的函数将 总是在 0 或以下终止。我们还必须 将 if 语句更改为“if n

Require Import ZArith.
Require Import Zwf.

Open Scope Z.

(* 现在我们根据泛函 G 定义函数 g *)

Definition G (n:Z) (G_rec :  (forall y : Z, Zwf 0 y n -> Z)) : Z.
  refine (if dec (n<?0) then 0 else n + (G_rec (n-1) _ )).

  (* now we need to show that n-1 < n *)
  now split; [ apply Z.ltb_ge | apply Z.lt_sub_pos].
Defined.

Definition g n := Acc_iter _ G (Zwf_well_founded 0 n).

(* 但现在我们无法计算!*)

Compute (g 1).

(* 我们刚刚得到一个以

     = (fix
        Ffix (x : Z)
             (x0 : Acc
                     (fun x0 x1 : Z =>
                      (match x1 with
                       | 0 => Eq
                       | Z.pos _ => Lt
                       | Z.neg _ => Gt
                       end = Gt -> False) /\
                      match x0 with
                      | 0 => match x1 with
                             | 0 => Eq
                             | Z.pos _ => Lt
                             | Z.neg _ => Gt
                             end
                      | Z.pos x2 =>

    ...

 end) 1 (Zwf_well_founded 0 1)
     : (fun _ : Z => Z) 1
   ) 

评论:我注意到了Zwf_well_founded定义为Opaque在图书馆,所以我试着做到Transparent通过复制证明并结束引理Defined.代替Qed.但这没有帮助...

补充观察:

如果我定义f' for nat with Fixpoint相反,并递归 可访问性证明,并结束于Defined.然后它会计算。但如果我以Qed.它并没有减少。这有关系吗?我认为定义存在透明度问题G or g某处...或者我完全错了?

Fixpoint f' (n:nat) (H: Acc lt n) : nat.
  refine (if dec (n<=?0) then 0 else n + (f' (n-1) (Acc_inv H _))).
  apply Nat.leb_gt in e.
  apply Nat.sub_lt; auto with *.
Defined.  (* Compute (f' 10 (lt_wf 10)). doesn't evaluate to a nat if ended with Qed. *)

无论如何,我的问题仍然存在Z.

Fixpoint g' (n:Z) (H: Acc (Zwf 0) n) : Z.
  refine (if dec (n<=?0) then 0 else n + (g' (n-1) (Acc_inv H _))).
  split; now apply Z.leb_gt in e; auto with *.
Defined.

Compute (g' 10 (Zwf_well_founded 0 10)).

Making Zwf_well_founded https://coq.inria.fr/library/Coq.ZArith.Zwf.html#Zwf_well_founded透明没有帮助,因为它在标准库中的定义方式:

Lemma Zwf_well_founded : well_founded (Zwf c).
...
    case (Z.le_gt_cases c y); intro; auto with zarith.
...
Qed.

如果将上面证明中的行替换为

     case (Z_le_gt_dec c y); intro; auto with zarith.

并替换Qed. with Defined.(你已经这样做了)一切都应该有效。这是因为原始证明依赖于逻辑项,并且这阻止了评估者进行模式匹配,因为逻辑实体Z.le_gt_cases是不透明的,而计算实体Z_le_gt_dec是透明的。看在愤怒中使用 Coq 的评估机制 http://gallium.inria.fr/blog/coq-eval/泽维尔·勒罗伊 (Xavier Leroy) 的博客文章。您可能还会发现有用Qed 被认为是有害的 https://gmalecha.github.io/reflections/2017/qed-considered-harmful格雷戈里·马莱查 (Gregory Malecha) 发表的文章。

而不是修改证明Zwf_well_founded你可以重复使用Zlt_0_rec https://coq.inria.fr/library/Coq.ZArith.Wf_Z.html#Zlt_0_rec像这样:

Require Import Coq.ZArith.ZArith.

Open Scope Z.

Definition H (x:Z) (H_rec : (forall y : Z, 0 <= y < x -> Z)) (nonneg : 0 <= x) : Z.
  refine (if Z_zerop x then 0 else x + (H_rec (Z.pred x) _ )).
  auto with zarith.
Defined.

Definition h (z : Z) : Z :=
  match Z_lt_le_dec z 0 with left _ => 0 | right pf => (Zlt_0_rec _ H z pf) end.

Check eq_refl : h 100 = 5050.

这有点不太方便,因为现在我们必须处理负数h.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Coq 无法在 Z 上计算有根据的函数,但它可以在 nat 上运行 的相关文章

  • F# 中序列的递归函数

    这是一个相当微不足道的问题 但快速的谷歌搜索并没有给我答案 为序列编写递归函数的标准方法是什么 对于列表 您可以使用空列表和头 尾模式进行模式匹配 序列的等效项是什么 没有标准的方法可以做到这一点 因为您很少为序列编写递归函数 您应该查看各
  • Javascript 'this' 覆盖 Z 组合器和所有其他递归函数

    背景 我有一个由a实现的递归函数Z 组合器如图所示here https stackoverflow com questions 17645356 anonymous recursion any way to replace javascri
  • 为什么这个记忆器适用于递归函数?

    我不明白为什么下面的代码是这样的fib以线性而非指数时间运行 def memoize obj Memoization decorator from PythonDecoratorLibrary Ignores kwargs cache ob
  • 产量回报延迟迭代问题

    我知道yield return 利用了延迟加载 但我想知道我是否可能滥用迭代器或者很可能需要重构 我的递归迭代器方法返回给定的所有祖先PageNode包括pageNode itself public class PageNodeIterat
  • 计算 python 字典/数组数据结构的非空尾叶 - 递归算法?

    我正在寻找一个函数来查找一种复杂字典 数组结构的所有非空端点 我认为因为我不知道嵌套数组的数量或它们的位置 所以它必须是递归的 而我只是还没有完全理解这种思维方式 所以对于嵌套字典 x top middle nested value nes
  • 如何使用递归获取父级的所有子级,然后获取其子级

    问候 我的 JSP Web 应用程序中有父事务的比喻 我将事务 ID 存储在数据库中 要求是显示父级的所有子级 然后显示父级子级的后续子级 实际上 这个父母及其孩子的列表永远不会超过 4 或 5 层 但我需要考虑到它可以比这更多层 我尝试过
  • 带子图聚合的递归查询(任意深度)

    我问了一个问题earlier https stackoverflow com questions 28036055 recursive query with sub graph aggreagation关于沿着图表聚合数量 提供的两个答案效
  • 文件/文件夹结构的递归搜索

    我正在尝试为返回文件和文件夹列表的 Web 服务构建递归搜索功能 我创建了这两个方法 因此它们充当递归搜索 它首先获取顶级内容 然后将任何文件添加到 fileList 并将任何子文件夹添加到 subFoldersList 我们传入访问级别
  • 在 Coq 模块系统中导入 与包含

    确切的语义是什么Include M1在另一个模块中 比如 M 这与做有什么不同Import M1在模块 M 内 更准确地说 以下命令的语义是什么 Module Type M M1 lt M2 lt M3 总结这两个白话命令的语义 命令Inc
  • 为什么Python有最大递归深度?

    Python有最大递归深度 但没有最大迭代深度 为什么递归受到限制 把递归当成迭代来对待 而不限制递归调用的次数不是更自然吗 我只想说这个问题的根源来自于尝试实现流 参见这个问题 https stackoverflow com questi
  • 在 Clojure 中退出 Recur 循环

    我想跳出下面的循环 并在第 10 行计算结果为 true 时返回最佳最小移动 我查看了 print 语句的输出 当第 10 行的计算结果为 true 时 它 找到了我正在查找的数据 但仍然重复出现 在 Clojure 中 有没有办法在语句计
  • 如何返回n对括号的所有有效组合?

    def paren n lst for x in range n current string join lst solutions list for i in range len current string 1 close curren
  • 在依赖类型的函数式编程语言中,扁平化列表是否更容易?

    在 haskell 中寻找一个可以展平任意深度嵌套列表的函数时 即应用的函数concat递归并在最后一次迭代时停止 使用非嵌套列表 我注意到这需要有一个更灵活的类型系统 因为随着列表深度的变化 输入类型也会变化 确实 有几个 stackov
  • php 删除特定文件夹及其所有内容

    我正在使用 php 删除包含已删除帖子图像的文件夹 我正在使用下面的代码 这是我在网上找到的并且做得很好 我想知道当一个文件夹中有其他文件夹时 如何只删除其中的特定文件夹 当我使用下面的代码时 如何才能做到这一点 使用 dev images
  • 在堆栈已满并给出分段错误之前,C/C++ 中的最大递归函数调用次数?

    我正在做一个问题 我使用递归函数来创建线段树 对于较大的值 它开始出现分段错误 所以我之前认为可能是因为数组索引值越界 但后来我认为这可能是因为程序堆栈太大 我编写这段代码是为了计算系统出现段错误之前允许的最大递归调用次数 include
  • Javascript - deepEqual 比较

    问题 来自 Eloquent Javascript 第二版 第 4 章 练习 4 编写一个函数 deepEqual 它接受两个值 并且仅当它们相等时才返回 true 是相同的值或具有相同属性的对象 其值也是 与对 deepEqual 的递归
  • 我在函数的最后一次递归调用中得到“方案应用程序而不是过程”

    所以这是代码 define time prime test n newline display n start prime test n runtime define start prime test n start time if pri
  • 使用fold_left/right反转OCaml中的列表

    更新 解决方案 感谢 jacobm 的帮助 我想出了一个解决方案 Folding Recursion let reverse list 3 theList List fold left fun element recursive call
  • 来自 JSON 的 Angular 8 动态表单

    我正在尝试从 JSON 模式递归生成动态表单 但我正在努力解决找不到表单控件的问题 这是代码示例 我收到这个错误 错误错误 找不到名称为 createdAt 的控件 我尝试了不同的方法 但仍然存在问题 我知道我错过了一些东西 所以请帮忙 任
  • 卷积函数可以写成尾递归形式吗?

    我有一个函数 我想以尾递归形式编写 该函数计算求和的方法数k通过滚动s双面模具n次 我已经在上面看到了这个函数的数学解这个答案 https math stackexchange com questions 397689 why convol

随机推荐

  • 在 ReactJS 中重定向到上一页

    自从我进行检查后 我在重定向到上一页时遇到问题isLoggedIn 现在的问题是检查后isLoggedIn它重定向到默认路由 如何维护我所在的页面 我现在所做的是使用referer但它是未定义的 请帮我找到另一种方法 请检查我的代码如下 L
  • 从模型状态验证中删除对象

    我有两个模型 public class UserInfo public long ID get set Required StringLength 50 public string FirstName get set public bool
  • 如何获取matplotlib中的图例位置

    我正在尝试获取 matplotlib 中的图例位置 似乎 Legend get window extent 应该提供此功能 但无论图例位于何处 它都会返回相同的值 这是一个例子 from matplotlib import pyplot a
  • 异常后重试操作:请批评我的代码

    我的 Perl 应用程序使用的资源有时会暂时不可用 从而导致异常die 最值得注意的是 它访问由多个线程共享的 SQLite 数据库 并通过以下方式与其他应用程序共享 DBIx Class 每当发生此类异常时 应重试该操作 直到达到超时为止
  • 使 ViewPager 的高度等于 PagerAdapter 中最高项目的高度

    我有一个ViewPager并用它在视图之间滑动而不是 Fragments 当我给View Pagerwrap content 高度 它不显示任何内容 所以我必须给它一个固定的高度 但我遇到了另一个问题 当项目的高度大于固定高度时 视图无法正
  • 具有默认实现的接口和抽象类有什么区别? [复制]

    这个问题在这里已经有答案了 C 8 0 引入了一项新的语言功能 接口成员的默认实现 public interface IRobot void Talk string message Debug WriteLine message 新的默认接
  • 如何从 std::string 获取可写的 C 缓冲区?

    我正在尝试使用 MFC 移植我的代码CString to std string适用于微软Windows平台 我对某件事很好奇 在下面的例子中说 CString MakeLowerString LPCTSTR pStr CString str
  • 无法将下一个js部署到azure

    我正在尝试将我的 NEXTJS 应用程序部署到 azure 我使用安装了 Node 的 Linux 操作系统创建了一个 Web 应用程序 我的package json看起来像这样 name frontend version 1 0 0 de
  • 使用同一个ajax调用打开多个动态链接

    我正在显示多个使用相同的动态链接 ajax加载第一个链接上的内容很好 但不适用于其余链接 如何让它加载同一div中其他链接的内容 Html string a href link name name a div div Jquery href
  • 使用 GoogleMap 或 MapBox Direction API 在我的应用程序中实现我自己的导航

    我想在我的 Android 应用程序中为驾驶员实现导航地图 我不想使用 URL 方案打开 google 地图应用程序来导航 我更喜欢在我的应用程序中实现此导航功能 就像 Google 地图一样 我的要求很简单 将用户从一个地方导航到另一个地
  • shouldComponentUpdate 并非从未被调用

    请看一下我的代码 我尝试限制给定无状态组件的重新渲染 但这样做发现 shouldComponentUpdate 永远不会被调用 我已经从 styledComponents 中删除了包装器 之前有人报道过这种情况 但仍然绝对没有被调用 除此之
  • 在 JavaScript 中迭代带有“洞”的数组

    我有一个数组 其中一些项目将被删除 但有些循环仍在运行 所以我想简单地跳过删除对象的地方 我知道 for i in array 的语法应该执行此操作 因为它会迭代索引 但是我应该如何删除我的项目呢 因为当我执行 array 4 null 时
  • 查看pdf时隐藏或修改Webview2的工具栏

    我正在使用新的 Webview2 控件在 WPF 应用程序中呈现 Pdf 文件 这运行良好 但我想自定义工具栏以隐藏例如某些条件的保存按钮 我没有找到直接从 Webview2 CoreWebView2 对象执行此操作的方法或属性 但是 如果
  • 尝试调用自定义过滤器会导致“错误 TS2349:无法调用类型缺少调用签名的表达式”

    我试图从 Angular 控制器调用自定义过滤器 但收到错误 无法调用类型缺少调用签名的表达式 我在我从事的上一个项目中是这样实现的 所以我不知道哪里出了问题 此时过滤器不包含任何逻辑 因为我需要先编译它 这是过滤器
  • 用带孔的多边形制作 sf 对象并设置 crs

    With contourLines 我已经提取了数据的 95 轮廓 我想用正确的 crs 制作一个 sf 对象 虽然我无法分享我的实际数据集 但我改编了一个示例SO post https stackoverflow com question
  • Codeigniter ajax使用ajax代码将数据发送到控制器

  • 如何在 WinRT 8.1 上 P/调用 kernel32.dll

    我正在尝试使用本机 API 方法 GetNativeSystemInfo 在 Windows 8 1 上标记为支持手机和桌面应用商店应用程序 在文档中 它被列为存在于 kernel32 dll 中 伟大的 所以我对 P Invoke 的第一
  • Android:如何使用 AlarmManager

    我需要在 20 分钟后触发一段代码AlarmManager正在设置 有人可以向我展示有关如何使用的示例代码吗AlarmManager在 Android 中 我已经研究了一些代码几天了 但它不起作用 一些示例代码 并不是那么容易AlarmMa
  • 停止运行 PHP 服务器,命令行

    所以我已经做到了php S localhost 8000 但我不再需要它了 我需要找回我的 8000 localhost 如何停止php服务器 killall 9 php 我就是这么做的
  • Coq 无法在 Z 上计算有根据的函数,但它可以在 nat 上运行

    我正在 为我自己 写一篇关于如何在 Coq 中进行有根据的递归的解释 参见 Coq Art 书 第 15 2 章 首先我做了一个基于的示例函数nat效果很好 但后来我又做了一次Z 当我使用Compute来评估它 它并没有一直降低到Z价值 为