如何在 Coq 中实现联合查找不相交集数据结构?

如何解决如何在 Coq 中实现联合查找不相交集数据结构?

我对 Coq 很陌生,但是对于我的项目,我必须在 Coq 中使用 union-find 数据结构。 Coq 中是否有联合查找(不相交集)数据结构的任何实现?

如果没有,有人可以提供实现或一些想法吗?它不必非常有效。 (无需进行路径压缩或所有花哨的优化)我只需要一个可以保存任意数据类型(如果太难,则为 nat)并执行的数据结构:union查找

提前致谢

解决方法

如果您只需要一个数学模型,而不考虑实际性能,我会选择最直接的一个:功能映射(有限偏函数),其中每个元素都可以选择链接到另一个元素合并。

  • 如果一个元素没有链接,那么它的规范代表就是它自己。
  • 如果一个元素链接到另一个元素,则其规范代表就是该其他元素的规范代表。

注意:在本答案的其余部分中,作为 union-find 的标准,我将假设元素只是自然数。如果您想要其他类型的元素,只需使用另一个映射将所有元素绑定到唯一编号即可。

然后您将定义一个函数 find : UnionFind → nat → nat,该函数返回给定元素的规范代表,只要您可以点击链接即可。请注意,该函数将使用递归,其终止参数并非微不足道。为了实现这一点,我认为最简单的方法是保持一个数字只链接到一个较小的数字的不变性(即如果 i 链接到 j,那么 i > j)。然后递归终止,因为当跟随链接时,当前元素是一个递减的自然数。

定义函数 union : UnionFind → nat → nat → UnionFind 更容易:union m i j 只返回更新的地图,其中 max i' j' 链接到 min i' j',其中 i' = find m ij' = find m j .

[关于性能的旁注:保持不变意味着你不能根据它们的等级充分选择一对分区中的哪一个合并到另一个;但是,如果您愿意,您仍然可以实现路径压缩!]

至于地图确切使用哪种数据结构:有几种可用。 standard library(查看标题FSets)有几个满足接口FMapInterface 的实现(FMapList、FMapPositive 等)。 stdpp 库有 gmap

同样,如果性能不是问题,只需选择最简单的编码,或者更重要的是,选择使您的证明最简单的编码。我只想到一个自然数列表。 列表的位置是逆序的元素。 列表的值是偏移量,即为了到达链接的目标而向前跳过的位置数。

  • 对于链接到 i (j) 的元素 i > j,偏移量为 i − j
  • 对于规范代表,偏移量为零。

以我最好的伪 ASCII 艺术技能,这里有一张地图,其中链接是 { 6↦2,4↦2,3↦0,2↦1 } 并且规范代表是 { 5,1,0 } :

  6   5   4   3   2   1   0   element
  ↓   ↓   ↓   ↓   ↓   ↓   ↓
               /‾‾‾‾‾‾‾‾‾↘
[ 4 ; 0 ; 2 ; 3 ; 1 ; 0 ; 0 ] map
   \       \____↗↗ \_↗
    \___________/

动机是上面讨论的不变量然后结构化被强制执行。因此,希望 find 实际上可以通过结构归纳来定义(在列表的结构上),并且可以免费终止。


相关论文是:Sylvain Conchon and Jean-Christophe Filliâtre. A Persistent Union-Find Data Structure. In ACM SIGPLAN Workshop on ML.

它描述了在 ML 中实现一个高效的 union-find 数据结构,从用户的角度来看是持久的,但在内部使用了变异。对你来说更有趣的是,他们在 Coq 中证明了它是正确的,这意味着他们有一个 Coq 模型用于联合查找。然而,这个模型反映了他们试图证明正确的命令式程序的内存存储。我不确定它是否适用于您的问题。

,

Maëlan 有一个很好的答案,但对于更简单和效率更低的不相交集合数据结构,您可以使用函数来 nat 来表示它们。这避免了任何终止粘性。本质上,任何全函数的原像形成域上的不相交集。另一种看待这个的方式是将任何不相交集 G 表示为柯里化应用程序 find_root G : nat -> nat,因为 find_root 是不相交集提供的基本接口。 这也类似于在 Coq 中使用函数来表示 Maps,就像在 Software Foundations 中一样。 https://softwarefoundations.cis.upenn.edu/lf-current/Maps.html

Require Import Arith.
Search eq_nat_decide.
(* disjoint set *)
Definition ds := nat -> nat.
Definition init_ds : ds := fun x => x.
Definition find_root (g : ds) x := g x.
Definition in_same_set (g : ds) x y := 
    eq_nat_decide (g x) (g y).
Definition union (g : ds) x y : ds := 
    fun z =>
    if in_same_set g x z
    then find_root g y
    else find_root g z.

你也可以像这样在不相交集合中的类型上使其泛型

Definition ds (a : Type) := a -> nat.
Definition find_root {a} (g : ds a) x := g x.
Definition in_same_set {a} (g : ds a) x y := 
    eq_nat_decide (g x) (g y).
Definition union {a} (g : ds a) x y : ds a := 
    fun z =>
    if in_same_set g x z
    then find_root g y
    else find_root g z.

要为特定的 a 初始化不相交集,您基本上需要一个类型为 a 的 Enum 实例。

Definition init_bool_ds : ds bool := fun x => if x then 0 else 1.

根据您的证明风格和需要,您可能想用 eq_nat_decide 换取 eqb 或其他一些大致相当的东西。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-